Skip to content

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.

// After the user signs in
usertrax.identify("user_xyz", {
email: "jane@example.com",
plan: "team",
seats: 5,
});
// Later conversions inherit user_data + meta snapshot
usertrax.push({ event: "purchase", total: 49.99, currency: "EUR" });
tracker.identify("user_xyz", {
email: "jane@example.com",
plan: "team",
});
  1. Persistence — Stored in localStorage (usertrax_identify) and reused across page loads and sessions.
  2. user_data merge — Canonical trait keys (email, phone, phone_number, first_name, last_name, name, customer_id, address) are merged into each conversion’s user_data. The distinct id becomes customer_id when you do not set one explicitly. Fields on a single push({ user_data: … }) override traits from identify.
  3. Full trait snapshot — All traits (including custom keys like plan or seats) are sent on every conversion under meta_data.$usertrax_identify:
{
"distinct_id": "user_xyz",
"traits": { "email": "jane@example.com", "plan": "team", "seats": 5 }
}
  1. PostHog — When PostHog is loaded and usertraxConfig.posthog is not false, identify also calls posthog.identify(distinctId, traits).
  2. Feedback widget — Dispatches usertrax:identify so a loaded feedback widget applies the same identity (also hydrates from localStorage on boot).
Trait keyMaps to user_data
emailYes
phoneYes
phone_numberYes
first_nameYes
last_nameYes
nameYes
customer_idYes
addressYes
Any other keymeta_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.

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.

// Stop profile linking: clears uxv_id + usertrax_identify
usertrax.optOut();
// Later events send profile_opt_out: true (no visitor_id)
// Re-enable / grant consent: mints a new uxv_id
usertrax.optIn();

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.

  • Safari / ITP: Script-written localStorage may expire after about 7 days of inactivity. uxv_id is therefore not durable on Safari — “returning visitor over months” does not hold for a meaningful share of traffic.
  • Cross-domain: uxv_id is not propagated across domains (only the session id via the uxs URL param). Teams tracking several domains get one profile per domain unless the visitor is identified by a strong id (email / customer_id).