Identifying users
How visitors, users and sessions work, and when to call identify() and reset().
LaunchPulse tracks anonymous visitors out of the box. If your product has accounts, calling identify() connects those anonymous sessions to a real user in your database.
Visitor, user, actor
Three ids, and the difference matters when you read numbers in the dashboard.
| Id | What it is |
|---|---|
visitor_id | The anonymous per-browser id. Assigned automatically on init() |
user_id | What you set via identify(). Empty until you call it |
| actor | user_id when present, otherwise visitor_id |
The actor is the unit used for conversion, activation and “people” counts. That’s the point of identifying: without it, the same person on their laptop and their phone is two actors. With it, they’re one.
The dashboard’s Visitors metric counts distinct visitor_id — it is deliberately browser-level, so it stays comparable whether or not you identify.
identify()
lp.identify("user_8f21c");
Sets the user id, persists it in the _lp_vid cookie, and emits a $identify event.
Pass an internal user id, never PII. The SDK warns in the console if the value looks like an email address. Emails end up in your analytics store, in the events log, and in anything you export. A database id doesn’t.
// Good
lp.identify(user.id);
// Bad — warns, and puts an email in your analytics
lp.identify(user.email);
Call it as soon as you know who the person is: right after login, right after signup, and on every page load for an already-authenticated session. The value persists in the cookie, so re-calling it with the same id is harmless and keeps identity correct after the cookie expires or the user clears storage.
Call it before your first-value event, so that event can be attributed to a user. See Conversions and activation.
// React, after your session loads
useEffect(() => {
if (session?.user) window.lp?.identify(session.user.id);
}, [session]);
reset()
lp.reset();
Clears the user id and rotates both the visitor id and the session id. Everything after the call is a fresh anonymous browser.
Call it on logout. Call it on any shared device — a kiosk, a support machine, a demo laptop — where the next person must not inherit the previous person’s identity.
Don’t call it on every page load or on a route change. Rotating the visitor id throws away 30 days of attribution history for that browser.
The cookie
Identity lives in a first-party cookie named _lp_vid.
| Property | Value |
|---|---|
| Visitor id format | lpv_<base36 time><10 random chars> |
| Visitor lifetime | 30 days (cookie Max-Age) |
| Session inactivity timeout | 30 minutes |
| Flags | Path=/, SameSite=Lax, Secure on https, optional Domain |
A visitor that returns within 30 days is the same visitor_id. After 30 days of no visits, they come back as a new visitor.
A session ends after 30 minutes of inactivity. The next event after that gap mints a new session id.
Subdomains
Without a Domain, the cookie is host-only — app.yourapp.com and www.yourapp.com would be separate visitors. Set cookieDomain to share identity across subdomains:
LaunchPulse.init("lp_pub_yourkey", { cookieDomain: ".yourapp.com" });
The collector normally supplies this automatically. The SDK ships no public-suffix list, so it can never mis-scope your cookie.
Attribution
Attribution is stored on the visitor, and it comes in two flavors.
First-touch is frozen for the visitor’s lifetime. Whatever brought someone in the first time stays attached to every event they ever send, for 30 days:
first_sourcefirst_campaignfirst_landing_page
Session attribution refreshes on each new session:
session_sourcesession_mediumsession_campaignsession_landing_page
So if someone finds you through a Hacker News post, leaves, and comes back a week later via a Google search, first-touch still says Hacker News, and session attribution says Google. That’s what makes it possible to tell what actually acquires people versus what merely brings them back.
How source is classified
- UTM params win.
utm_sourcebecomes the source;utm_medium, orcampaignif there’s no medium, becomes the medium. - Otherwise the referrer host, stripped of
www., and ignored when it matches your own host. Medium isorganicfor google, bing, duckduckgo, yahoo, ecosia and brave, andreferralfor everything else. - Otherwise
direct/direct.
Captured UTM parameters: utm_source, utm_medium, utm_campaign, utm_content, utm_term.
More on reading this in Sources and Domains and referrers.
Privacy
Your visitors’ IP addresses are used only to derive a country, then discarded. They are never stored. Combined with the “no PII in identify()” rule, that keeps your analytics free of personal data by default. See Security.
Identifying from your backend
Server-side events carry identity too — you set user_id in the payload rather than calling identify(). See Server-side events. Use the same id in both places, or you’ll end up with two actors for one person.