vevee.analytics.identify()POST /api/v1/identifypk_live_

Tell Vevee who the current person is, write profile properties, and - optionally - merge a pre-signup anonymous session into the new account. The merge is a consent-gated operation under GDPR / ePrivacy.

Signature

vevee.analytics.identify(
  distinctId: string,              // the real user id
  properties?: PersonProfile,      // applied as $set (overwrite)
  propertiesOnce?: PersonProfile,  // applied as $set_once (first-write-wins)
  options?: IdentifyOptions,
): Promise<AnalyticsIdentifyResponseData>

interface IdentifyOptions {
  mergeAnonymousId?: string;    // anonymous id to merge from - REQUIRES consent
  consentGiven?: boolean;       // self-declaration that consent was obtained
}

Parameters

NameTypeDescription
distinctIdrequiredstringThe real, stable user id you want events attributed to from now on.
propertiesoptionalPersonProfileProfile properties - overwrite semantics (applied as $set).
propertiesOnceoptionalPersonProfileProfile properties written only if the key is not already set (applied as $set_once). Use for first-touch attribution like signup_source.
options.mergeAnonymousIdoptionalstringThe anonymous id used before signup. Linking it requires consent - see With a merge.
options.consentGivenoptionalbooleanSet true after obtaining explicit consent for the merge. Without it, the SDK throws consent_required.

Response

interface AnalyticsIdentifyResponseData {
  personId: string;
  merged: boolean;   // true when an anonymous person was actually folded in
}

Without a merge - the common case

Once the visitor has signed up, this is what you call on every page load. Idempotent - safe to call repeatedly. Profile properties can also be set inline from capture().

await vevee.analytics.identify(user.id, {
  email: user.email,
  plan: 'pro',
}, {
  signup_source: 'twitter',
});

With a merge - REQUIRES CONSENT

Linking a previously anonymous browsing session to a real account requires explicit end-user consent under GDPR / ePrivacy. Acquire consent through your cookie banner first, then pass consentGiven: true. The SDK throws consent_required (status 400) otherwise.

await vevee.analytics.identify(
  user.id,
  { email: user.email },
  undefined,
  { mergeAnonymousId: anonId, consentGiven: true },
);

The server records the consent in consent_audit_logas a 5-year responsibility-transfer record. APL cannot verify your declaration - as the data controller, that’s your responsibility.

When the merge runs, every analytics_events row, every analytics_distinct_idsmapping, and the anonymous person’s profile are rewritten onto the new identified person. merged comes back true only when there was a real anonymous person to fold in.

!
In hybrid mode (the default), there is no APL-minted anonymous id to merge. The SDK never writes to localStorage, and pre-login events live in analytics_anonymous_events with no person link. Use mergeAnonymousId only when you opt into identified mode (and accept the cookie-banner requirement), or when you mint your own anonymous id with consent already in hand.

Aggregate mode

identify() is disabled in aggregate mode - that universe never identifies individuals. The SDK throws invalid_request. Switch to hybrid (default) or identified if you need user-level analytics.

i
identify is idempotent - safe to call on every page load. After signup, drop mergeAnonymousId and keep just distinctId + profile properties.

Errors

  • consent_required (400) - mergeAnonymousId was passed without consentGiven: true. Acquire consent first.
  • invalid_request (400) - called in aggregate mode, or malformed field.
  • analytics_quota_exceeded (429) - the workspace is over its monthly analytics quota.
  • test_quota_exceeded (429) - the sandbox analytics quota is exhausted.
  • invalid_key (401) - bad or revoked API key.
i
Related: capture(), alias() (same merge mechanic, no $set), Behavioral analytics & funnels and Privacy & GDPR guides.