Identity and contacts
How an anonymous visitor becomes one contact across devices.
A contact is one person in your audience. Every event belongs to a contact, even before you know who they are.
Anonymous first
On the first visit, the SDK creates an anonymous ID and stores it. On
the web it also writes a first-party cookie on your registrable domain,
so www.example.com and app.example.com stay one visitor with one
attribution chain. Until you identify them, the contact is a guest.
Identify with your own ID
Call identify when someone signs in or signs up. Pass the stable user
ID from your database.
founderhq.identify("user_8421", { email: "jane@acme.com" });FounderHQ then merges the guest's history into that contact. The pageviews and events from before the sign-up stay attached, which is what makes attribution work.
Rules worth knowing:
- One external ID per contact. Use the same ID in your browser SDK, your mobile SDK, and the Node SDK.
- Never pass an email, a session ID, or a random value as the ID.
- Placeholder values are rejected:
anonymous,guest,id,null,undefined,none,nil,nan,[object Object], and empty strings. - If that browser was already identified as a different person, FounderHQ does not merge the two. It starts a fresh anonymous identity instead.
- Call
reset()on sign-out, so the next person on a shared machine starts clean. - Calling
identifyagain for the same person is safe. Do it on every page load if you like. Only the first call records an identification; later calls with new properties become a property update, and calls with nothing new send nothing.
Properties on the person
identify accepts properties. You can also set them later.
founderhq.setPersonProperties({ plan: "growth" }, { signup_source: "podcast" });The first argument overwrites. The second is set once and never overwritten, which is how you keep first-touch facts honest. FounderHQ does this for captured facts too: it stores both the latest value and the initial value of things like the campaign, the browser, and the country.
By default (person_profiles: "identified_only") property changes made
before identify wait on the device and travel with the identify call,
so you never create profiles for people you do not know. Set
person_profiles: "always" to profile guests too, or "never" to
stitch identity without writing person properties.
Properties FounderHQ understands
Any property is stored and shown on the contact. These names also fill the contact's own fields:
| Property | Contact field |
|---|---|
email | Email, used to match contacts |
phone | Phone, used to match contacts |
name | Split on the first space into first and last name |
firstName / first_name, lastName / last_name | First and last name; these win over name |
avatarUrl | Photo on the contact |
timezone | Time zone |
locale | Locale |
founderhq.identify("user_8421", {
email: "jane@acme.com",
name: "Jane Cooper",
avatarUrl: "https://cdn.acme.com/avatars/jane.png",
});Properties on every event
Super properties ride along on every later event from that device.
founderhq.register({ workspace_tier: "growth" });
founderhq.registerOnce({ first_seen_variant: "b" });
founderhq.unregister("workspace_tier");From the server
Server events name the contact directly, by externalId, email, or
phone. Use the same external ID as the client and you keep one
contact.