> For the complete documentation index, see [llms.txt](https://docs.amply.tools/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.amply.tools/developer-guide/user-attributes.md).

# User attributes

This page covers two related but distinct jobs: telling Amply **who the user is** (an identifier from your backend), and telling Amply **what you know about them** (arbitrary key/value traits).

A PM should read this as: "the developer sets a user ID once the person signs in, and sets custom properties whenever a relevant fact changes (subscription tier, plan, region, preference)."

**Use this when** you want campaigns to target specific users or cohorts, or when you need the same user's data to follow them across sessions and devices. **Don't use this when** you want to record something that just happened — that's an event (see [Tracking events](/developer-guide/tracking-events.md)).

## User ID vs custom properties

The two concepts look similar but behave differently.

|             | User ID                             | Custom properties                |
| ----------- | ----------------------------------- | -------------------------------- |
| Purpose     | Identify the person across sessions | Describe traits about the person |
| Value       | A single string (your backend ID)   | Many key/value pairs             |
| When to set | On sign-in; clear on sign-out       | Any time a fact changes          |
| Example     | `"user_7391"`                       | `{ tier: "pro", region: "EU" }`  |

Set the user ID once per session when authentication happens. Set custom properties whenever the underlying data changes — there's no need to re-send the same values on every launch.

## Setting the user ID

Pass your stable internal identifier. On sign-out, pass `null` to clear it.

{% tabs %}
{% tab title="iOS (Swift)" %}

```swift
amply.setUserId("user_7391")

// On sign-out
amply.setUserId(nil)
```

{% endtab %}

{% tab title="Android (Kotlin)" %}

```kotlin
amply.setUserId("user_7391")

// On sign-out
amply.setUserId(null)
```

{% endtab %}

{% tab title="React Native (TS)" %}

```ts
import Amply from '@amplytools/react-native-amply-sdk';

Amply.setUserId('user_7391');

// On sign-out
Amply.setUserId(null);
```

{% endtab %}
{% endtabs %}

Do not use the user ID for PII (email, name, phone). Use an opaque identifier from your backend.

## Setting custom properties

Custom properties are batched and persisted by the SDK. The SDK will attach them to every event and make them available to campaign targeting rules.

### Set one property

{% tabs %}
{% tab title="iOS (Swift)" %}

```swift
amply.setCustomProperty(key: "tier", value: "pro")
```

{% endtab %}

{% tab title="Android (Kotlin)" %}

```kotlin
amply.setCustomProperty("tier", "pro")
```

{% endtab %}

{% tab title="React Native (TS)" %}

```ts
Amply.setCustomProperty('tier', 'pro');
```

{% endtab %}
{% endtabs %}

### Set many at once (preferred for multiple updates)

{% tabs %}
{% tab title="iOS (Swift)" %}

```swift
amply.setCustomProperties(properties: [
    "tier": "pro",
    "region": "EU",
    "trial_days_remaining": 5
])
```

{% endtab %}

{% tab title="Android (Kotlin)" %}

```kotlin
amply.setCustomProperties(mapOf(
    "tier" to "pro",
    "region" to "EU",
    "trial_days_remaining" to 5
))
```

{% endtab %}

{% tab title="React Native (TS)" %}

```ts
Amply.setCustomProperties({
  tier: 'pro',
  region: 'EU',
  trial_days_remaining: 5,
});
```

{% endtab %}
{% endtabs %}

### Read a property

{% tabs %}
{% tab title="iOS (Swift)" %}

```swift
Task {
    let tier = try await amply.getCustomProperty(key: "tier")
    print("tier: \(tier ?? "none")")
}
```

{% endtab %}

{% tab title="Android (Kotlin)" %}

```kotlin
lifecycleScope.launch {
    val tier = amply.getCustomProperty("tier")
    Log.d("App", "tier: $tier")
}
```

{% endtab %}

{% tab title="React Native (TS)" %}

```ts
const tier = await Amply.getCustomProperty('tier');
console.log('tier:', tier);
```

{% endtab %}
{% endtabs %}

### Remove a property or clear everything

{% tabs %}
{% tab title="iOS (Swift)" %}

```swift
amply.removeCustomProperty(key: "trial_days_remaining")
amply.clearCustomProperties()
```

{% endtab %}

{% tab title="Android (Kotlin)" %}

```kotlin
amply.removeCustomProperty("trial_days_remaining")
amply.clearCustomProperties()
```

{% endtab %}

{% tab title="React Native (TS)" %}

```ts
Amply.removeCustomProperty('trial_days_remaining');
Amply.clearCustomProperties();
```

{% endtab %}
{% endtabs %}

## Accepted value types

| Platform         | Accepted custom property value types                                             |
| ---------------- | -------------------------------------------------------------------------------- |
| iOS (Swift)      | `String`, `Int`, `Int64`, `Float`, `Double`, `Bool`, `Date` (or `DateTimeValue`) |
| Android (Kotlin) | `String`, `Int`, `Long`, `Float`, `Double`, `Boolean`, `DateTimeValue`           |
| React Native     | `string`, `number`, `boolean`                                                    |

Keys are strings up to 255 characters. Pick short, stable keys.

## Batching — don't call in a tight loop

Writes go through a persisted store. Calling `setCustomProperty` a hundred times in a loop will work, but it's wasteful — use `setCustomProperties` with a single map instead.

Bad:

```ts
for (const [key, value] of Object.entries(profile)) {
  Amply.setCustomProperty(key, value); // 50 writes
}
```

Good:

```ts
Amply.setCustomProperties(profile); // 1 batched write
```

## What the dashboard sees

Once set, custom properties are available to campaign targeting (`Users where tier is pro and region is EU`) and appear in the user's profile view. Because properties persist on-device and sync to the backend, they survive app restarts.

## Related

* [Tracking events](/developer-guide/tracking-events.md) — one-off actions vs persistent traits
* [Handling deeplinks](/developer-guide/handling-deeplinks.md) — routing campaigns after they match a user
* [Concepts — User attributes](/concepts/user-attributes.md) — how Amply ties a device to a person
* [iOS SDK reference](/reference/sdk-ios.md) — exact signatures
* [Android SDK reference](/reference/sdk-android.md) — exact signatures
* [React Native SDK reference](/reference/sdk-react-native.md) — exact signatures


---

# 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 dynamically by asking a question.

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

```
GET https://docs.amply.tools/developer-guide/user-attributes.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.
