Most people who read your site never tell you who they are. Leed records what they did anyway — which pages, in what order, for how long — against an anonymous first-party identifier, so that the history has an owner waiting the moment someone identifies themselves. This page is about that moment: what is stored before it, what triggers it, and what does and does not get attached afterwards.
Identification is always something the visitor does. There is no purchased identity graph and no reverse-IP lookup behind any of this. Somebody becomes a person in your workspace by handing over an email address, in one of six ways.
The three cookies
All three are set on your own domain by your own site, so none of them is a third-party cookie, and all three are readable by scripts on the page.
| Cookie | What it holds | Lifetime | Set by | Readable by page scripts |
|---|---|---|---|---|
__lid | The visitor id — one UUID per browser, the key everything else hangs off | 1 year | The session middleware, on the first request that arrives without a valid one | Yes |
__sid | The session id — a new one starts whenever this cookie is absent | 30 minutes, refreshed on every request | The same middleware | Yes |
___gimme___ | A one-shot flag meaning this browser has not sent a fingerprint yet | 30 minutes, deleted as soon as a fingerprint arrives | Set when a new visitor id or a new session is created outside the tracker path | Yes |
Both __lid and __sid have their expiry pushed forward on every response, so an active reader’s session never expires mid-visit and a returning reader keeps the same visitor id for a year of continuous use. A browser that clears cookies, or a private window, produces a new __lid and therefore a new anonymous visitor.
What the ___gimme___ cookie does
Not every arrival on your site runs the trackers. Somebody who clicks a tracked email link, a short link or a gated-file link lands on a redirect endpoint, and that request has to open a session before any JavaScript has run — so there is no device fingerprint to record with it.
When that happens, Leed sets ___gimme___ on the response. The next time the browser loads a real page and the trackers initialize, the presence of that cookie is what makes the page send its fingerprint and screen size to /api/lid. The cookie is deleted the moment a fingerprint arrives, so it is never sent twice for the same visitor.
The fingerprint is a hashed device signature plus the screen width and whether the browser looks like a private window. It is used for one thing: matching a returning visitor back to an existing __lid when the cookie itself has gone. It is not exposed on the contact record and is not part of any report.
What a session records
A session is a bounded stretch of activity: it opens when a request arrives with no __sid, and its end time is pushed forward by every subsequent request. The page views inside it are stored against it, which is what makes “three pages, eleven minutes” a meaningful row later on. The scripts that write those page views — and the rest of the measurement side, which this page deliberately leaves alone — are covered by how Leed tracks visitors. This page owns identity; that one owns measurement.
The session also records how it started, classified from the path of the very first request. That classification is the entry source you see against a session on a contact record.
| Entry path | Session start type | What it means in practice |
|---|---|---|
…/clerk | form_fill | The first thing this browser did was post a form |
/s/… | shortcode | Arrived through a tracked short link |
/f/… | file_download | Arrived through a gated-file link |
/e/… | email | Arrived through a tracked link in one of your emails |
| anything else | pageview | An ordinary page load |
The entry source shown per session on a contact is not quite the same thing: it prefers the referring host of the session’s first page view, falls back to Email when the session started from an email link, and otherwise reads Direct. So a short-link click with no referrer displays as Direct even though the session’s start type is shortcode. That is worth knowing before you report it as a bug — the click itself is recorded in full on the short link’s own report.
Recognizing a returning visitor
A page on your site can ask Leed whether the current __lid belongs to somebody already known. The answer is deliberately thin: known: true, a greeting, and the profile fields the form needs to prefill — with the internal contact id stripped out before the response leaves the server. A script on your page can personalize; it cannot enumerate your contact database.
The six ways someone becomes identified
Every path ends at the same write: a contact upserted on the pair (workspace, email address). The email address is the key, which is why the same person arriving twice through two different routes produces one record, not two.
flowchart TD
subgraph onsite["On your site — a browser and a session are present"]
A["First visit"] --> B["__lid set for a year<br/>__sid set for 30 minutes"]
B --> C["Session opened, entry path classified"]
C --> D["Page views recorded against the session"]
D --> E{"Identifying event<br/>during this session?"}
E -- "no" --> D
E -- "form submitted" --> F1["source: form"]
E -- "documentation sign-in" --> F2["source: mcp"]
E -- "tracked email link clicked" --> F3["source: valid_email"]
end
subgraph offsite["Off your site — no browser, no session"]
G1["CSV import"] --> H1["source: upload"]
G2["Added by hand in Engage"] --> H2["source: manual"]
G3["Salesforce webhook"] --> H3["source: salesforce"]
end
F1 --> S["The session it happened in is<br/>stamped with the contact id"]
F2 --> S
F3 --> S
S --> U["Contact created or matched<br/>on workspace + email address"]
H1 --> U
H2 --> U
H3 --> U
F2 -.->|"this path only"| W["Every earlier session recorded<br/>against the same __lid is<br/>attached as well"]
W --> U
U --> X["Return visits recognised from __lid"]
| Path | What the visitor did | Source recorded | What history comes with them |
|---|---|---|---|
| On-site form fill | Submitted one of your published forms | form | The session the form was submitted in, including everything they read in that visit before filling it in |
| Documentation sign-in | Verified their email to reach your docs through the reader flow | mcp | The identifying session plus every earlier session recorded against the same __lid |
| Email open or click | Opened or clicked a tracked link in one of your emails | valid_email | The session the click started |
| CSV import | Nothing — you brought them in | upload | None; there is no browser session to attach |
| Added by hand in Engage | Nothing — you typed them in | manual | None |
| Salesforce sync | Nothing — the record arrived over the inbound webhook | salesforce | None |
A contact whose source reads salesforce came in through one bespoke inbound webhook rather than a configurable connector; CRM integration says exactly what is and is not wired up. The most common path by a wide margin is the first one, and form submissions covers what happens to the rest of the submitted fields. A reader who signs in to your documentation arrives as a real contact too, through the reader sign-in flow.
What the profile looks like
The profile is the Engage contact record — the same screen documented in full on Contacts. Identity fields, source, persona match and scores all live there. Two parts of it are this page’s subject.
Site engagement, in the center card, opens with four totals across the contact’s whole history — Sessions, Pages viewed, Form fills and Last active — then ranks the pages they viewed by view count with a bar apiece and a +N more pages tail, then lists their most recent sessions with a date, a duration, a page count and an entry source, with +N earlier sessions beneath.
Activity, in the right-hand facet rail, is the same material read chronologically instead of by page: page views and form submissions interleaved newest first, each reading Viewed+N earlier events.
Neither panel invents anything. A contact with no attached sessions reads No site activity recorded yet. — which, given the asymmetry above, is a perfectly ordinary state for someone you imported from a CSV.
Reading that history as progress through your funnel is a separate exercise, and journey stages is the vocabulary for it.
What the Starter plan gates
The gate is unusual and worth describing exactly, because it does not look like a gate.
Below Starter, the contact detail request still succeeds. The server returns the profile with its identity fields intact and the three activity arrays empty, plus a readerIdentityGated flag that the UI keys its upgrade state on. Nothing 402s, nothing errors, and a tampered client gets the same empty arrays — the data is withheld at the source rather than hidden in the browser. This is one of the four gate shapes described in when a feature is gated.
The profile itself is never gated. Identified contacts, their names, titles, accounts and sources are a Free-tier capability; only the per-person drill-down is paid.
Privacy posture, stated plainly
- Identification is always visitor-initiated. Nothing here identifies a person who has not given you their email address.
- Tracking is first-party. The cookies are set on your own domain by your own site, and the requests go to your own domain.
- Marketing consent is a different thing and is recorded per contact. An opt-in is written when someone identifies themselves through a form, and an opt-out suppresses them on every send thereafter.
- Nothing on your preview site is recorded. Sessions, page views, form fills and short-link clicks are all skipped for preview requests, deliberately, so that your own testing never contaminates your data. Preview site versus live site has the rest of the differences.
Where the old profile URL went
/leaddetail/:id still resolves and still renders the older, single-page lead view. It is not where the product points any more — every link from Engage goes to the contact record — but an old bookmark or a link in a saved report will not break. Legacy URLs that still work lists the rest of them.