There is one link button, Mod-k, and one picker behind it — and the same picker appears everywhere in the CMS that takes a link: the page editor, the menu builder and the CTA editor all open the same three tabs. Learn it once.
The picker is also doing something on your behalf that is easy to miss. Paste a URL from your own site into the External tab and, the moment you click away, it becomes an internal page reference instead — a link that follows the page when you rename it rather than breaking. That conversion, and the cases where it does not happen, are most of this page.
The link picker is free on every plan. One action inside it — inserting a document’s extracted text — is not; it is flagged where it appears.
What the picker does before you type
Open the picker with a bare cursor sitting inside a word and it snaps the selection out to the whole word before showing you anything. Highlight most of a phrase and it expands outward to the word boundaries. This is deliberate: people routinely miss a character when highlighting and do not notice until the published page has a stray letter outside the link. Bold, italic and the other marks behave the same way.
The Link Text field is then pre-filled from that snapped range. Leave it alone and the picker only adds the link mark to the existing words — it does not rewrite them, which matters in Suggesting mode, where a pure mark change is recorded as Format: link rather than as a delete-and-retype.
If the cursor is already inside a link, the picker opens on that link, with the tab that matches its href already selected — Internal Page for a pageid: href, Documents for a document link, External URL for anything else.
| Tab | What you pick | Stored href | Default target | Gate |
|---|---|---|---|---|
| Internal Page | One of your own published pages, from a searchable list | pageid:<pageId> | Same tab | None |
| External URL | Any URL, typed or pasted | The URL as typed | _blank — a new tab | None |
| Documents | An uploaded document | f/<assetId>/<filename>, marked as a download | Same tab | Inserting the document’s extracted text is Starter and up |
Internal Page
The Internal Page tab is a combobox over your pages. Type and it filters on title, falling back to the path for pages without one; each row shows the title with its full path underneath.
What it stores is not a path. It stores pageid:<pageId> — a reference to the page itself. At build time every one of those references is resolved against the page’s current URL, so:
- Change the page’s slug, move it into a different folder, or restructure the whole section, and the link keeps working. Nothing to find and fix.
- The link can never rot into a path that no longer exists, because there is no path in it to go stale.
That is why URL Paths and Slugs can describe URLs as something you are free to change: internal links do not depend on them.
The list is built from your pages’ live URLs, so a page that has never been published has no entry and cannot be selected here. Publish it first, then link to it.
External URL
The External URL tab is a single field. Anything you put there is stored verbatim and opens in a new tab.
Why your own URL becomes a page link
When you leave that field — click elsewhere, tab away, press Apply — the picker sends what you typed to Leed and asks whether it resolves to one of your pages. If it does, the field is rewritten to pageid:…, the matching page is selected, and you are switched to the Internal Page tab. You will see the tab flip; that is the conversion happening.
The rule is narrow and worth knowing exactly:
flowchart TD
TYPE["What you typed, trimmed"] --> EMPTY{"Empty?"}
EMPTY -->|yes| KEEP["Left exactly as typed —<br/>stays an external link"]
EMPTY -->|no| PROTO{"Starts with // ?"}
PROTO -->|"yes — protocol-relative,<br/>another host"| KEEP
PROTO -->|no| REL{"Starts with / ?"}
REL -->|yes| LOOK["Look the path up"]
REL -->|no| URL{"Parses as an absolute URL?"}
URL -->|no| KEEP
URL -->|yes| SCHEME{"http or https?"}
SCHEME -->|"no — mailto:, tel:, javascript:"| KEEP
SCHEME -->|yes| HOST{"Host equals your<br/>public domain?"}
HOST -->|no| KEEP
HOST -->|yes| STRIP["Drop the origin,<br/>keep the path"] --> LOOK
LOOK --> HIT{"A page or redirect<br/>matches that path?"}
HIT -->|no| SLASH{"Retry with a<br/>trailing slash"}
SLASH -->|"still no match"| KEEP
SLASH -->|match| WIN
HIT -->|yes| WIN["Rewritten to a pageid: reference<br/>and the tab flips to Internal Page"]
Two details the diagram earns: the lookup matches redirects as well as current URLs, so pasting an old address you kept as an alias still finds the right page; and the trailing-slash retry means /docs/pricing and /docs/pricing/ both resolve.
What does not convert
The host comparison is against your workspace’s public domain and nothing else. Everything below is treated as an external link and stored as typed:
| What you paste | Result | Why |
|---|---|---|
/docs/pricing/ or /docs/pricing | Converted to pageid: | A relative path is always looked up |
https://<your public domain>/blog/hello/ | Converted to pageid: | The host matches your public domain |
| A URL on your preview domain | Stays external | Only the public domain is compared |
A *.workers.dev URL for your site | Stays external | Same reason |
| A path for a page that has never been published | Left as a literal path | There is no live URL to match yet, so the link is fixed to that path |
//example.com/thing | Stays external | Protocol-relative — it starts with / but addresses another host |
mailto:, tel:, javascript: | Stays external | Only http: and https: are considered |
| Any other site’s URL | Stays external | As intended |
Documents
The Documents tab lists every document asset in your library by name and extension. Choosing one stores a download link to the file:
pageid:db540641-1361-4474-8590-c95936b5318e
f/3qa11wy1/product-spec.pdfThe first is what an internal page link looks like; the second is what a document link looks like. Documents are uploaded like any other asset — see Video, Audio and Document Assets.
Below the list, with a document selected, sits Insert extracted text. It drops the document’s extracted text into the page as editor blocks, below the paragraph you are in — useful when a PDF holds content you want as real, searchable page content rather than a download.
What a reader sees when the target is gone
A pageid: link is resolved when the site builds. If the page it points at is not in the build — unpublished, deleted, excluded — the link does not 404. The build strips the anchor and leaves the words behind in a plain <span>: the sentence still reads correctly, the text is no longer clickable, and nothing on the page announces that anything happened.
That is a deliberate trade — a silently plain phrase is better for a reader than a link into nothing — but it means a broken internal link is invisible unless you look. If you publish a page that links forward to one you have not published yet, publish both.
The reader-facing half of this, including how it behaves across a documentation set, is on Linking Between Docs Pages.
Linking to a heading
Same-page links work with ordinary markdown: [label](#anchor-slug). Anchors are generated automatically for headings at levels 1 through 5 from the heading’s text, lower-cased and dash-separated. In practice you will only ever use levels 2 through 5, because your page’s H1 comes from its title rather than from the body. ###### gets no anchor at all — if you need to link to something, do not put it at level six.
Two headings with the same text get de-duplicated with a numeric suffix (-1, -2), which is a good reason to keep headings on one page distinct.
Linking to a heading on another page
A fragment on an internal link works too: [label](pageid:<pageId>#heading-slug). The build resolves the page id to its current URL and keeps the fragment (and any query string) on the end, so the reader lands on the section rather than the top of the page.
The syntax for all of this, outside the picker, is on Links and Internal Links.
Keeping links honest
Internal links look after themselves. The two things that need attention are the links that point outward and the URLs that used to point in.
External links are checked automatically once a day and the failures are collected for you — Link Health shows what is broken and where it is linked from. And when you do change a page’s URL, add the old path as a redirect so anything outside your control — a bookmark, a search result, someone else’s blog post — still arrives; Aliases and Redirects covers that, and it is also what makes the picker’s path lookup match an old address.
The Link button’s shortcut and its neighbors on the toolbar are on Editor Toolbar Reference. The same picker builds your navigation, over on Building and Editing a Menu.