> ## Documentation Index
> Fetch the complete documentation index at: https://docs.permutive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Identity Management

> Track users across sessions, devices, and platforms with aliases

export const IdentityPriority = () => <>
    <p>Priority determines which identifier is used for identity resolution:</p>
    <ul>
      <li><strong>Lower number = Higher priority</strong> (0 is the highest)</li>
      <li>Identifiers are resolved in priority order</li>
      <li>If the highest priority identifier resolves to a user, that identity is used</li>
    </ul>
    <pre><code>{`Priority 0 (Highest): Hashed email - Most reliable, persistent
Priority 1: Internal user ID - Reliable when user is logged in
Priority 2: Advertising ID - Less reliable, can be reset
Priority 3 (Lowest): Device ID - Least reliable`}</code></pre>
  </>;

export const IdentityResolution = () => <>
    <p>When you set an identifier:</p>
    <ol>
      <li>SDK sends the identifier to Permutive servers</li>
      <li>Server checks if this identifier is associated with an existing user</li>
      <li>If found, user profiles are merged</li>
      <li>SDK receives updated cohorts and state</li>
      <li>All future events are linked to the resolved identity</li>
    </ol>
  </>;

export const AliasDefinition = () => <>
    <p>An <strong>identifier</strong> (formerly called an <strong>alias</strong> in some SDK and API references) is an alternative identity for a user. Each identifier has:</p>
    <ul>
      <li><strong>Tag</strong> - The type of identifier (e.g., "email_sha256", "internal_id", "aaid")</li>
      <li><strong>Identity</strong> - The actual identifier value</li>
      <li><strong>Priority</strong> - Ordering when multiple identifiers exist (lower number = higher priority)</li>
      <li><strong>Expiry</strong> - Optional expiration date/time</li>
    </ul>
  </>;

export const IdentityOverview = () => <>
    <p>A user on a device is automatically allocated a unique device ID by the Permutive SDK on behalf of the publisher. This <strong>user ID</strong> is distinct across publishers, such that the same user who visits two different publishers' sites on their device will be assigned distinct IDs. As a first-party identity, it does not track users across domains or devices, and it has no reliance on third-party identifiers like cookies or mobile device IDs. The user ID is used in Permutive's cloud to generate accurate publisher-level audience insights, and on-device to store cohort information across sessions.</p>
    <p>It is also possible to assign users to other IDs, called <strong>identifiers</strong>, such as an email address the user has authenticated with on the publisher's site, or a third-party identity provided by a partner that the publisher has obtained user consent for. Identifiers can be used to unify the view of a user across multiple devices they use (such as segmenting a user based on their behavior on two different sites owned by the publisher which they are logged in to) or to connect auxiliary data about the user (such as augmenting the segmentation of users with a third-party audience that a partner provides information about).</p>
  </>;

Identity management allows you to track users across different sessions, devices, and platforms by associating multiple identifiers (aliases) with a single user profile.

<CardGroup cols={3}>
  <Card title="Single Identity" href="#setting-identity" icon="user" />

  <Card title="Multiple Identities" href="#multiple-identities" icon="users" />

  <Card title="AAID Provider" href="#automatic-identity-providers" icon="fingerprint" />
</CardGroup>

## Overview

<IdentityOverview />

In the Android SDK, you can set aliases using the `setIdentity()` method or configure automatic identity providers like AAID at initialization.

## Key Concepts

<AccordionGroup>
  <Accordion title="Alias" icon="tag">
    <AliasDefinition />
  </Accordion>

  <Accordion title="Identity Resolution" icon="arrows-rotate">
    <IdentityResolution />
  </Accordion>

  <Accordion title="Priority System" icon="arrow-down-1-9">
    <IdentityPriority />
  </Accordion>
</AccordionGroup>

## Setting Identity

