Short Links and Attribution

A short link is a compact, branded URL served from your own public domain. Someone clicks it, Leed records the click against their session and redirects them to the destination. Because the click is recorded, a short link is not only a shorter URL — it is a measurement point, and every session that starts with one can be followed all the way to a form submit and a contact record.

Every short link resolves at the same path on your live site:

https://<your public domain>/s/<code>

The code is either generated for you — eight characters drawn from upper- and lower-case letters and digits, so kJ2mQ8vD is a typical one — or a vanity code you choose. Because the URL is short, stable and on your own domain, it is what you put on a flyer, a conference badge, a QR code, a radio read, or any social post whose link you cannot edit after publishing.

The Shortcodes section of Engage with a code selected, showing its destination, hidden UTM tags and the Attribution facet

Open Engage in the rail, switch the section picker to Shortcodes, and click + — or go straight to /engage/shortcodes/new, which is a real URL rather than a modal, so you can link a colleague directly to the create form.

Creating needs the shortcode:publish privilege, which the Publish role and above carry, on top of the Growth plan. Reading the list and a code’s detail needs only shortcode:read, which every role from Read upward carries. The permission check runs before the plan check, so a Read-only user on a Growth workspace gets a 403 rather than an upgrade prompt — see Roles and Permissions for the ladder.

The new-shortcode form with the Site page / External URL toggle, the five UTM inputs, the extra-parameters editor and the vanity field

Choosing a destination

The form opens on a two-way toggle. Exactly one of the two is required — the API rejects a body carrying both or neither with “Either url or pageId must be specified.”

Pick a page from the dropdown. The link is stored as a page reference, not a URL, and is resolved to that page’s current published path on every redirect. Change the page’s slug next month and the printed short link keeps working — it simply starts pointing at the new address.

https://acme.example.com/s/kJ2mQ8vD
→ 302  https://acme.example.com/pricing/

If the page has no published path yet — a short link created against a draft — the redirect degrades to your site root rather than failing. The link will “work” and take the visitor somewhere unexpected, so publish the page before you print the code. How a page’s path is derived is covered in URL Paths and Slugs.

The on-site conversion nobody expects

If you choose External URL but paste a URL that happens to sit on your own public or preview domain, Leed does not store it as an external link. It takes the path out of the URL, looks it up in your published path index, and — when it finds a match — converts the link into a page reference and discards the URL you typed. A relative path such as /pricing/ is treated the same way.

So pasting https://acme.example.com/pricing/ gives you exactly the same short link as picking Pricing from the page dropdown, including the slug-survival behavior and, importantly, including the UTM handling described below. If the path is not in the index — a page you have not published, or a path served by something other than Leed — the URL stays external.

UTM tags

Five standard UTM fields are offered, with placeholder examples in the form, plus an editor for any additional query parameters you need.

FieldWhat it answersExample
utm_sourceWhere the click came fromnewsletter
utm_mediumWhat kind of channel it wasemail
utm_campaignWhich initiative it belongs tospring-launch
utm_contentWhich placement or creativehero-cta
utm_termKeyword or variantrunning-shoes

All five are optional. Every value you enter is normalized once, at creation: trimmed, lower-cased, and any run of internal whitespace collapsed to a single hyphen. Type Spring Launch and the code stores spring-launch forever. Normalization happens on the way in only — there is no later pass that could change a stored value under you.

The additional parameters editor holds free-form key/value pairs for anything outside the UTM five — an affiliate id, a print run number. Keys are restricted to letters, digits, dots, underscores and hyphens; anything else is refused with “Invalid parameter key … — use only letters, numbers, dots, underscores, or hyphens.” Both halves of each pair are percent-encoded when stored, so an &, = or # inside a value can never break out of its slot and corrupt the redirect URL.

Once a code exists, its tags are display-only. The detail view shows them in a Hidden UTM tags card — one row per tag, with the value as a chip and a short hint of what the tag means, and not set in italics for the ones you left blank.

Where the tags actually go

This catches people out when they check their work by clicking their own link: an on-site short link visibly lands on a bare /pricing/, which looks like the tags were lost. They were not. Open the code in Engage and the tags are on the record, and every metric on the page is computed from them.

Vanity codes

