> ## 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="IDFA Provider" href="#idfa-identity" icon="fingerprint" />
</CardGroup>

## Overview

<IdentityOverview />

In the iOS SDK, you can set aliases using the `setIdentities(aliases:)` method. The SDK uses a singleton pattern via `Permutive.shared`.

## 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 Alias">
    For apps with a single identifier type:

    <CodeGroup>
      ```swift Swift theme={"dark"}
      do {
          let alias = Alias(tag: "internal_id", identity: userId)
          try Permutive.shared.setIdentities(aliases: [alias])
      } catch {
          print("Failed to set identity: \(error)")
      }
      ```

      ```objectivec Objective-C theme={"dark"}
      NSError *error = nil;
      PermutiveAlias *alias = [[PermutiveAlias alloc]
          initWithTag:@"internal_id"
          identity:userId];

      [Permutive.shared setIdentitiesWithAliases:@[alias] error:&error];
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Multiple Aliases">
    For apps tracking multiple identifier types (email, user ID, etc.):

    <CodeGroup>
      ```swift Swift theme={"dark"}
      do {
          let aliases = [
              // Highest priority: hashed email
              Alias(tag: "email_sha256", identity: emailHash),
              // Medium priority: internal user ID
              Alias(tag: "internal_id", identity: userId, priority: 1),
              // Lower priority: with expiry date
              Alias(
                  tag: "session_id",
                  identity: sessionId,
                  priority: 2,
                  expiry: Date().addingTimeInterval(86400 * 30) // 30 days
              )
          ]
          try Permutive.shared.setIdentities(aliases: aliases)
      } catch {
          print("Failed to set identities: \(error)")
      }
      ```

      ```objectivec Objective-C theme={"dark"}
      NSError *error = nil;

      // Highest priority: hashed email
      PermutiveAlias *emailAlias = [[PermutiveAlias alloc]
          initWithTag:@"email_sha256"
          identity:emailHash];

      // Medium priority: internal user ID
      PermutiveAlias *idAlias = [[PermutiveAlias alloc]
          initWithTag:@"internal_id"
          identity:userId
          priority:1];

      // Lower priority: with expiry
      NSDate *expiry = [NSDate dateWithTimeIntervalSinceNow:86400 * 30];
      PermutiveAlias *sessionAlias = [[PermutiveAlias alloc]
          initWithTag:@"session_id"
          identity:sessionId
          priority:2
          expiry:expiry];

      [Permutive.shared setIdentitiesWithAliases:@[emailAlias, idAlias, sessionAlias]
                                           error:&error];
      ```
    </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">
    ```swift theme={"dark"}
    import CryptoKit

    func hashEmail(_ email: String) -> String {
        let normalized = email.trimmingCharacters(in: .whitespaces).lowercased()
        let data = Data(normalized.utf8)
        let hash = SHA256.hash(data: data)
        return hash.compactMap { String(format: "%02x", $0) }.joined()
    }

    // Usage
    let emailHash = hashEmail("user@example.com")
    let alias = Alias(tag: "email_sha256", identity: emailHash)
    try? Permutive.shared.setIdentities(aliases: [alias])
    ```
  </Tab>

  <Tab title="Incorrect - Plain Text">
    ```swift theme={"dark"}
    // DON'T DO THIS - sending PII
    let alias = Alias(tag: "email", identity: "user@example.com")  // 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               |
| Vendor identifier    | `idfv`                     | `UIDevice.identifierForVendor` |
| Customer ID          | `customer_id`              | E-commerce systems             |
| Subscriber ID        | `subscriber_id`            | Subscription services          |

### Reserved Tags

Some alias tags are reserved by the SDK and cannot be used:

* `appnexus`
* `amp`
* `gigya`
* `sailthru`
* `aaid`

Aliases with these tags will be ignored.

## IDFA Identity

<Info>
  **Permutive recommends against using IDFA** due to Apple's App Tracking Transparency requirements. Consider using `identifierForVendor` or hashed email addresses instead.
</Info>

If you do need IDFA, use the dedicated `setIdentityForIDFA` method:

```swift theme={"dark"}
import AdSupport
import AppTrackingTransparency
import Permutive_iOS

func setIDFAIdentity() {
    if #available(iOS 14, *) {
        ATTrackingManager.requestTrackingAuthorization { status in
            guard status == .authorized else { return }

            let idfa = ASIdentifierManager.shared().advertisingIdentifier
            do {
                try Permutive.shared.setIdentityForIDFA(idfa)
            } catch {
                // IDFA may be all zeros (tracking denied)
                print("Failed to set IDFA: \(error)")
            }
        }
    }
}
```

<Card title="IDFA Provider Guide" icon="fingerprint" href="/sdks/mobile/ios/integrations/idfa-provider">
  Complete IDFA integration documentation
</Card>

## Retrieving User ID

Get the current Permutive user ID:

<CodeGroup>
  ```swift Swift theme={"dark"}
  let userId = Permutive.shared.currentUserId
  print("Permutive User ID: \(userId)")
  ```

  ```objectivec Objective-C theme={"dark"}
  NSString *userId = [Permutive.shared currentUserId];
  NSLog(@"Permutive User ID: %@", userId);
  ```
