Identity resolution guide
How getuserfeedback.com stitches user activity across devices, sessions, and the login boundary.
- Last reviewed
Identity resolution stitches together user activity across devices, sessions, and the login boundary — so that a person who browses your app before signing up and then logs in on a different device is recognized as the same user.
This powers everything on the platform: targeting, personalization, behavioral segmentation, and response history all depend on knowing who you're talking to, even when the same person shows up with different identifiers at different times.
For the story behind why this matters, see the blog post.
How it works
Identity resolution decides which identifiers and activity belong to the same profile. It does not prove that an identifier belongs to the person using your app. Use Identity verification when widget requests should require a valid signed token and identity values matching configured token claims should be marked as verified.
- You send identifiers. When you call
identify(), you send one or more identifiers — a user ID, email, phone number, device ID, or any combination. - We match. getuserfeedback.com checks whether any incoming identifier already belongs to an existing user profile. Matching is deterministic — exact type and value after normalization.
- We merge. If the incoming identifiers match more than one existing profile, those profiles are merged into one. All history moves to the merged profile.
- The profile grows. Each new interaction can add identifiers. Over time, a single profile accumulates every identifier the user has ever been seen with.
Supported identifier types
| Type | Example | Priority |
|---|---|---|
| User ID | user_123 | Highest |
jane@example.com | High | |
| Phone | +1234567890 | High |
| Device ID | device_abc | Medium |
| Advertising ID | ad_xyz | Medium |
| Device token | token_abc | Medium |
| External IDs | shopify_customer_id | Configurable |
You don't need to send all of these. Send what you have. Most teams start with a user ID and an email and that's enough.
Each source maps its fields to identifier types. Check the source's integration guide for its mapping.
Use Segment-compatible externalIds for identifiers that are specific to your
business or a connected system, such as Shopify customer IDs or Salesforce
contact IDs.
await client.identify("user_123", { email: "jane@example.com" }, {externalIds: [{id: "gid://shopify/Customer/123",type: "shopify_customer_id",collection: "users",encoding: "none",},],});The React Native SDK uses the same identify() call from
useGetUserFeedback():
import { useEffect } from "react";import { useGetUserFeedback } from "@getuserfeedback/react-native";function IdentifyUser({ user }: { user: { id: string; email: string } }) {const client = useGetUserFeedback();useEffect(() => {async function identifyUser() {try {await client.identify(user.id, { email: user.email });} catch (error) {console.error("Unable to identify user", error);}}void identifyUser();}, [client, user.email, user.id]);return null;}Call and await client.reset() from your auth provider's authoritative logout
handler before another user can enter the same provider tree. Do not infer
logout from an initial null render.
External IDs help match profiles, but they are not traits by themselves. If you also want to target or segment by a value, send it as a trait too.
Where identifiers come from
Every install path and every connected integration feeds the same resolution graph. You don't have to standardize the source — send what you have, from wherever you have it.
- SDKs and Web pages — the JavaScript SDK,
React SDK,
React Native SDK,
iframe, and Web pages
all pass identifiers via
identify()or URL parameters. - GTM — the Google Tag Manager template pulls common identifiers from your data layer automatically, or lets you map fields explicitly.
- Segment as a source — every
identifyandtrackevent you forward from Segment carries identifiers into the same graph. See Segment as a source. - Mixpanel cohorts — cohort sync runs include each member's distinct ID and configured profile fields. See Mixpanel cohorts as a source.
- API — server-to-server callers can pass identifiers on every request. See the API overview.
Intake guardrails
Identity intake applies per-type guardrails to keep profiles stable and to prevent noisy or incorrect identifiers from accumulating indefinitely.
These are the default guardrails for each identifier type. Workspace admins can change their limits and priorities; your saved settings take precedence over these defaults.
| Identifier type | Default guardrail |
|---|---|
| User ID | 1 ever |
| Mixpanel distinct ID | 1 ever |
5 per year | |
| Phone | 5 per year |
| Device ID | 5 per year |
| Advertising ID | 5 per week |
| Device token | 5 per week |
| Anonymous ID | 5 per week |
| External IDs | 8 per week |
When more identifiers arrive than fit within these guardrails, lower-priority identifiers are ignored first.
Placeholder values such as anonymous, <email>, or <user_id> are filtered
automatically before matching.
Changing identity rules
Workspace admins can change identifier limits and priorities in Settings → Identity resolution. Choose Edit, make your changes, and select Save changes. By default, the new rules apply to subsequent processing. Existing profiles aren't rebuilt.
To also update existing data, select Reprocess existing data and pick a start date. Then select Save draft. The draft calculates a preview while your current rules and profiles stay in use. Once it's ready, open Review and select Start rollout to apply it. Saving a draft doesn't apply it.
An existing historical draft keeps its reprocessing scope when you edit it; it can't be converted into a forward-only save by removing reprocessing.
If another admin changes the rules or integration requirements while you're editing, saving is refused. Refresh the page and make your changes against the current settings.
Identifiers required by integrations
Creating a Mixpanel cohort integration automatically adds its required identifier if it's missing. Your existing limits and priorities are preserved; historical reprocessing isn't started.
You can tune a required identifier, but you can't remove it while an integration uses it. Paused integrations still reserve their identifiers. Deleting an integration releases its requirement, but doesn't delete the rule. If another integration uses the same identifier, it stays required.
How matching works
When an event arrives with identifiers, the system:
- Normalizes each identifier (lowercased email, trimmed whitespace, etc.).
- Searches for existing profiles that share any
(type, value)pair. - Only considers active, non-merged profiles.
This is purely deterministic. No probabilistic models, no fingerprinting, no third-party data. Only first-party identifiers you explicitly send.
How merging works
When identifiers match more than one existing profile, the system merges them:
- Pick the destination. Profiles are ranked by: number of shared identifiers (more wins), identifier type priority (higher priority wins), then age of the earliest identity (oldest wins).
- Merge into the destination. All other matched profiles are folded in. Their identifiers are moved to the destination profile.
- Move history. Responses, trait assignments, and targeting state move to the merged profile. Nothing is lost.
- Mark sources. The source profiles are marked as merged and won't match future events.
Pre-login and post-login continuity
A common pattern: a user interacts with your app before logging in, then creates an account or signs in. Without identity resolution, that's two separate profiles with separate history.
With identity resolution, when the user logs in and you call identify() with
their user ID, the system links their pre-login activity to their post-login
profile. Their earlier interactions — flow views, responses, targeting
state — are all connected to the right person.
If that user ID should be marked as verified, put it in a token claim mapped to
userId and enable
Identity verification. Resolution
matches identifiers to profiles; verification distinguishes values asserted by
the signed token from other declared identity data.
This works across devices too. If the same user logs in on a different device, a different browser, or a different session, their activity is linked to the same profile as long as they share at least one identifier.
Correcting mistaken matches
If incorrect identity rules have merged unrelated users, correct the rules and choose historical reprocessing to build a preview using those rules. Review the preview before starting rollout.
Deleting an integration is not a promise to restore every profile to an earlier state. It also doesn't delete the identifier's rule. Treat changes to incoming data and historical reprocessing as separate decisions.
What resolution powers
- Targeting — rules like "show this survey to Pro users who haven't responded" work correctly across sessions and devices.
- Response history — responses from pre-login and post-login sessions are connected. You won't accidentally re-survey someone.
- Behavioral segmentation — segments reflect the full picture, not just one session or one device.
Normalization
Identifiers are normalized before matching:
- Emails are lowercased and trimmed.
- Phone numbers are trimmed.
- All string values are trimmed of leading/trailing whitespace.
- Placeholder values like
<user_id>,<email>,0are filtered out automatically.
Examples
These examples show how identity resolution plays out in common scenarios.
New user signs up
- A visitor lands on your site. The widget assigns them a session identifier.
- They browse a few pages, see a survey, and submit a response.
- They sign up. Your app calls
identify("user_456", { email: "jane@example.com" }). - The system links the session identifier,
user_456, andjane@example.cominto one profile. The earlier response is now attached to Jane.
Same user, different device
- Jane is already identified as
user_456on her laptop. - She logs in on her phone. Different device, different session — but same
user_456. - The new session identifier is added to her existing profile. One person, one profile, every device.