<Tabs>
  <Tab title="Single Identity">
    For apps with only one type of user identifier:

    <CodeGroup>
      ```kotlin Kotlin theme={"dark"}
      // Set identity when user logs in
      fun onUserLoggedIn(userId: String) {
          permutive.setIdentity(userId)
      }
      ```

      ```java Java theme={"dark"}
      // Set identity when user logs in
      public void onUserLoggedIn(String userId) {
          permutive.setIdentity(userId);
      }
      ```
    </CodeGroup>

    <Tip>
      When using the single-parameter `setIdentity()`, the alias tag is automatically set to `"default"`.
    </Tip>

    ### With Priority and Expiry

    <CodeGroup>
      ```kotlin Kotlin theme={"dark"}
      fun onUserLoggedIn(userId: String) {
          val expiryDate = Calendar.getInstance().apply {
              add(Calendar.YEAR, 1)  // Expire in 1 year
          }.time

          permutive.setIdentity(
              identity = userId,
              priority = 0,  // Highest priority
              expiry = expiryDate
          )
      }
      ```

      ```java Java theme={"dark"}
      public void onUserLoggedIn(String userId) {
          Calendar calendar = Calendar.getInstance();
          calendar.add(Calendar.YEAR, 1);
          Date expiryDate = calendar.getTime();

          permutive.setIdentity(userId, 0, expiryDate);
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Multiple Identities">
    For apps tracking multiple types of identifiers (email, internal ID, ad ID, etc.):

    <CodeGroup>
      ```kotlin Kotlin theme={"dark"}
      import com.permutive.android.Alias

      fun setupUserIdentities(userId: String, emailHash: String, adId: String?) {
          val aliases = buildList {
              // Highest priority: hashed email (never expires)
              add(Alias.create(
                  tag = "email_sha256",
                  identity = emailHash,
                  priority = 0
              ))

              // Medium priority: internal user ID (expires in 1 year)
              val oneYearLater = Calendar.getInstance().apply {
                  add(Calendar.YEAR, 1)
              }.time
              add(Alias.create(
                  tag = "internal_id",
                  identity = userId,
                  priority = 1,
                  expiry = oneYearLater
              ))

              // Lower priority: advertising ID (expires in 30 days)
              adId?.let { id ->
                  val thirtyDaysLater = Calendar.getInstance().apply {
                      add(Calendar.DAY_OF_YEAR, 30)
                  }.time
                  add(Alias.create(
                      tag = "ad_id",
                      identity = id,
                      priority = 2,
                      expiry = thirtyDaysLater
                  ))
              }
          }

          permutive.setIdentity(aliases)
      }
      ```

      ```java Java theme={"dark"}
      import com.permutive.android.Alias;

      public void setupUserIdentities(String userId, String emailHash, String adId) {
          List<Alias> aliases = new ArrayList<>();

          // Highest priority: hashed email
          aliases.add(Alias.create("email_sha256", emailHash, 0));

          // Medium priority: internal user ID
          Calendar oneYearLater = Calendar.getInstance();
          oneYearLater.add(Calendar.YEAR, 1);
          aliases.add(Alias.create("internal_id", userId, 1, oneYearLater.getTime()));

          // Lower priority: advertising ID
          if (adId != null) {
              Calendar thirtyDaysLater = Calendar.getInstance();
              thirtyDaysLater.add(Calendar.DAY_OF_YEAR, 30);
              aliases.add(Alias.create("ad_id", adId, 2, thirtyDaysLater.getTime()));
          }

          permutive.setIdentity(aliases);
      }
      ```
    </CodeGroup>
  </Tab>

  <Tab title="At Initialization">
    You can provide aliases when creating the Permutive instance:

    <CodeGroup>
      ```kotlin Kotlin theme={"dark"}
      val customAliases = listOf(
          Alias.create(
              tag = "email_sha256",
              identity = "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e",
              priority = 0
          ),
          Alias.create(
              tag = "internal_id",
              identity = "user_12345",
              priority = 1
          )
      )

      val permutive = Permutive(
          context = this,
          workspaceId = YOUR_WORKSPACE_ID,
          apiKey = YOUR_API_KEY,
          customAliases = customAliases
      )
      ```

      ```java Java theme={"dark"}
      Permutive permutive = new Permutive.Builder()
          .context(this)
          .workspaceId(YOUR_WORKSPACE_ID)
          .apiKey(YOUR_API_KEY)
          .customAlias(Alias.create("email_sha256", "f660ab912ec121d...", 0))
          .customAlias(Alias.create("internal_id", "user_12345", 1))
          .build();
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Security Best Practices

