Identify users
POST /api/v1/ingest/identify: link a visitor to a user id with traits, including the email used to link payments.
POST https://pilotfox.app/api/v1/ingest/identifyTells PilotFox that a visitor is one of your users: their sessions, before and after, then count for that user in the
Users report, user filters and retention, and the traits you send are stored on the user's profile. It needs an
API key with ingest:write. Reference:
POST /api/v1/ingest/identify.
The tracking script has its own identify (pilotfox.identify(...), see
Events and identify) for signed-in visitors. The server-side one does the same,
with two differences: you say which visitor you mean, and the email trait it sends
links payments.
Request
{
"site": "SITE_ID",
"uid": "user_8412",
"ip": "203.0.113.7",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
"traits": { "email": "ada@example.com", "plan": "pro", "seats": 5 }
}| Field | Required | What it is |
|---|---|---|
site | yes | The site's public id. |
uid | yes | Your user id, up to 255 characters (a number is read as text). An id with no text in it is a 400. Use an id that cannot be guessed, such as a UUID, rather than an email or a counter. |
anonymous_id | one of the two | Your own stable id for the visitor, as sent with server events. |
ip and user_agent | one of the two | The IP address and User-Agent of the visitor's browser, as your server received them: the visitor the browser's own events belong to. Both are needed. |
traits | no | An object of traits to store on the user's profile. A value that is not an object is ignored. |
Send anonymous_id, or both ip and user_agent (if all three come, anonymous_id decides). Which visitor each one
names is explained in Matching server events to visitors. To
identify someone who is browsing your site, use the address and user agent of a request their browser made to your
server, for example the sign-in request: that links the visitor the tracking script has been recording.
Traits
- Values are strings, numbers or booleans. A trait whose value is an object, an array or not a finite number is dropped, and so is one whose key or text holds a NUL character or an unpaired UTF-16 surrogate.
- Merged, not replaced. Traits you send are added to the profile or overwrite the same keys; keys you leave out
stay as they were. To remove a trait, send it with
null:{ "plan": null }. - 4 KB per profile. The stored traits, as compact JSON, are kept within 4 KB. A new or larger trait that would go past it is skipped, and the stored ones are kept.
Response
204 No Content, with no body. It is also the answer when the site's settings exclude the request (an excluded IP
address, network, country or user agent, judged on the ip and user_agent you send) or it comes from a detected bot
while the site blocks bots: nothing is stored then, and the answer does not say so.
| Status | When |
|---|---|
400 Invalid identify | No site or uid, an empty uid, an ip that is not an IP address, a user_agent or anonymous_id that is not a string, or neither a non-empty anonymous_id nor both ip and user_agent. (A body that is not JSON is a 400 too, with another message.) |
401 | No API key, an invalid one, or another kind of credential. |
403 | The key lacks ingest:write. |
404 Site not found | The site does not exist, was deleted, or the key cannot write to it (another organization's, outside its site list). |
429 | The key's write budget is spent: identify and events share it. |
The email trait and payments
When a payment arrives from a payment provider or the payments API, PilotFox links it to a visit, and so to its traffic source, campaign and affiliate. One way is the customer's email: a payment whose customer email equals the email of a user is linked to that user's latest session before the payment, when no checkout reference or user id linked it first (see Revenue attribution).
Only an email trait sent by this endpoint counts. Anyone can call the tracking script's identify from their
own browser with any user id and any email, so an email set that way is shown on the profile but never links a
payment. Editing a user's traits in the dashboard never makes an email link payments either.
- The email is compared without regard to case.
- Sending
emailagain replaces it; sending"email": nullremoves it, and payments stop linking by it. Traits sent without anemailkey leave it as it is. - Since payments go to the user's sessions, identify the user's browser (with
ipanduser_agent), not only ananonymous_idyour server made up: a user with no session gets no payment linked.
A complete example
At sign-in, your server knows the user and the browser that signed in:
curl -X POST "https://pilotfox.app/api/v1/ingest/identify" \
-H "Authorization: Bearer $PILOTFOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"site": "SITE_ID",
"uid": "user_8412",
"ip": "203.0.113.7",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36",
"traits": { "email": "ada@example.com", "plan": "pro", "seats": 5 }
}'The answer is 204. The user's sessions from that browser now carry user_8412, the profile has the three traits, and
a payment with the customer email ada@example.com (in any case) can be linked to that user.
Calling pilotfox.identify("user_8412") in the browser as well does no harm: both name the same user, and only the
server call makes the email link payments.