Contact Management
Identify users, update user properties and contacts, and track events.
This guide covers how to set the user identity, update contacts and custom properties, pass device identifiers, track location, and send custom and screen-name events through the Zeta iOS SDK.
On this page
- Update user properties
emailIdvsemailZTContactAdditionalInfo- Starting and clearing the user identity session
- Passing IDFA, IDFV, and push tokens
- Location tracking
- Unique client ID
- Event tracking
Update user properties
The ZTUserManagable protocol, exposed from ZetaClient, performs user operations. Update user data using the builder pattern, or build a ZTUser object and call updateUser(_:).
ZetaClient.shared.user?.build { user in
user.uid = "uid"
user.firstName = "User1"
user.lastName = "last-name"
user.name = "name"
user.signedUpAt = "2024-09-17T05:54:58.000Z"
user.source = "source"
user.email = ZTUserEmail(email: "[email protected]")
user.emailId = "[email protected]" // only accepted if uid is not email
user.phone = ZTUserPhone(phone: "1234")
user.additionalProperties = [
"zt_test_string": "zt_test_value",
"zt_test_number": 123,
"zt_test_boolean": true,
"zt_test_array": ["zt_test_value1", "zt_test_value2", "zt_test_value3"],
"zt_test_dict": ["zt_test_dict_key": "zt_test_dict_value"]
]
}
let user = ZTUser(name: "John Wick")
ZetaClient.shared.user?.updateUser(user)
[[ZetaClient shared].user build:^(ZTUser *user) {
user.uid = @"uid";
user.firstName = @"User1";
user.lastName = @"last-name";
user.name = @"name";
user.signedUpAt = @"2024-09-17T05:54:58.000Z";
user.source = @"source";
user.emailId = @"[email protected]"; // only accepted if uid is not email
ZTContactAdditionalInfo *ztAdditionalInfo = [[ZTContactAdditionalInfo alloc] init];
ZTUserEmail *ztEmail = [[ZTUserEmail alloc] initWithEmail:@"[email protected]" additionalInfo:ztAdditionalInfo];
user.email = ztEmail;
ZTContactAdditionalInfo *ztAdditionalInfoPhone = [[ZTContactAdditionalInfo alloc] init];
ZTUserPhone *ztPhone = [[ZTUserPhone alloc] initWithPhone:@"1234" additionalInfo:ztAdditionalInfoPhone];
user.phone = ztPhone;
user.additionalProperties = @{
@"zt_test_string": @"zt_test_value",
@"zt_test_number": @123,
@"zt_test_boolean": @YES,
@"zt_test_array": @[@"zt_test_value1", @"zt_test_value2", @"zt_test_value3"],
@"zt_test_dict": @{@"zt_test_dict_key": @"zt_test_dict_value"}
};
}];
ZTContactAdditionalInfo *ztAdditionalInfo = [[ZTContactAdditionalInfo alloc] init];
ZTUserEmail *ztEmail = [[ZTUserEmail alloc] initWithEmail:@"[email protected]" additionalInfo:ztAdditionalInfo];
ZTContactAdditionalInfo *ztAdditionalInfoPhone = [[ZTContactAdditionalInfo alloc] init];
ZTUserPhone *ztPhone = [[ZTUserPhone alloc] initWithPhone:@"1234" additionalInfo:ztAdditionalInfoPhone];
ZTLocation *location = [[ZTLocation alloc] initWithLatitude:12.933663251837913
longitude:77.62168405034637
isForeground:YES];
ZTUser *user = [[ZTUser alloc]
initWithUid:@"uid"
emailId:@"[email protected]"
firstName:@"User1"
lastName:@"last-name"
name:@"John Wick"
signedUpAt:@"2024-09-17T05:54:58.000Z"
email:ztEmail
phone:ztPhone
source:@"source"
location:location
additionalProperties:@{
@"zt_test_string": @"zt_test_value",
@"zt_test_number": @123,
@"zt_test_boolean": @YES,
@"zt_test_array": @[@"zt_test_value1", @"zt_test_value2", @"zt_test_value3"],
@"zt_test_dict": @{@"zt_test_dict_key": @"zt_test_dict_value"}
}];
[[ZetaClient shared].user updateUser:user];
emailId vs email
emailId vs emailuser.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).user.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
uidis set as an email address in the samebuildcall, theemailIdvalue is ignored.
ZTContactAdditionalInfo
ZTContactAdditionalInfoFor contacts (email, phone), you can attach additional properties:
ZetaClient.shared.user?.build { user in
let ztAdditionalInfo = ZTContactAdditionalInfo()
ztAdditionalInfo.subscriptionStatus = .active
ztAdditionalInfo.inactivityReason = "reason"
ztAdditionalInfo.signedUpAt = "2024-09-17T05:54:58.000Z"
ztAdditionalInfo.lastOpened = "2024-09-17T05:54:58.000Z"
ztAdditionalInfo.doubleOptInStatus = "single"
ztAdditionalInfo.phoneType = "mobile"
ztAdditionalInfo.lastSent = "2024-09-17T05:54:58.000Z"
ztAdditionalInfo.lastClicked = "2024-09-17T05:54:58.000Z"
ztAdditionalInfo.properties = ["key": "value"]
user.email = ZTUserEmail(email: "[email protected]", additionalInfo: ztAdditionalInfo)
}
[[ZetaClient shared].user build:^(ZTUser *user) {
ZTContactAdditionalInfo *info = [[ZTContactAdditionalInfo alloc] init];
info.subscriptionStatus = ZTContactSubscriptionStatusActive;
info.inactivityReason = @"reason";
info.signedUpAt = @"2024-09-17T05:54:58.000Z";
info.lastOpened = @"2024-09-17T05:54:58.000Z";
info.doubleOptInStatus = @"single";
info.phoneType = @"mobile";
info.lastSent = @"2024-09-17T05:54:58.000Z";
info.lastClicked = @"2024-09-17T05:54:58.000Z";
info.properties = @{@"key": @"value"};
user.email = [[ZTUserEmail alloc] initWithEmail:@"[email protected]" additionalInfo:info];
}];
ZTContactAdditionalInfo properties
ZTContactAdditionalInfo properties| Property | Type | Description |
|---|---|---|
preference | [String] | Optional. Defaults to ["standard"] if not provided. |
subscriptionStatus | ZTContactSubscriptionStatus | Contact's subscription state. Supported values: new, active, inactive, none. |
properties | [String: Any] | Optional. Additional custom contact properties. |
Notes
- All date-time values must be in ISO 8601 format, UTC.
preferenceof a contact defaults tostandard. Other preferences can be added or customized inside ZMP Settings; only values defined there may be passed inpreference.double_opt_in_statusis optional. Defaultnull; acceptssingleordouble.phone_typeis optional. Defaultnull; acceptsmobileorlandline.additionalPropertiesonZTUseraccepts 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.shared.user?.build { user in
user.uid = "uid"
user.emailId = "[email protected]"
}
let user = ZTUser(uid: "john123", emailId: "[email protected]")
ZetaClient.shared.user?.updateUser(user)
[[ZetaClient shared].user build:^(ZTUser *user) {
user.uid = @"uid";
user.emailId = @"[email protected]";
}];
ZTUser *user = [[ZTUser alloc] initWithUid:@"john123" emailId:@"[email protected]"];
[[ZetaClient shared].user updateUser:user];
Note:
emailIdis ignored if theuidis also an email address.
Clear the identity session when the user changes inside your app:
ZetaClient.shared.user?.clear()
[[ZetaClient shared].user clear];
Note: Call
clear()whenever the user profile changes in your app (sign-out, account switch, etc.).
Passing IDFA, IDFV, and push tokens
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
ZetaClient.shared.user?.updateDeviceToken(token: deviceToken)
}
ZetaClient.shared.user?.updateIDFA(idfa)
ZetaClient.shared.user?.updateIDFV(idfv)
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[[ZetaClient shared].user updateDeviceTokenWithToken:deviceToken];
}
[[ZetaClient shared].user updateIDFA:idfa];
[[ZetaClient shared].user updateIDFV:idfv];
Location tracking
updateLocation(_:) accepts coordinates plus a foreground/background flag. The foreground/background flag indicates whether the location was collected with the app in the foreground or background. The provided location is cached in memory and attached to subsequent events as a property.
ZetaClient.shared.user?.updateLocation(
ZTLocation(
latitude: 12.933663251837913,
longitude: 77.62168405034637,
isForeground: true
)
)
ZTLocation *location = [[ZTLocation alloc]
initWithLatitude:12.933663251837913
longitude:77.62168405034637
isForeground:YES];
[[ZetaClient shared].user updateLocation:location];
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_idname:value pair. If a profile is updated with aunique_client_idmatching another profile, the profiles are merged. - A
unique_client_idpair 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.shared.user?.setUniqueClientId(value, forKey: name)
[[ZetaClient shared].user setUniqueClientId:value forKey:name];
Event tracking
Auto-tracked events
| Event | When fired |
|---|---|
app_installed | First launch only. |
app_opened | App transitions from background to foreground. |
app_closed | App transitions from foreground to background. |
app_terminated | App is closed. |
Screen name tracking
Use trackScreenName(screen:deeplink:properties:) to track screen navigation. The provided screen name is cached in memory and attached to subsequent events as a property.
screen— screen name.deeplink— optional. The deeplink URL that opened this screen.properties— optional. Additional properties.
ZetaClient.shared.event?.trackScreenName(
screen: "Events Screen",
deeplink: "app://home",
properties: ["screen": "Home"]
)
[[ZetaClient shared].event
trackScreenNameWithScreen:@"Events Screen"
deeplink:@"app://home"
properties:@{@"screen": @"Home"}];
Custom events
Send a custom event by passing a name and a dictionary of properties. Properties must be JSON-encodable; if any property value is not JSON-encodable, the entire event is discarded.
eventName— a meaningful name that describes the event.properties—[String: Any], JSON-encodable.
ZetaClient.shared.event?.send(
name: "EventTest",
properties: [
"events-array": ["screen1", "screen2"],
"events-dict": ["screen": "events"]
]
)
[[ZetaClient shared].event
sendWithName:@"EventTest"
properties:@{
@"events-array": @[@"screen1", @"screen2"],
@"events-dict": @{@"screen": @"events"}
}];
Next
- Push Notifications — device token, click tracking, deeplinks.
- In-App Messaging — foreground messages and email collection.
- App Inbox — a persistent, queryable message store.
- User Guide: User Properties — standard and custom properties in ZMP.
- User Guide: Identity Resolution — how profiles merge.
See also
- Platform support -- feature availability by platform and SDK version.
