Contact Management

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

This guide covers setting user identity (uid, emailId), attaching profile properties and contacts, tracking screen views and custom events, and updating location.

On this page

Update user properties

The ZTUserManager interface, exposed via ZetaClient.user, performs user operations. Update user data using the builder pattern or by calling updateUser().

ZetaClient.user.builder()
    .setUid("uid")
    .setFirstName("User1")
    .setLastName("last-name")
    .setName("name")
    .setSignedUpAt("2024-09-17T05:54:58.000Z")
    .setSource("source")
    .setEmail(ZTUserEmail(email = "[email protected]"))
    .setEmailId("[email protected]")
    .setPhone(ZTUserPhone(phone = "1234"))
    .setAdditionalProperties(mapOf(
        "zt_test_string" to "zt_test_value",
        "zt_test_number" to 123,
        "zt_test_boolean" to true,
        "zt_test_array" to listOf("zt_test_value1", "zt_test_value2"),
        "zt_test_dict" to mapOf("key" to "value")
    ))
    .submit()
ZetaClient.INSTANCE.getUser().builder()
    .setUid("uid")
    .setFirstName("User1")
    .setLastName("last-name")
    .setName("name")
    .setSignedUpAt("2024-09-17T05:54:58.000Z")
    .setSource("source")
    .setEmail(new ZTUserEmail("[email protected]"))
    .setEmailId("[email protected]")
    .setPhone(new ZTUserPhone("1234"))
    .setAdditionalProperties(Map.of(
        "zt_test_string", "zt_test_value",
        "zt_test_number", 123,
        "zt_test_boolean", true
    ))
    .submit();

You can also create a ZTUser object and call updateUser():

val user = ZTUser(name = "John Wick")
ZetaClient.user.updateUser(user)
ZTUser user = new ZTUser();
user.setName("John Wick");
ZetaClient.INSTANCE.getUser().updateUser(user);

emailId vs email

  • emailId — use when the email should be treated as the unique identifier for the user. This populates the Email field under ZMP Identifiers (as well as the Contact for this email).
  • email — use when you want to add the email as a contact with additional properties (preferences, subscription status). This populates the Contact section.

Important: If the uid is set as an email address in the same builder()...submit() call, the emailId value is ignored.

ZTContactAdditionalInfo

For contacts (email, phone), you can attach additional properties:

val additionalInfo = ZTContactAdditionalInfo().apply {
    subscriptionStatus = ZTContactSubscriptionStatus.ACTIVE
    inactivityReason = "reason"
    signedUpAt = "2024-09-17T05:54:58.000Z"
    lastOpened = "2024-09-17T05:54:58.000Z"
    doubleOptInStatus = "single"
    phoneType = "mobile"
    lastSent = "2024-09-17T05:54:58.000Z"
    lastClicked = "2024-09-17T05:54:58.000Z"
    properties = mapOf("key" to "value")
}
ZetaClient.user.builder()
    .setEmail(ZTUserEmail(email = "[email protected]", additionalInfo = additionalInfo))
    .submit()
ZTContactAdditionalInfo info = new ZTContactAdditionalInfo();
info.setSubscriptionStatus(ZTContactSubscriptionStatus.ACTIVE);
info.setInactivityReason("reason");
info.setSignedUpAt("2024-09-17T05:54:58.000Z");
info.setLastOpened("2024-09-17T05:54:58.000Z");
info.setDoubleOptInStatus("single");
info.setPhoneType("mobile");
info.setProperties(Map.of("key", "value"));

ZetaClient.INSTANCE.getUser().builder()
    .setEmail(new ZTUserEmail("[email protected]", info))
    .submit();

ZTContactAdditionalInfo properties

PropertyTypeDescription
preferenceList<String>Optional. Defaults to ["standard"] if not provided.
subscriptionStatusZTContactSubscriptionStatusContact's subscription state. Supported values: NEW, ACTIVE, INACTIVE, NONE.
inactivityReasonStringOptional. Reason the contact became inactive.
signedUpAtStringOptional. ISO 8601 date-time when the contact signed up.
lastOpenedStringOptional. ISO 8601 date-time when the contact last opened a message.
doubleOptInStatusStringOptional. "single" or "double".
phoneTypeStringOptional. "mobile" or "landline".
lastSentStringOptional. ISO 8601 date-time when a message was last sent to the contact.
lastClickedStringOptional. ISO 8601 date-time when the contact last clicked a message.
propertiesMap<String, Any>Optional. Additional custom contact properties.