Leaving Vanity code blank gives you a generated eight-character code. Fill it in and that string becomes the code itself. Vanity codes accept lowercase letters, digits and hyphens only, from 1 to 64 characters; anything else is rejected in the form with “Vanity must use only lowercase letters, numbers, and hyphens.” A vanity that is already in use on your workspace is refused by the server with a 409.

Deletion exists as a narrow escape hatch: a code can be removed only while it has never recorded a click. The Delete action sits in the header for users with shortcode:publish and takes two clicks — the first turns it red and relabels it Confirm delete.

Once a code has clicks the button is disabled and carries the tooltip “Shortcodes with recorded clicks can’t be deleted.” The server enforces the same rule independently, and it counts all-time clicks rather than the clicks in the report window, refusing with a 409 and the message “This shortcode has recorded clicks and can no longer be deleted.”

Those two checks can disagree. The button’s enabled state is derived from the windowed click count, so a code whose only clicks fall outside the report window offers a Delete button that then fails with the 409. The server rule is the authoritative one: if a code has ever been clicked, its attribution history stays.

What a click records

Each redirect writes one event carrying the code, its UTM values, the destination, the visitor’s session, the referring host and the time. Two things are deliberately not recorded:

  • Preview-site requests are never counted. A click that arrives through your preview domain redirects normally and writes nothing, which is what keeps your own testing out of the numbers. The two environments are explained in Preview Site vs Live Site.
  • A click with no session to attach to is skipped. Every event is anchored to a session, and a request that arrives without one — a link checker, a client with cookies fully blocked — has nothing to attribute. The redirect still happens; only the event is dropped.

Sessions themselves are described in How Leed Tracks Visitors, and a /s/ click is one of the ways a session gets classified there.

sequenceDiagram
    autonumber
    actor V as Visitor
    participant S as Your site worker
    participant K as Shortcode record
    participant D as Event store
    participant P as Destination page
    V->>S: GET /s/kJ2mQ8vD
    S->>K: Look up the code
    K-->>S: Destination + UTM tags
    alt Preview request, or no session
        S--xD: No event written
    else Live request with a session
        S->>D: Write click event (session, referrer, time, UTM)
    end
    S-->>V: 302 to the destination
    V->>P: Browse pages in the same session
    V->>P: Submit a form
    P->>D: Form fill event on the same session
    Note over D: The journey row for that session<br/>now reads "Form submitted"
    D->>D: Email matches a contact record
    Note over D: The same row becomes "Lead created"

The shape of that diagram is the point: the redirect is synchronous and immediate, but the attribution is a later consequence of the same session id. A click that shows no lead has not failed to record — it simply has not been followed by a form submit yet.

Reading the numbers

Selecting a code loads its report. The window defaults to the trailing eight weeks, bucketed weekly for the trend, and can be narrowed with explicit start and end times through the API. A range may not exceed 365 days, and on plans with a shorter analytics retention the start is silently clamped to your retention cutoff; a window that falls entirely outside it returns a 402 instead.

The right rail carries three facets, each of which reads “No clicks recorded yet.” until the code has been used.

Attribution holds the four headline numbers and the referrer mix:

MetricWhat it countsWindow
ClicksEvery recorded redirect for the codeThe report window
Unique visitorsDistinct sessions that clicked itThe report window
LeadsDistinct contacts reached by matching a post-click form submit’s email to a contact recordThe report window
Click → leadLeads ÷ clicks, shown to one decimal place; exactly 0.0% when there are no clicksThe report window
Where clicks came fromReferrer-host share of clicks; a click with no referrer is grouped as direct, and the shares always total 100%The report window
TrendClick counts in one-week buckets, with empty weeks filled in as zero rather than skippedThe report window

Funnel shows the five click-to-lead steps as bars, and the center card repeats them with each step’s conversion from the one before it:

StepLabel shownWhat counts
1ClicksEvery recorded redirect
2VisitorsDistinct sessions that clicked
3Engaged 2+Clicked sessions that then viewed two or more distinct pages, counting only views at or after the click
4Form submitsClicked sessions that submitted at least one form after the click
5LeadsDistinct contacts matched by email from those submissions

Because every step after the first is anchored to the click, the whole funnel is first-touch attributed to the code: browsing a visitor did before clicking never inflates it.

