User Identification
Associate the current browser with a known user (similar to PostHog’s identify). Call once after login or signup; every later push() automatically includes the person context.
Prefer usertrax.identify() as the single call site: when the feedback widget is also on the page, the same call identifies the visitor there too (hides the email field, attaches user metadata). Identity is persisted in localStorage (usertrax_identify), so the widget picks it up even if it loads after the tracker.
Web (Script Tag)
Section titled “Web (Script Tag)”// After the user signs inusertrax.identify("user_xyz", { email: "jane@example.com", plan: "team", seats: 5,});
// Later conversions inherit user_data + meta snapshotusertrax.push({ event: "purchase", total: 49.99, currency: "EUR" });NPM (ESM)
Section titled “NPM (ESM)”tracker.identify("user_xyz", { email: "jane@example.com", plan: "team",});How it works
Section titled “How it works”- Persistence — Stored in
localStorage(usertrax_identify) and reused across page loads and sessions. user_datamerge — Canonical trait keys (email,phone,phone_number,first_name,last_name,name,customer_id,address) are merged into each conversion’suser_data. The distinct id becomescustomer_idwhen you do not set one explicitly. Fields on a singlepush({ user_data: … })override traits fromidentify.- Full trait snapshot — All traits (including custom keys like
planorseats) are sent on every conversion undermeta_data.$usertrax_identify:
{ "distinct_id": "user_xyz", "traits": { "email": "jane@example.com", "plan": "team", "seats": 5 }}- PostHog — When PostHog is loaded and
usertraxConfig.posthogis notfalse,identifyalso callsposthog.identify(distinctId, traits). - Feedback widget — Dispatches
usertrax:identifyso a loaded feedback widget applies the same identity (also hydrates fromlocalStorageon boot).
Supported trait keys for user_data
Section titled “Supported trait keys for user_data”| Trait key | Maps to user_data |
|---|---|
email | Yes |
phone | Yes |
phone_number | Yes |
first_name | Yes |
last_name | Yes |
name | Yes |
customer_id | Yes |
address | Yes |
| Any other key | meta_data only |
Use setUserData() when you only need Google Enhanced Conversions hashing without a stable distinct id — see Ads & Enhanced Conversions. Use identify() when you want a persistent person id and traits on all events.
Visitor profiles (uxv_id)
Section titled “Visitor profiles (uxv_id)”The tracker also stores a durable visitor id in localStorage under uxv_id (independent of session timeout / uxs_id) and sends it as visitor_id on both session and conversion events. That lets returning visitors and identified users appear as one profile in the dashboard.
Profiles are created on identify, not on arrival
Section titled “Profiles are created on identify, not on arrival”A visitor_id alone does not create a profile. One is only materialized once identify() supplies an email or customer_id, so anonymous visitors never show up in the profile list.
No history is lost: the visitor_id is stored on every session, and as soon as someone identifies, their earlier anonymous sessions and conversions are attached to the new profile retroactively.
The reason: without this rule every browser would get a profile — and one per page view wherever localStorage is blocked — producing large numbers of profiles holding a single session and no identity. For pure session analysis, the sessions view is the right place.
Opt-out / Opt-in
Section titled “Opt-out / Opt-in”// Stop profile linking: clears uxv_id + usertrax_identifyusertrax.optOut();// Later events send profile_opt_out: true (no visitor_id)
// Re-enable / grant consent: mints a new uxv_idusertrax.optIn();Consent mode
Section titled “Consent mode”Default is opt-out (profilesRequireConsent: false): uxv_id is minted automatically. For consent-banner flows (e.g. TTDSG / ePrivacy), set:
window.usertraxConfig = { profilesRequireConsent: true, // no uxv_id until optIn()};While consent is pending, session and conversion events send profile_opt_out: true. This matters: identify() puts email / customer_id into user_data, and without that flag the API would stitch a profile from those strong IDs before consent was ever granted. Sessions and conversions still track as usual — only the profile link is withheld.
With profiles: false, a visitor id is never minted or sent.
See also Configuration & API.
Limitations
Section titled “Limitations”- Safari / ITP: Script-written
localStoragemay expire after about 7 days of inactivity.uxv_idis therefore not durable on Safari — “returning visitor over months” does not hold for a meaningful share of traffic. - Cross-domain:
uxv_idis not propagated across domains (only the session id via theuxsURL param). Teams tracking several domains get one profile per domain unless the visitor is identified by a strong id (email/customer_id).