Notes

  • All date-time values must be in ISO 8601 format, UTC.
  • preference of a contact defaults to standard. Other preferences can be added or customized inside ZMP Settings; only values defined there may be passed in preference.
  • double_opt_in_status is optional. Default null; accepts single or double.
  • phone_type is optional. Default null; accepts mobile or landline.
  • The snake_case names above refer to JSON payload keys; the corresponding Kotlin properties use camelCase (doubleOptInStatus, phoneType).
  • additionalProperties on ZTUser accepts arbitrary key-value pairs and appears under the User Properties section in ZMP.

Starting and clearing the user identity session

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

ZetaClient.user.builder()
    .setUid("uid")
    .setEmailId("[email protected]")
    .submit()
ZetaClient.INSTANCE.getUser().builder()
    .setUid("uid")
    .setEmailId("[email protected]")
    .submit();

Note: emailId is ignored if the uid is also an email address.

Clear the identity session when the user changes inside your app:

ZetaClient.user.clear()
ZetaClient.INSTANCE.getUser().clear();

Note: Call clear() whenever the user profile changes in your app (sign-out, account switch, etc.).

App Set ID, Advertisement ID, and push tokens

Pass device identifiers to the SDK to enhance user identification.

ZetaClient.user.setAppSetId(appSetId)
ZetaClient.user.setAdvertisementId(advertisementId)
ZetaClient.user.updatePushToken(token)
ZetaClient.INSTANCE.getUser().setAppSetId(appSetId);
ZetaClient.INSTANCE.getUser().setAdvertisementId(advertisementId);
ZetaClient.INSTANCE.getUser().updatePushToken(token);

Note: The App Set ID is scoped to the developer's apps on the device and does not require user consent. The Advertisement ID (GAID) requires user consent under relevant privacy frameworks.

Location tracking

trackLocation() accepts latitude, longitude, and a foreground/background flag. The location is cached in memory and attached to subsequent events as a property.

ZetaClient.user.trackLocation(
    latitude = 12.933663251837913,
    longitude = 77.62168405034637,
    isForeground = true
)
ZetaClient.INSTANCE.getUser().trackLocation(
    12.933663251837913,
    77.62168405034637,
    true
);

Unique client ID

The SDK supports host apps providing a unique_client_id to ZMP. Before using it, review these conditions:

  • 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.
  • A unique_client_id pair is discarded if the same key already exists with a different value.
  • Enabling support for a unique client ID requires site-configuration updates. Coordinate with your account team to ensure the configuration is correct. Using an incorrect or mismatched client ID name may result in errors.
ZetaClient.user.setUniqueClientId(name = "key_name", value = "value")
ZetaClient.INSTANCE.getUser().setUniqueClientId("value", "key_name");

Event tracking

Auto-tracked events

EventWhen fired
app_installedFirst launch only.
app_openedApp transitions from background to foreground.
app_closedApp transitions from foreground to background.

Note: app_terminated is an iOS-only lifecycle event. The Android SDK does not fire this event.

Screen name tracking

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

ZetaClient.event.trackScreenName(
    screenName = "Events Screen",
    deeplink = "app://home",
    properties = mapOf("screen" to "Home")
)
ZetaClient.INSTANCE.getEvent().trackScreenName(
    "Events Screen",
    "app://home",
    Map.of("screen", "Home")
);

Custom events

Send a custom event by passing a name and a map of properties. Properties must be JSON-encodable.

ZetaClient.event.send(
    eventName = "EventTest",
    properties = mapOf(
        "events-array" to listOf("screen1", "screen2"),
        "events-dict" to mapOf("screen" to "events")
    )
)
ZetaClient.INSTANCE.getEvent().send(
    "EventTest",
    Map.of(
        "events-array", List.of("screen1", "screen2"),
        "events-dict", Map.of("screen", "events")
    )
);

Date-time formatting

All date-time values sent as event properties or user properties must be in ISO 8601 format with UTC timezone:

2024-09-17T05:54:58.000Z

The SDK exposes a formatDateToIso() extension on Long that converts a millisecond timestamp to this format:

import net.zetaglobal.app.zetacore.common.ZTDeviceUtil.formatDateToIso

val iso = System.currentTimeMillis().formatDateToIso()
// e.g. "2024-09-17T05:54:58.000Z"
import net.zetaglobal.app.zetacore.common.ZTDeviceUtilKt;

String iso = ZTDeviceUtilKt.formatDateToIso(System.currentTimeMillis());
// e.g. "2024-09-17T05:54:58.000Z"

Next

See also