One ID, set once, the moment sign-in is real
Crossdeck tracks an anonymous device on its own from the first page view. identify() is the one thing it can't do for you — which value is "the signed-in user" depends entirely on the auth provider you wired, so calling it is your job: one line, placed exactly once, at the moment your provider tells you the user is real.
That ID is the anchor. Every event, error, and entitlement attaches to it. Get it right and the record is coherent forever; get it wrong and it generally can't be repaired after the fact — Crossdeck records the identity you assert, it doesn't second-guess you.
Call identify right after sign-in
Inside your auth provider's "signed in" callback, mirror the user into Crossdeck with the stable account ID — the same string on every platform.
// In your auth provider's "signed in" callback.
await Crossdeck.identify("user_847", {
email: "[email protected]",
traits: { name: "Wes" },
});
// In your auth provider's "signed in" callback.
cd?.identify(
userId: "user_847",
email: "[email protected]",
traits: ["name": "Wes"]
)
Use the stable ID your auth provider issues — the Firebase uid, the Auth0 sub, your own user-table primary key. The same account is the same string on web and mobile. Don't use the email: Sign in with Apple's Private Relay hands your iOS app a different address than the web, so emails won't match across platforms. The email is a trait, not the identifier — and plan isn't a trait either; that's an entitlement the rail keeps current, so leave it out of traits.
The anonymous history merges in; reset clears it on logout
Behind the call, the SDK sends both IDs — the anonymous one it minted before login and your user_847 — to the identity graph, which resolves them to a single Crossdeck customer (cdcust_…) and caches it locally. The events captured before sign-in aren't lost: they merge onto the same person, so your funnels stay intact across the sign-up boundary.
On logout, call reset() on every platform. It's a clean client-side wipe — the cached customer is cleared, the user ID is dropped, and a fresh anonymous ID is minted so the next session starts its own identity. (Server-side the previous link is kept; reset is a wipe, not an unlink.)
// In your "signed out" callback, on every platform.
Crossdeck.reset();
// In your "signed out" callback, on every platform.
cd?.reset()
The one thing to get right: the same stable ID on every platform. If your iOS app calls identify() with a different ID than the web — or never calls it — the install stays anonymous. A customer who paid on the web opens the app, the entitlement check finds no human to attach to, and they're silently downgraded to free on the device they expected it on. It fails quietly in production, not at integration time.
One customer, every device
Open the customer in your Crossdeck dashboard. The anonymous device, the email, and your user ID collapse into one record — and the entitlement they bought anywhere now resolves on every device they sign in on.
Anonymous device + email + your user ID collapsed into one customer. The pre-sign-in events are kept — funnels intact across the boundary.