Identity & Sessions
Link anonymous browsing to known users and manage session lifecycle. Identity is what turns anonymous page views into actionable user profiles.
The sign-in flow
This is the pattern every web app should follow:
import { init, track, identify, reset } from '@poluruprvn/pug-web'
init('PROJECT_ID', { apiKey: 'KEY', endpoint: 'https://api.pug.sh' })
// 1. Anonymous browsing — events accumulate against anonymous profile
track('page_view')
track('add_to_cart', { product_id: 'sku-123' })
// 2. User signs in — merge anonymous history into identified profile
async function onSignIn(user: { id: string; email: string; plan: string }) {
identify(user.id, {
email: user.email,
plan: user.plan,
name: user.name
})
track('login', { method: 'email' })
}
// 3. User signs out — clear identity, start fresh anonymous session
function onSignOut() {
reset()
track('page_view') // new anonymous session
}After identify(), all prior anonymous events (page views, cart additions) appear on the identified profile in Profiles.
Identify
Link anonymous activity to a known user:
import { identify } from '@poluruprvn/pug-web'
identify('user-123', {
email: 'user@example.com',
plan: 'pro',
company: 'Acme Inc',
signed_up_at: '2026-01-15'
})Rules:
- Call
identify()as early as possible after sign-in — before any post-logintrack()calls - Use a stable, unique external ID (your database user ID, not email)
- Traits are merged — subsequent
identify()calls add/update traits without removing existing ones - The same external ID always resolves to the same profile
Identify on every page load for logged-in users
If your app restores sessions from cookies (most apps do), call identify() on every page load for authenticated users:
// On app init, after checking auth state
if (currentUser) {
identify(currentUser.id, {
email: currentUser.email,
plan: currentUser.plan
})
}This ensures returning visitors are recognized immediately, not just after an explicit sign-in event.
Reset
Clear identity on sign-out or account switch:
import { reset } from '@poluruprvn/pug-web'
reset()reset():
- Clears the stored identity
- Starts a new anonymous session
- Does not delete the identified profile — it remains in the dashboard
Always call reset() before a different user signs in on a shared device.
Sessions
Sessions group events within a single visit.
How sessions work
First event → session ID created
Events within 30 min → same session ID (timeout configurable)
30 min idle → session expires
Next event → new session ID (identity preserved)The Web SDK:
- Creates a session ID on the first event after init
- Extends the session on each event within the timeout window
- Syncs session ID across browser tabs via
localStorage
Configure timeout in init:
init('PROJECT_ID', {
apiKey: 'KEY',
session: { timeoutMs: 30 * 60 * 1000 } // 30 minutes
})Force session rotation
Start a new session without clearing identity — useful after explicit “new visit” signals:
import { rotate } from '@poluruprvn/pug-web'
rotate()| Function | Clears identity | New session ID |
|---|---|---|
rotate() | No | Yes |
reset() | Yes | Yes |
Alias
Merge two profile IDs server-side — for cases where a user had separate profiles before and after a migration:
anonymous-abc ──alias──▶ user-123
legacy-id-xyz ──alias──▶ user-123Alias is a server-side operation via ProfilesSDKService. Contact your backend team or use the Profiles API directly. The Web SDK does not expose a client-side alias function.
Backend
Identify calls ProfilesSDKService.Identify via Connect RPC:
POST /profiles.v1.ProfilesSDKService/Identify
Authorization: Bearer <sdk-api-key>
x-project-id: <project-id>Profile writes are async — expect a few seconds before the profile appears in dashboard search.
Common mistakes
| Mistake | Consequence | Fix |
|---|---|---|
Never calling identify() | All users stay anonymous | Call on sign-in and page load for auth’d users |
| Using email as external ID | ID changes if email changes | Use database user ID |
Skipping reset() on sign-out | Next user’s events attributed to previous user | Always reset on sign-out |
Calling identify() before init() | Silent failure | Init first |
| Different IDs across platforms | Duplicate profiles | Use same ID scheme on web and mobile |
Verify identity
- Browse anonymously — check Profiles for anonymous profile with events
- Sign in — call
identify() - Refresh Profiles — search by external ID; pre-login events should appear
- Sign out — call
reset(); new anonymous profile created
Further reading
- Profiles dashboard
- Profiles API
- Retention analysis — requires consistent identity