</CodeGroup>

## Tracking User ID Changes

Use `TriggerAction` to react when the user ID changes:

<CodeGroup>
  ```swift Swift theme={"dark"}
  var userIdTrigger: TriggerAction?

  func watchUserIdChanges() {
      userIdTrigger = Permutive.shared.triggerProvider?.actionUpdateForUserIdentity { userId in
          print("User ID changed to: \(userId)")
      }
  }

  // Release when done
  deinit {
      userIdTrigger = nil
  }
  ```

  ```objectivec Objective-C theme={"dark"}
  @property (nonatomic, strong) PermutiveTriggerAction *userIdTrigger;

  - (void)watchUserIdChanges {
      self.userIdTrigger = [Permutive.shared.triggerProvider
          actionUpdateForUserIdentity:^(NSString *userId) {
              NSLog(@"User ID changed to: %@", userId);
          }];
  }
  ```
</CodeGroup>

## Common Patterns

<AccordionGroup>
  <Accordion title="Login Flow" icon="right-to-bracket">
    <CodeGroup>
      ```swift Swift theme={"dark"}
      func onLoginSuccess(userId: String, email: String) {
          let emailHash = hashEmail(email)

          do {
              let aliases = [
                  Alias(tag: "email_sha256", identity: emailHash),
                  Alias(tag: "internal_id", identity: userId, priority: 1)
              ]
              try Permutive.shared.setIdentities(aliases: aliases)
          } catch {
              print("Failed to set identity: \(error)")
          }
      }
      ```

      ```objectivec Objective-C theme={"dark"}
      - (void)onLoginSuccessWithUserId:(NSString *)userId email:(NSString *)email {
          NSString *emailHash = [self hashEmail:email];

          NSError *error = nil;
          PermutiveAlias *emailAlias = [[PermutiveAlias alloc]
              initWithTag:@"email_sha256"
              identity:emailHash];

          PermutiveAlias *idAlias = [[PermutiveAlias alloc]
              initWithTag:@"internal_id"
              identity:userId
              priority:1];

          [Permutive.shared setIdentitiesWithAliases:@[emailAlias, idAlias]
                                               error:&error];
      }
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Using Vendor Identifier" icon="apple">
    ```swift theme={"dark"}
    import UIKit
    import Permutive_iOS

    func setVendorIdentity() {
        guard let idfv = UIDevice.current.identifierForVendor?.uuidString else {
            return
        }

        let alias = Alias(tag: "idfv", identity: idfv, priority: 2)
        try? Permutive.shared.setIdentities(aliases: [alias])
    }
    ```
  </Accordion>

  <Accordion title="Guest to Logged-In Transition" icon="user-plus">
    ```swift theme={"dark"}
    class UserManager {
        // User starts as guest (anonymous)
        func onAppLaunch() {
            // SDK automatically creates anonymous ID
            // Optionally set vendor identifier
            setVendorIdentity()
        }

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

            // Permutive merges guest data with authenticated profile
            try? Permutive.shared.setIdentities(aliases: [
                Alias(tag: "email_sha256", identity: emailHash),
                Alias(tag: "internal_id", identity: userId, priority: 1)
            ])
        }
    }
    ```
  </Accordion>
</AccordionGroup>

## Expiry

Aliases can expire automatically, useful for GDPR compliance, session identifiers, and temporary access tokens.

```swift theme={"dark"}
// Never expire (default)
Alias(tag: "email_sha256", identity: emailHash)

// Expire in 30 days
let thirtyDaysFromNow = Date().addingTimeInterval(86400 * 30)
Alias(tag: "session_id", identity: sessionId, expiry: thirtyDaysFromNow)

// Expire at distant future (effectively never)
Alias(tag: "permanent_id", identity: id, expiry: Date.distantFuture)
```

## tvOS Considerations

<Info>
  **tvOS Note:** Identity management works identically on tvOS. However, IDFA and App Tracking Transparency are not available on tvOS. Use `identifierForVendor` or hashed email as primary identifiers.
</Info>

## Troubleshooting

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

    **Solutions:**

    * Check network connectivity
    * Verify the alias has been used in other sessions/devices
    * Enable debug logging: `options.logModes = LogMode.all`
    * Look for identity-related logs in the console
  </Accordion>

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

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

  <Accordion title="Reserved tag error">
    **Problem:** Alias with certain tags is ignored.

    **Solution:** Avoid reserved tags: `appnexus`, `amp`, `gigya`, `sailthru`, `aaid`. Use custom tags instead.
  </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
    * Use `identifierForVendor` as a fallback identifier
  </Tab>

  <Tab title="Don't">
    * Send unhashed email addresses or phone numbers
    * Use reserved tag names
    * Use generic tag names like "id1", "id2"
    * Set identity multiple times unnecessarily
    * Skip priority assignment when using multiple aliases
    * Rely on IDFA as your primary identifier
  </Tab>
</Tabs>

## Related Documentation

<CardGroup cols={2}>
  <Card title="IDFA Provider" icon="fingerprint" href="/sdks/mobile/ios/integrations/idfa-provider">
    Apple advertising identifier integration
  </Card>

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

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

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