Skip to content

Identity

IdentifiableUserService tells every vendor who the user is at sign-in, so what's collected from then on belongs to that user, and forgets them at sign-out.

class AnalyticsIdentity(private val identity: IdentifiableUserService) {

    suspend fun onSignedIn(userId: String) = identity.identify(Identity(userId))

    suspend fun onSignedOut() = identity.reset()

    /** At every cold start: some vendors do not remember the user between launches. */
    suspend fun restore(session: Session) {
        session.userId?.let { identity.identify(Identity(it)) }
    }
}
final class AnalyticsIdentity {
    private let identity: any IdentifiableUserService

    init(identity: any IdentifiableUserService) {
        self.identity = identity
    }

    func onSignedIn(userId: String) {
        identity.identify(Identity(userId: userId))
    }

    func onSignedOut() {
        identity.reset()
    }

    /// Call it at every app start: some vendors forget the user between launches.
    func restore(session: any Session) {
        if let userId = session.userId {
            identity.identify(Identity(userId: userId))
        }
    }
}
class AnalyticsIdentity(final IdentifiableUserService identity) {
  Future<void> onSignedIn(String userId) => identity.identify(Identity(userId));

  Future<void> onSignedOut() => identity.reset();

  /// Call it at every app start: some vendors forget the user between launches.
  Future<void> restore(Session session) async {
    if (session.userId case final userId?) await identity.identify(Identity(userId));
  }
}
export class AnalyticsIdentity {
  constructor(private readonly identity: IdentifiableUserService) {}

  onSignedIn(userId: string): Promise<void> {
    return this.identity.identify(new Identity(userId));
  }

  onSignedOut(): Promise<void> {
    return this.identity.reset();
  }

  /** Call it at every app start: some vendors forget the user between launches. */
  async restore(session: Session): Promise<void> {
    if (session.userId !== undefined) await this.identity.identify(new Identity(session.userId));
  }
}

Identity.userId uses the name every vendor uses. Pass an id that doesn't change and doesn't reveal who the person is, such as your backend's account id, never an email address or a phone number.

What each vendor does

Vendor identify reset
Firebase setUserId(userId) setUserId(null)
Mixpanel identify(userId, true) reset(): a new anonymous id
Adjust a user_id global callback parameter; the key is configurable removes that parameter
AppsFlyer setCustomerUserId(userId) setCustomerUserId(null); nothing on Flutter and React Native, whose packages can't clear it
Amplitude setUserId(userId) reset(): clears the user and rotates the device id

If your app must not send a user id to a vendor, register that vendor's provider without identity.

Every cold start

Not every vendor remembers the user. AppsFlyer 7 forgets the user id between launches, so a signed-in user who reopens the app would be anonymous there. At every start-up, identify a signed-in user again, as restore above does.

The order matters for AppsFlyer. It attaches the user id to the launch it sends when it starts, and with Herald that happens when consent is re-applied. So identify the user before re-applying consent:

  1. start()
  2. identify(...), if a user is signed in
  3. setEnabled(storedDecision)