<Warning>
  **Always hash** personally identifiable information like email addresses before sending to Permutive.
</Warning>

<Tabs>
  <Tab title="Correct - Hashed">
    ```kotlin theme={"dark"}
    import java.security.MessageDigest

    fun hashEmail(email: String): String {
        val normalized = email.trim().lowercase()
        val bytes = MessageDigest.getInstance("SHA-256").digest(normalized.toByteArray())
        return bytes.joinToString("") { "%02x".format(it) }
    }

    // Usage
    val emailHash = hashEmail("user@example.com")
    permutive.setIdentity(
        listOf(Alias.create("email_sha256", emailHash, priority = 0))
    )
    ```
  </Tab>

  <Tab title="Incorrect - Plain Text">
    ```kotlin theme={"dark"}
    // DON'T DO THIS - sending PII
    permutive.setIdentity(
        listOf(Alias.create("email", "user@example.com", priority = 0))  // WRONG!
    )
    ```
  </Tab>
</Tabs>

### Standard Tag Names

| Identifier Type      | Recommended Tag            | Notes                 |
| -------------------- | -------------------------- | --------------------- |
| SHA-256 hashed email | `email_sha256`             | Most common           |
| Internal user ID     | `internal_id` or `user_id` | Your system's ID      |
| Advertising ID       | `aaid` (Android)           | Use AaidAliasProvider |
| Customer ID          | `customer_id`              | E-commerce systems    |
| Subscriber ID        | `subscriber_id`            | Subscription services |

## Automatic Identity Providers

### AAID (Android Advertising ID)

Use the Google Ads add-on for automatic AAID identification:

<Steps>
  <Step title="Add Dependency">
    ```kotlin theme={"dark"}
    dependencies {
        implementation("com.permutive.android:core:1.11.3")
        implementation("com.permutive.android:google-ads:2.2.0")
    }
    ```
  </Step>

  <Step title="Add Permission">
    In your `AndroidManifest.xml`:

    ```xml theme={"dark"}
    <manifest>
        <uses-permission android:name="com.google.android.gms.permission.AD_ID"/>
    </manifest>
    ```

    <Note>
      From Android API 31+, the AD\_ID permission is required to access the advertising ID.
    </Note>
  </Step>

  <Step title="Configure SDK">
    <CodeGroup>
      ```kotlin Kotlin theme={"dark"}
      import com.permutive.android.aaid.AaidAliasProvider

      val permutive = Permutive(
          context = this,
          workspaceId = YOUR_WORKSPACE_ID,
          apiKey = YOUR_API_KEY,
          aliasProviders = listOf(AaidAliasProvider(this))
      )
      ```

      ```java Java theme={"dark"}
      import com.permutive.android.aaid.AaidAliasProvider;

      Permutive permutive = new Permutive.Builder()
          .context(this)
          .workspaceId(YOUR_WORKSPACE_ID)
          .apiKey(YOUR_API_KEY)
          .aliasProvider(new AaidAliasProvider(this))
          .build();
      ```
    </CodeGroup>

    The AAID will be automatically retrieved and set with the tag `"aaid"`.
  </Step>
</Steps>

## Common Patterns

