> For the complete documentation index, see [llms.txt](https://docs.hackle.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hackle.io/en/development-guide/ios/user-identifier.md).

# User Identifier & Properties

{% hint style="info" %}
User Identifier Management

User Identifiers are used to uniquely identify users. For information about the meaning and importance of User Identifiers, and how to choose them, refer to the [Manage User Identifiers](/en/getting-started/user-identifier.md) documentation.
{% endhint %}

{% hint style="warning" %}
For functions that change user information (`setUser`, `setUserId`, `setDeviceId`, `updateUserProperties`, `resetUser`, and so on), we recommend using the variants that take a completion handler or the async variants.

The completion handler is invoked after the changed user information has been applied to the SDK.
{% endhint %}

## User Identifier

### Identifiers Managed by the SDK

The iOS SDK includes functionality to manage the device's identifier. Therefore, users can be automatically identified without separately providing a User Identifier.

You can query the identifiers managed by the SDK as follows.

{% tabs %}
{% tab title="Swift" %}

```swift
// Get the device ID
let deviceId = hackleApp.deviceId

// Get the session ID
let sessionId = hackleApp.sessionId

// Get all user information
let user = hackleApp.user
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
// Get the device ID
NSString *deviceId = [hackleApp deviceId];

// Get the session ID
NSString *sessionId = [hackleApp sessionId];

// Get all user information
HackleUser *user = [hackleApp user];
```

{% endtab %}
{% endtabs %}

#### Modify Device ID

You can inject a custom device ID instead of using the device ID provided by Hackle.

{% tabs %}
{% tab title="Swift" %}

```swift
// Change the device ID
hackleApp.setDeviceId(deviceId: "CUSTOM_DEVICE_ID") {
    // Applied
}

await hackleApp.setDeviceId(deviceId: "CUSTOM_DEVICE_ID")

// Using the builder pattern
let user = User.builder()
    .deviceId("CUSTOM_DEVICE_ID") // Device ID
    .build()

hackleApp.setUser(user: user) {
    // Applied
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
// Change the device ID
[hackleApp setDeviceIdWithDeviceId:@"CUSTOM_DEVICE_ID" completion:^{
    // Applied
}];
```

{% endtab %}
{% endtabs %}

#### Set User Identifier (User ID)

You can set the identifier for a logged-in user.

{% tabs %}
{% tab title="Swift" %}

```swift
// Add the logged-in user ID
hackleApp.setUserId(userId: "LOGIN_ID") {
    // Applied
}

await hackleApp.setUserId(userId: "LOGIN_ID")

// Using the builder pattern
let user = User.builder()
    .userId("LOGIN_ID") // User ID
    .build()

hackleApp.setUser(user: user) {
    // Applied
}
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
// Add the logged-in user ID
[hackleApp setUserIdWithUserId:@"LOGIN_ID" completion:^{
    // Applied
}];
```

{% endtab %}
{% endtabs %}

### Additional Identifiers

You can add identifier types other than the default identifiers (deviceId, userId) as follows.

{% hint style="info" %}
Additional identifiers are not integrated with the [Hackle ID](/en/getting-started/user-identifier/hackle-id.md).
{% endhint %}

{% hint style="danger" %}
Calling `setUser` overwrites the current device's user information.

* If you are currently using userId A and call `setUser` without passing userId A, the userId changes from A to null.
* If you are currently using a custom deviceId and call `setUser` without passing the current deviceId, the custom deviceId reverts to the Hackle deviceId.
* If you use additional identifiers and do not pass them when calling `setUser`, the additional identifiers are reset.
* For properties, the cached properties on the device may be retained or reset in the following cases:
  * If the userId and deviceId are the same before and after `setUser`, cached properties are retained.
  * If the userId or deviceId changes before and after `setUser`, cached properties are deleted.
    {% endhint %}

{% tabs %}
{% tab title="Swift" %}

```swift
import Hackle

let user = User.builder()
    .userId("142")                  // User ID (Hackle ID can be used)
    .deviceId("ae2182e0")           // Device ID (Hackle ID can be used)
    .identifier("myCustomId", "42") // Custom ID
    .build()

hackleApp.setUser(user: user) {
    // Applied
}

await hackleApp.setUser(user: user)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
@import Hackle;

HackleUserBuilder *builder = [HackleUser builder];
[builder userId:@"142"];                   // User ID (Hackle ID can be used)
[builder deviceId:@"ae2182e0"];            // Device ID (Hackle ID can be used)
[builder identifier:@"myCustomId" :@"42"]; // Custom ID
HackleUser *user = [builder build];

[hackleApp setUserWithUser:user completion:^{
    // Applied
}];
```

{% endtab %}
{% endtabs %}

## User Property

The Hackle SDK supports adding user properties.

* Properties must be sent as key-value pairs (Property Key and Property Value).
* A maximum of 128 properties can be added.

<table><thead><tr><th width="133.04296875">Category</th><th width="127.60546875">Type</th><th>Constraints</th></tr></thead><tbody><tr><td>Property Key</td><td><code>string</code></td><td><ul><li>Character limit is 128 characters.</li><li>Case-insensitive.</li><li>For example, AGE and age are recognized as the same Property Key.</li></ul></td></tr><tr><td>Property Value</td><td><code>boolean</code>, <code>string</code>, <code>number</code>, <code>array</code></td><td><ul><li>For string type, the character limit is 1024 characters.</li><li>String type is case-sensitive.</li><li>For example, APPLE and apple are recognized as different Property Values.</li><li>For number type, up to 15 integer digits and up to 6 decimal places are supported.</li></ul></td></tr></tbody></table>

### Add User Property

You can add a user property simply by adding it with `set` on a `PropertyOperations` object and then calling `updateUserProperties`.

{% hint style="warning" %}
The `setUserProperty` function is deprecated as of iOS SDK 4.0.0. Use `updateUserProperties` instead.
{% endhint %}

{% tabs %}
{% tab title="Swift" %}

```swift
import Hackle

let operations = PropertyOperations.builder()
    .set("gender", "female")
    .build()

hackleApp.updateUserProperties(operations: operations) {
    // Applied
}

await hackleApp.updateUserProperties(operations: operations)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
@import Hackle;

PropertyOperationsBuilder *builder = [PropertyOperations builder];
[builder set:@"gender" :@"female"];
PropertyOperations *operations = [builder build];

[hackleApp updateUserPropertiesWithOperations:operations completion:^{
    // Applied
}];
```

{% endtab %}
{% endtabs %}

### Configure User Properties

You can add or remove user properties.

<table><thead><tr><th width="150">Supported Functions</th><th>Description</th></tr></thead><tbody><tr><td><code>set</code></td><td>Sets a User Property. If a Property Value already exists for the Property Key, it is overwritten.</td></tr><tr><td><code>setOnce</code></td><td><p>Sets a User Property value only once. If a property already exists for the Property Key, it is ignored.</p><p>For example, you can use this to set a user's registration date or initial sign-up location.</p></td></tr><tr><td><code>unset</code></td><td>Removes a User Property.</td></tr><tr><td><code>clearAll</code></td><td>Removes all User Properties.</td></tr></tbody></table>

Instantiate a `PropertyOperations` object with the user properties you want to configure. Then call `updateUserProperties` to update the user properties. You can configure multiple properties at once.

{% tabs %}
{% tab title="Swift" %}

```swift
import Hackle

let operations = PropertyOperations.builder()
    .set("age", 42)
    .set("grade", "GOLD")
    .setOnce("sign_up_date", "2020-07-03")
    .build()

hackleApp.updateUserProperties(operations: operations) {
    // Applied
}

await hackleApp.updateUserProperties(operations: operations)
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
@import Hackle;

PropertyOperationsBuilder *builder = [PropertyOperations builder];
[builder set:@"age" :@42];
[builder set:@"grade": @"GOLD"];
[builder setOnce:@"sign_up_date" :@"2020-07-03"];
PropertyOperations *operations = [builder build];

[hackleApp updateUserPropertiesWithOperations:operations completion:^{
    // Applied
}];
```

{% endtab %}
{% endtabs %}

## Reset User

You need to reset the previously configured information. When reset, all previously configured identifiers and properties are cleared.

{% hint style="danger" %}
Resetting the user also clears all user properties stored on the server. If you want to handle logout, use `hackleApp.setUserId(userId: nil)`.

Setting null to userId handles logout on the client side.
{% endhint %}

{% tabs %}
{% tab title="Swift" %}

```swift
hackleApp.resetUser {
    // Applied
}

await hackleApp.resetUser()
```

{% endtab %}

{% tab title="Objective-C" %}

```objectivec
[hackleApp resetUserWithCompletion:^{
    // Applied
}];
```

{% endtab %}
{% endtabs %}

Calling `resetUser()` clears all previously configured identifiers and properties.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.hackle.io/en/development-guide/ios/user-identifier.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
