Identify people
Updated 2026-11-02
Why it matters
Tracking starts with an anonymous browser. Identifying someone links that browser, including its earlier visits, to a person. That's how a Stripe payment connects to the visits behind it. Call it at signup and sign-in.
In code
window.headstream?.identify({
email: "ada@example.com",
name: "Ada Lovelace",
company: "Analytical Engines",
});
These traits are saved:
| Trait | Notes |
|---|---|
email | The main way to match a person |
name | |
company | |
phone | |
stripeCustomerId | The most direct link to Stripe payments |
heard_about | See self-reported attribution, up to 500 characters |
Other traits are accepted, but aren't saved to the person.
From forms
You may not need any code. When a form submits, the script reads these fields and calls identify for you:
- Email: an input of type
email, or a name or ID containingemail - Phone: a name or ID containing
phone,mobileortel - Company: a name or ID containing
companyororganization - Name: a name or ID such as
name,full_nameorfirst_name heard_about: see the self-reported docs
Password fields, hidden fields, and fields with names such as card, cvv, ssn, secret or token are skipped.
Forms must fire a real submit event. A button that posts data with fetch and no form won't be read, so call identify yourself.
How matching works
Headstream looks for an existing person in this order: same email, same Stripe customer ID, then same browser.
Email outranks the browser. On a shared device, the browser moves to whoever signed in last.
When one person identifies on two devices with the same email, both browsers link to one person. Their visits then count together for attribution. Each browser still counts as a separate visitor in traffic reports.
See people
The Customers page lists paying people with revenue, highest first. Each person has a journey showing touches and payments in order. This also works through GET /api/v1/customers and the get_customer_journey MCP tool.
Erase a person
Under Project, use the Delete a person card. Or use the API:
curl -X POST https://headstream.app/api/v1/people/erase \
-H "Authorization: Bearer hsk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"siteId":"SITE_ID","email":"ada@example.com"}'
It returns { "erased": false } if no person has that email.