# 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 %}

## 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
// 디바이스ID 가져오기
let deviceId = hackleApp.deviceId

// 세션 ID 가져오기
let sessionId = hackleApp.sessionId

// 사용자 정보 모두 가지고 오기
let user = hackleApp.user
```

{% endtab %}

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

```objectivec
// 디바이스ID 가져오기
NSString *deviceId = [hackleApp deviceId];

// 세션 ID 가져오기
NSString *sessionId = [hackleApp sessionId];

// 사용자 정보 모두 가지고 오기
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
// 디바이스 ID 변경
hackleApp.setDeviceId(deviceId: "CUSTOM_DEVICE_ID")

// 빌더 패턴 사용
let user = User.builder()
    .deviceId("CUSTOM_DEVICE_ID") // 디바이스 ID
    .build()

hackleApp.setUser(user: user)
```

{% endtab %}

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

```objectivec
// 디바이스 ID 변경
[hackleApp setDeviceIdWithDeviceId:@"CUSTOM_DEVICE_ID"];
```

{% endtab %}
{% endtabs %}

#### Set User Identifier (User ID)

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

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

```swift
// 로그인 한 사용자 ID 추가
hackleApp.setUserId(userId: "LOGIN_ID")

// 빌더 패턴 사용
let user = User.builder()
    .userId("LOGIN_ID") // 사용자 ID
    .build()

hackleApp.setUser(user: user)
```

{% endtab %}

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

```objectivec
// 로그인 한 사용자 ID 추가
[hackleApp setUserIdWithUserId:@"LOGIN_ID"];
```

{% 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")                  // 사용자 ID (핵클 통합 식별자 사용가능)
    .deviceId("ae2182e0")           // 디바이스 ID (핵클 통합 식별자 사용가능)
    .identifier("myCustomId", "42") // Custom ID
    .build()

hackleApp.setUser(user: user)
```

{% endtab %}

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

```objectivec
@import Hackle;

HackleUserBuilder *builder = [HackleUser builder];
[builder userId:@"142"];                   // 사용자 ID (핵클 통합 식별자 사용가능)
[builder deviceId:@"ae2182e0"];            // 디바이스 ID (핵클 통합 식별자 사용가능)
[builder identifier:@"myCustomId" :@"42"]; // Custom ID
HackleUser *user = [builder build];

[hackleApp setUserWithUser:user];
```

{% 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. Calling the function below works the same as adding a property using `set` in a `PropertyOperations` object.

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

```swift
import Hackle

hackleApp.setUserProperty(key: "gender", value: "female")
```

{% endtab %}

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

```objectivec
@import Hackle;

[hackleApp setUserPropertyWithKey:@"gender" value:@"female"];
```

{% 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)
```

{% 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];
```

{% 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()
```

{% endtab %}

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

```objectivec
[hackleApp resetUser];
```

{% endtab %}
{% endtabs %}

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


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

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

The question should be specific, self-contained, and written in natural language.
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.
