Skip to content

Customer Data Platform Events

For developers

CDP events that enrich the Segmentify user profile with arbitrary attributes. Business meaning: Event Catalog. Watch the CDP gotchas.

Overview

Customer Data Platform (CDP) events enrich the Segmentify user profile with arbitrary attributes for segmentation, personalization, and targeting.

In this SDK, CDP is exposed through the following methods:

  • Events.UserTraits(params) — arbitrary profile enrichment (USER_TRAITS)
  • Events.IdentifyUser(params) — identify a known user with change-based dedup (USER_IDENTIFY)
  • Events.RegisterUser(params) — CDP registration (USER_REGISTER)
  • Events.LoginUser(params) — CDP login (USER_LOGIN)
  • Events.LogoutUser(params) — CDP logout (USER_LOGOUT)
  • Events.SubscribeUser(params) — channel subscription (USER_SUBSCRIBE)
  • Events.UnsubscribeUser(params) — channel unsubscription (USER_UNSUBSCRIBE)

Unlike USER_OPERATIONS events (Identify, Register, Login, Logout), these CDP events do not use a step field. The payload is sent under a dedicated event name with a properties object.

Transport uses the standard events endpoint (/add/events/v1.json) via sendEvent(), not the push endpoints.

UserTraits, IdentifyUser, RegisterUser, LoginUser, and LogoutUser shallow-clone the payload before sending. Omitted consent fields are not defaulted — only include callConsent, emailConsent, whatsappConsent, or smsConsent when you intend to report or update that channel. Partial profile updates must not overwrite previously reported consent with NOT_SET.

Valid consent values come from the CONSENT const: 'SUBSCRIBED' | 'UNSUBSCRIBED' | 'NOT_SET'.

If the payload is an empty object ({}), these methods no-op and never hit the network.

UserTraits

Method

Events.UserTraits(params)

Type

CdpEventsPayload in src/types.ts:

  • Top-level keys are trait names (string keys).
  • Values are scalars (string, number, boolean, undefined).
  • Typed convenience fields: email, phone, username, source, gender, fullName, and the four *Consent fields.

Flatten grouped traits into top-level keys (e.g. loyalty_level: 'gold'), not nested objects — the index signature is scalar-only.

Parameter semantics

There is no fixed schema: send any trait keys your CDP integration expects. Common examples:

FieldTypeNotes
emailstringProfile identifier when known
genderstringDemographic trait
agenumberNumeric trait
locationstringGeo or region
fullNamestringDisplay name
loyalty_level, location, age, etc.scalarAny additional trait keys your CDP expects
emailConsent, smsConsent, whatsappConsent, callConsentConsentChannel consent (SUBSCRIBED, UNSUBSCRIBED, NOT_SET)

The Expo Event Playground mock payload lives in shared/segmentify-configuration.ts as MOCK_DATA.USER_TRAITS.

Runtime payload behavior

SDK builds and sends:

{
"name": "USER_TRAITS",
"properties": { "...your traits..." }
}

Additional behavior:

  • Empty payload guard: if params has no keys, the method returns immediately and does not call the network.
  • Standard enrichment: sendEvent() adds userId, sessionId, device, os, osversion, currency, lang, testMode, sdkVersion, and email when a user exists in SDK storage (same as other core events).
  • No storage side effects: unlike Register / Login / Identify, UserTraits does not persist the traits object to SEGMENTIFY_USER storage.

When to use UserTraits vs USER_OPERATIONS

GoalMethod
Sign up, sign in, sign out, consent / IYS flowsRegister, Login, Logout, Identify, IysPermission
Arbitrary profile attributes (demographics, loyalty tier, preferences)UserTraits

Typical sequence:

  1. User authenticates → Register or Login (and optionally Identify for consent updates).
  2. Profile or preference data changes → UserTraits with updated trait keys.

IdentifyUser

Events.IdentifyUser(params: CdpEventsPayload) sends USER_IDENTIFY for a known user.

Deduplication: the SDK compares the incoming payload against the last successfully sent identify snapshot and only sends USER_IDENTIFY when it differs. The snapshot is written to AsyncStorage under SEGMENTIFY_USER_PROFILE after the server accepts the event — whether that delivery happens on the initial IdentifyUser call or when a queued event is replayed by onlineEventLogic. Failed sends do not update the snapshot, so the same profile is retried on the next call.