<AccordionGroup>
  <Accordion title="Login Flow" icon="right-to-bracket">
    ```kotlin theme={"dark"}
    class AuthActivity : AppCompatActivity() {

        private val permutive by lazy {
            (application as MyApplication).permutive
        }

        fun onLoginSuccess(userId: String, email: String) {
            val emailHash = hashEmail(email)

            val aliases = listOf(
                Alias.create("email_sha256", emailHash, priority = 0),
                Alias.create("internal_id", userId, priority = 1)
            )

            permutive.setIdentity(aliases)
            navigateToHome()
        }

        private fun hashEmail(email: String): String {
            val normalized = email.trim().lowercase()
            val bytes = MessageDigest.getInstance("SHA-256")
                .digest(normalized.toByteArray())
            return bytes.joinToString("") { "%02x".format(it) }
        }
    }
    ```
  </Accordion>

  <Accordion title="Logout Flow" icon="right-from-bracket">
    ```kotlin theme={"dark"}
    fun onLogout() {
        // Clear all persistent data
        lifecycleScope.launch(Dispatchers.IO) {
            permutive.clearPersistentData()
                .onSuccess {
                    withContext(Dispatchers.Main) {
                        navigateToLogin()
                    }
                }
                .onFailure { error ->
                    Log.e("Permutive", "Failed to clear data", error)
                }
        }
    }
    ```
  </Accordion>

  <Accordion title="Guest to Logged-In Transition" icon="user-plus">
    ```kotlin theme={"dark"}
    class UserManager(private val permutive: Permutive) {

        // User starts as guest (anonymous)
        fun onAppLaunch() {
            // SDK automatically creates anonymous ID
        }

        // User logs in or signs up
        fun onUserAuthenticated(userId: String, email: String) {
            val emailHash = hashEmail(email)

            // Permutive merges guest data with authenticated profile
            permutive.setIdentity(
                listOf(
                    Alias.create("email_sha256", emailHash, priority = 0),
                    Alias.create("internal_id", userId, priority = 1)
                )
            )
        }
    }
    ```
  </Accordion>
</AccordionGroup>

## Expiry

Aliases can expire automatically, useful for GDPR compliance, ad IDs, and session identifiers.

```kotlin theme={"dark"}
// Never expire (default)
Alias.create(tag = "email_sha256", identity = emailHash, expiry = Alias.NEVER_EXPIRE)

// Expire in 30 days
val expiry30Days = Calendar.getInstance().apply {
    add(Calendar.DAY_OF_YEAR, 30)
}.time
Alias.create(tag = "session_id", identity = sessionId, expiry = expiry30Days)
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Identity not resolving">
    **Problem:** Setting identity doesn't seem to merge user data.

    **Solutions:**

    * Check network connectivity
    * Verify alias has been used in other sessions/devices
    * Enable debug logging: `permutive.setDeveloperMode(true)`
    * Look for "Identified user with aliases" in logs
  </Accordion>

  <Accordion title="User identity split">
    **Problem:** Same user appears as two different users.

    **Solution:** Use consistent alias tags and values. When user logs in on multiple devices, use the same alias (e.g., hashed email).
  </Accordion>

  <Accordion title="PII concerns">
    **Problem:** Worried about sending personally identifiable information.

    **Solution:**

    * Always hash emails and other PII with SHA-256
    * Normalize data before hashing (lowercase, trim whitespace)
    * Never send raw email addresses, phone numbers, or names
  </Accordion>
</AccordionGroup>

## Best Practices

<Tabs>
  <Tab title="Do">
    * Hash PII (especially email addresses) before setting as identity
    * Use meaningful tag names that describe the identifier type
    * Set priorities based on reliability and persistence
    * Use expiry dates for temporary or less reliable identifiers
    * Set identity as early as possible in the user journey
    * Test identity resolution with debug logging enabled
  </Tab>

  <Tab title="Don't">
    * Send unhashed email addresses or phone numbers
    * Use generic tag names like "id1", "id2"
    * Set identity multiple times unnecessarily
    * Forget to handle logout scenarios
    * Hard-code identities (use dynamic values)
    * Skip priority assignment when using multiple aliases
  </Tab>
</Tabs>

## Related Documentation

<CardGroup cols={2}>
  <Card title="AAID Provider" icon="fingerprint" href="/sdks/mobile/android/integrations/aaid-provider">
    Automatic advertising ID tracking
  </Card>

  <Card title="Cohorts & Activations" icon="users" href="/sdks/mobile/android/core-concepts/cohorts-and-activations">
    Understanding user segments
  </Card>

  <Card title="Triggers Provider" icon="bell" href="/sdks/mobile/android/features/triggers-provider">
    React to cohort changes
  </Card>

  <Card title="Issues" icon="wrench" href="/sdks/mobile/android/troubleshooting/common-errors">
    Solutions to common issues
  </Card>
</CardGroup>
