# User Identifier & Properties

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

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

## User Identifier

### Default Identifiers Provided by Hackle

The Flutter SDK includes functionality to manage device identifiers. Therefore, users can be automatically identified even without providing a User Identifier separately.

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

```dart
import "package:hackle/hackle.dart";

// Get the device identifier managed internally
String deviceId = await HackleApp.getDeviceId();

// Get all previously configured user information
HackleUser user = await HackleApp.getUser();
```

#### Modify Device ID

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

```dart
import "package:hackle/hackle.dart";

// Change device identifier
await HackleApp.setDeviceId("CUSTOM_DEVICE_ID");
```

#### Set User Identifier (User ID)

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

```dart
import "package:hackle/hackle.dart";

// User identifier
await HackleApp.setUserId("LOGIN_ID");
```

### Additional Identifiers

If you need identifier types beyond the default identifiers (deviceId, userId), you can configure them as shown below.

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

{% hint style="danger" %}
Using `setUser` overwrites the user information on the current device.

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

```dart
import "package:hackle/hackle.dart";

HackleUser user = HackleUser.builder()
	.userId("LOGIN_ID") // User ID (Hackle ID compatible)
	.deviceId("CUSTOM_DEVICE_ID") // Device ID (Hackle ID compatible)
	.identifier("myCustomId", "CUSTOM_IDENTIFIER") // Custom ID
	.build();

await HackleApp.setUser(user);
```

## User Property

The Hackle SDK supports adding User Properties.

* A property must be sent as a key-value pair consisting of a Property Key and a Property Value.
* You can add a maximum of 128 properties.

<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 easily add a User Property. Calling the function below works identically to adding a property using `set` in a `PropertyOperations` object.

```dart
import "package:hackle/hackle.dart";

await HackleApp.setUserProperty("age", 30);
await HackleApp.setUserProperty("grade", "GOLD");
await HackleApp.setUserProperty("is_paying_user", false);
```

### 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.

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

await HackleApp.updateUserProperties(operations);
```

## Reset User

You need to reset 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(null);`.

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

```dart
import "package:hackle/hackle.dart";

await HackleApp.resetUser();
```


---

# 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/flutter/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.
