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
| Name | Type | Description | |
|---|---|---|---|
distinctId | required | string | The real, stable user id you want events attributed to from now on. |
properties | optional | PersonProfile | Profile properties - overwrite semantics (applied as $set). |
propertiesOnce | optional | PersonProfile | Profile properties written only if the key is not already set (applied as $set_once). Use for first-touch attribution like signup_source. |
options.mergeAnonymousId | optional | string | The anonymous id used before signup. Linking it requires consent - see With a merge. |
options.consentGiven | optional | boolean | Set 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.
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.
identify is idempotent - safe to call on every page load. After signup, drop mergeAnonymousId and keep just distinctId + profile properties.Errors
consent_required(400) -mergeAnonymousIdwas passed withoutconsentGiven: true. Acquire consent first.invalid_request(400) - called inaggregatemode, 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.
$set), Behavioral analytics & funnels and Privacy & GDPR guides.