Contact management

Identify users, update user properties and contacts, and track events.

Once the SDK is initialized, you can begin tracking user identity and behavior. This guide will walk you through updating user profiles, managing email and phone contacts, handling session identity, tracking locations, and sending custom events.

On this page


Update user properties

You can update user profile data in two ways: using the builder pattern or by passing a ZTUser object directly to updateUser().

Using the Builder Pattern (Recommended)

The builder pattern provides a clean, fluent API to set multiple properties at once:

ZetaClient.user.build((user) => {
  user.uid = 'user-unique-id';
  user.firstName = 'John';
  user.lastName = 'Doe';
  user.name = 'John Doe';
  user.signedUpAt = '2026-07-01T10:30:00Z'; // ISO 8601 format
  user.source = 'organic';
  user.emailId = '[email protected]';

  user.email = {
    email: '[email protected]',
    additionalInfo: {},
  };

  user.phone = {
    phone: '+1234567890',
    additionalInfo: {},
  };

  user.additionalProperties = {
    membership_level: 'gold',
    preferred_language: 'en',
    points_balance: 1500,
    is_subscribed: true,
  };

  user.location = {
    latitude: 40.7128,
    longitude: -74.006,
    isForeground: true,
  };
});

Direct Object Update

Alternatively, you can pass a partial ZTUser object directly:

const user = {
  name: 'Jane Smith',
  firstName: 'Jane',
  lastName: 'Smith',
};
ZetaClient.user.updateUser(user);

Understand emailId vs email

When updating user profiles, it is important to distinguish between emailId and email:

  • user.emailId: Use when the email address should be treated as the user's primary unique identifier. This populates the Email field under ZMP Identifiers (and also creates a Contact for this email).
  • user.email: Use when you want to add the email as a contact channel with additional properties (such as subscription status or preferences). This populates the Contact section in ZMP.

Important: If the user's uid is set to an email address in the same submission, the emailId value is ignored.


Add contact additional info

For email and phone contacts, you can attach rich metadata using the ZTContactAdditionalInfo object:

const contactAdditionalInfo = {
  subscriptionStatus: 'active',
  inactivityReason: 'none',
  signedUpAt: '2026-07-01T10:30:00Z',
  doubleOptInStatus: 'single',
  phoneType: 'mobile',
  lastSent: '2026-07-01T10:30:00Z',
  lastOpened: '2026-07-01T10:30:00Z',
  lastClicked: '2026-07-01T10:30:00Z',
  properties: { marketing_segment: 'newsletter' },
};

ZetaClient.user.build((user) => {
  user.email = {
    email: '[email protected]',
    additionalInfo: contactAdditionalInfo,
  };
});

Contact Additional Info Properties

  • preference (string[]): Optional. Defaults to ["standard"] if not provided. Other preferences can be customized in ZMP Settings; only values defined there may be passed here.
  • subscriptionStatus (string): The contact's subscription state. Supported values are new, active, or inactive.
  • inactivityReason (string): Optional. Reason for contact inactivity.
  • signedUpAt (string): Optional. Date when the contact signed up (ISO 8601 format recommended).
  • doubleOptInStatus (string): Optional. Default is null; accepts single or double.
  • phoneType (string): Optional. Default is null; accepts mobile or landline.
  • lastSent / lastOpened / lastClicked (string): Optional. Date-time values in ISO 8601 format, UTC.
  • properties (object): Optional. Additional custom key-value pairs for the contact.

Manage the user identity session

The SDK tracks user session-specific properties and events. Setting uid or emailId starts the user identity session:

ZetaClient.user.build((user) => {
  user.uid = 'john123';
  user.emailId = '[email protected]';
});

Clearing the user session

When a user logs out or switches accounts, clear the identity session on the device. This ensures subsequent events are not associated with the previous user:

ZetaClient.user.clear();

Listen for identity updates

Native identity callbacks are surfaced to JavaScript through an event listener. Register a listener for ZetaCoreEvents.IdentityDelegate, then call ZetaClient.getCachedBSIN() to request the current identity state. The event carries the device's bsin (Browser Session Identifier), which ZMP assigns shortly after initialization:

import { Platform, NativeEventEmitter, DeviceEventEmitter } from 'react-native';
import ZetaClient, { ZetaCoreEvents } from 'zetakit_reactnative';

const eventEmitter = Platform.select({
  ios: new NativeEventEmitter(ZetaClient.bridge),
  android: DeviceEventEmitter,
});

const identityListener = eventEmitter?.addListener(
  ZetaCoreEvents.IdentityDelegate,
  (event) => {
    console.log('Identity updated. BSIN:', event.bsin);
  }
);

// Request the current BSIN; the listener above receives the result.
ZetaClient.getCachedBSIN();

Call setIdentityDelegate() once after SDK initialization, on both iOS and Android, to receive automatic updates whenever the BSIN changes:

ZetaClient.user.setIdentityDelegate();

Important: Register the listener before calling getCachedBSIN(), and call identityListener?.remove() when the owning component unmounts.


Set advertising and vendor identifiers

Pass the device's advertising identifier (IDFA on iOS, GAID on Android) and the vendor/app-set identifier to enable cross-device identity resolution:

ZetaClient.user.setIdentifierForAdvertiser(idfaString);

ZetaClient.user.setIdentifierForVendor(idfvString);

Track location

Pass location coordinates along with a foreground/background flag. The provided location is cached in memory and automatically attached to subsequent events as a property:

const location = {
  latitude: 40.7128,
  longitude: -74.006,
  isForeground: true, // Indicates if collected while app is in foreground
};
ZetaClient.user.updateLocation(location);

Configure unique client IDs

The SDK supports providing a unique_client_id to ZMP for advanced profile-merge scenarios. Before using it, review these conditions:

  • Profile Merging: No two profiles may have the same unique_client_id name:value pair. If a profile is updated with a unique_client_id matching another profile, the profiles are merged.
  • Value Constraints: A unique_client_id pair is discarded if the same key already exists with a different value.
  • Coordination: Enabling support for a unique client ID requires site-configuration updates. Coordinate with your Zeta account team to ensure the configuration is correct.
ZetaClient.user.setUniqueClientId('custom_client_key', 'custom_client_value');

Track custom and screen events

Auto-tracked lifecycle events

The SDK automatically tracks the following core lifecycle events:

  • app_installed: Fired on the very first launch.
  • app_opened: Fired when the app transitions from the background to the foreground.
  • app_closed: Fired when the app transitions from the foreground to the background.
  • app_terminated: Fired when the app is fully closed (iOS only).

Screen name tracking

Use trackScreenName() to track user screen navigation. The provided screen name is cached in memory and attached to subsequent events as a property:

ZetaClient.events.trackScreenName('ProductDetailScreen', 'myapp://product/123', {
  category: 'electronics',
});

Custom events

Send custom events by passing an event name and a dictionary of properties. Properties must be JSON-serializable:

ZetaClient.events.send('purchase_completed', {
  item_id: 'sku_12345',
  price: 99.99,
  currency: 'USD',
  tags: ['promo', 'summer_sale'],
});

Important: If any property value is not serializable to JSON, the entire event data is silently discarded.


Next

Now that you can identify users and track events, continue to configure messaging channels:

See also