The snapshot is cleared on logout (Logout and LogoutUser) so the next account’s IdentifyUser is not deduplicated against the previous user’s profile.

  • React Native has no Web Crypto / IndexedDB, so (unlike the web SDK) the snapshot is not encrypted at rest. AsyncStorage is sandboxed per app.
  • Comparison is order-independent (keys are sorted before stringify), so reordering keys does not trigger a resend.
await Events.IdentifyUser({
email: 'user@example.com',
username: 'johndoe',
phone: '1234567890',
gender: 'male',
source: 'email-collection',
fullName: 'John Doe',
callConsent: 'SUBSCRIBED',
emailConsent: 'UNSUBSCRIBED',
whatsappConsent: 'NOT_SET',
smsConsent: 'SUBSCRIBED',
});

RegisterUser / LoginUser / LogoutUser

CDP lifecycle events sent under USER_REGISTER, USER_LOGIN, and USER_LOGOUT respectively. Each shallow-clones the payload and no-ops on an empty object. Omitted consent fields are not defaulted. Unlike the USER_OPERATIONS Register / Login, these do not persist to SEGMENTIFY_USER storage and do not run IYS logic.

await Events.RegisterUser({ email: 'user@example.com', username: 'johndoe' });
await Events.LoginUser({ email: 'user@example.com' });
await Events.LogoutUser({ email: 'user@example.com' });

SubscribeUser / UnsubscribeUser

Channel subscription events sent under USER_SUBSCRIBE / USER_UNSUBSCRIBE.

SubscribeUser takes a channel-discriminated SubscribeProperties; the required fields depend on channel:

channelRequired fields
web_pushpushSubscriptionId
emailemail, purpose
whatsappphoneNumber
smsphoneNumber
callphoneNumber

UnsubscribeUser takes { channel, email?, phoneNumber? }.

await Events.SubscribeUser({
channel: 'email',
email: 'test@email.com',
purpose: 'marketing',
});
await Events.SubscribeUser({
channel: 'web_push',
pushSubscriptionId: 'fcm_token_abc123_xyz',
});
await Events.SubscribeUser({
channel: 'whatsapp',
phoneNumber: '1234567890',
});
await Events.SubscribeUser({
channel: 'sms',
phoneNumber: '1234567890',
});
await Events.SubscribeUser({
channel: 'call',
phoneNumber: '1234567890',
});
await Events.UnsubscribeUser({ channel: 'email', email: 'test@email.com' });
await Events.UnsubscribeUser({
channel: 'whatsapp',
phoneNumber: '1234567890',
});

SubscribeUser and UnsubscribeUser send immediately when params is truthy; they do not apply the empty-payload guard used by the CDP lifecycle methods above.

Repository usage

  • Event Playground: example/src/App.tsxCustomer Data Platform section
  • Mock payloads: shared/segmentify-configuration.ts (MOCK_DATA.USER_TRAITS, MOCK_DATA.CDP)
  • Implementation: src/classes/events.ts (UserTraits, IdentifyUser, RegisterUser, LoginUser, LogoutUser, SubscribeUser, UnsubscribeUser)
  • Types: src/types.ts (CdpEventsPayload, SubscribeProperties, UnsubscribePayload, Channel)

Event Playground buttons

User Traits[CDP] Identify User[CDP] Register User[CDP] Login User[CDP] Logout User[CDP] Email Subscribe[CDP] WhatsApp Subscribe[CDP] SMS Subscribe[CDP] Call Subscribe[CDP] Email Unsubscribe[CDP] WhatsApp Unsubscribe[CDP] SMS Unsubscribe[CDP] Call Unsubscribe

Example

import { Events } from '@segmentify/react-native-v2';
await Events.UserTraits({
email: 'product@segmentify.com',
gender: 'male',
age: 30,
location: 'New York',
fullName: 'Jane Doe',
loyalty_level: 'gold',
emailConsent: 'SUBSCRIBED',
whatsappConsent: 'UNSUBSCRIBED',
smsConsent: 'NOT_SET',
callConsent: 'NOT_SET',
});

Checklist

  • Send traits after you have a stable user identity (Register / Login / Identify) when traits depend on known users.
  • Flatten trait keys to the top level (loyalty_level: 'gold'), matching the CdpEventsPayload scalar contract.
  • Avoid calling lifecycle methods with an empty object; the SDK no-ops but you get no analytics signal.
  • Inspect the outgoing payload in debug mode via SDK logger ([Final Payload] log from sendEvent()).