Journeys counts the attributed sessions and repeats the leads and conversion; the rows themselves are in the center card, newest click first, 25 at a time.

The Attributed journeys list for one short link, with outcome chips and one anonymous row
An anonymous row is a real click Leed could not attach to a person — not a missing record.

Each row shows the person’s name, their email address, how many pages the session touched, how long they were actively reading, and one outcome chip:

ChipMeaning
Lead createdA post-click form submit whose email matches a contact record
Form submittedA post-click form submit that has not been matched to a contact
Still browsingA clicked session with page views and no form submit

Where there is no identity to show, the name reads Anonymous visitor and the email reads Not yet identified. That is an honest row, not a broken one — most clicks are anonymous until the person hands you an email address. Everything the visitor did before that moment is still attached to them once they do, which is the subject of Lead Profiles and Visitor Identity.

Why my code shows clicks but no leads

Work down the funnel and the answer is usually visible in one of three places.

Clicks but no visitors. Every click is anchored to a session, so this should not happen; if it does, the clicks are landing in a different report window than the visitors you are counting.

Visitors but nobody engaged. The destination is being bounced off. Engaged 2+ counts sessions that viewed two or more distinct pages after the click, so a single-page landing experience with no onward link can never advance past step two.

Form submits but no leads. A lead is counted by matching the submitted email address to a contact record on your workspace. If the form does not collect an email address, or the submission was suppressed, there is nothing to match. Contact capture from forms is covered in Contacts.

And one non-answer worth ruling out first: if you have been testing the link yourself on the preview site, none of those clicks exist.

Why the report needs contact access

The journeys list names real people, so /shortcodes/:code/metrics is checked against contact permissions — contact:read scoped to the contact resource — rather than shortcode permissions. Somebody who can see your short links is not automatically allowed to see who clicked them.

The same report also respects your plan’s contact quota. Contacts sitting above the quota are locked, and a journey attributed to one of them comes back with its name and email blanked while the session’s counts and outcome remain. The behavior is deliberately fail-closed: under a finite quota, a journey Leed cannot positively place inside the visible window shows no identity at all. What that quota is and how it behaves is on Contacts, with the numbers in Usage and Limits.

Organizing a long list

Once you have more than a handful of codes, the left panel’s Filter & view button opens a two-part menu. Search, separately, matches a code’s own text and its utm_source — not its destination.

MenuOptions
Group byOn-site / External · UTM source · UTM medium · UTM campaign · None (flat)
Sort byName · Domain · UTM source · UTM medium · UTM campaign

Grouping by UTM campaign is the practical way to review a launch: every code cut for it, on-site and external, in one group.

How this fits the wider attribution picture

A short-link click starts a session on your site and stamps it with the code’s UTM values. Those values then feed the workspace-wide inbound attribution report, which answers the question this page cannot: not how did this one code perform, but which sources, mediums and campaigns brought you traffic and leads across everything you published. That report is in Journeys, Funnels and Attribution and is gated separately from short-link tracking.

FieldRequiredFixed at creationNotes
Destination pageOne of the twoYesStored as a page reference; resolved to the page’s current path on every redirect
External URLOne of the twoYesStored verbatim; converted to a page reference if it points at your own domain and matches a published path
utm_sourceNoYesTrimmed, lower-cased, spaces collapsed to hyphens
utm_mediumNoYesSame normalization
utm_campaignNoYesSame normalization
utm_contentNoYesSame normalization
utm_termNoYesSame normalization
Additional parametersNoYesKey/value pairs; keys limited to letters, digits, ., _, -; both halves percent-encoded
Vanity codeNoYes1–64 lowercase letters, digits and hyphens; becomes the code; a taken value is refused with a 409
CodeGeneratedYesEight mixed-case alphanumeric characters when no vanity is supplied

From an AI client

Over the Operator MCP, short links are read-only: list_shortcodes returns every code on the workspace with its stored fields, and get_shortcode resolves one code to its destination URL and full short link. There is no delete tool, and no MCP tool creates a code.

Creating one from a conversation is possible through the in-product Leed Assistant, which carries a create_shortcode tool marked high risk: it parks the request for your explicit approval before anything is written, because a created code is permanent.

ESC