> 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
