VisitTrack
Start free
☰ Browse the docs

Developers

People & identify

Tie visitors to your own user ids and traits (email, plan, signup date), then filter, count and export them in the People tab, the API and MCP.

identify() links an anonymous visitor to a user in your own app. Everyone you identify shows up in the People tab — one row per user id, even when that person used several devices — with their traits, first and last seen, the source that first brought them in, and the custom events they've done.

Several accounts from one browser stay separate people. When the same browser is identified as a new user id, events from that moment on belong to the new person; everything before stays with the previous one, and the anonymous visits before the first identify belong to the first person identified. Each account on that browser shows the browser's original first-touch source.

Send identify with traits

POST /api/track with a secret API key (Settings → API / MCP). visitorId is the _ana_vid value tracker.js stores in the browser: pass it to your backend at signup (a hidden form field, a header, or checkout metadata).

code
curl -X POST https://visitrack.app/api/track \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "identify",
    "visitorId": "the_ana_vid_value",
    "externalId": "usr_8f2a1",
    "traits": { "email": "ana@example.com", "plan": "free", "signedUpAt": "2026-09-28T10:00:00.000Z" }
  }'

From the browser

app.js
window.visitrack.identify("usr_8f2a1", { email: "ana@example.com", plan: "free" });

Traits shallow-merge, latest wins per key: a later identify with only { "plan": "individual" } changes the plan and keeps email and signedUpAt. Traits are stored per person, so a person on two devices always has one current set of traits. Trait values are stored as sent; filters compare them as text.

Traits are personal data

Traits often contain an email address. They are only visible to members of the site and to its API keys / MCP connections — never on a public dashboard.

Recipe: track the plan

  1. On signup: identify with { "email": "…", "plan": "free", "signedUpAt": "<ISO date>" }.
  2. On upgrade: identify again with { "plan": "individual" } (or "business"), and send a custom event such as upgraded so it can be filtered by 'has done'.
  3. On cancel: identify with { "plan": "free" }.
  4. Send product milestones as custom events (POST /api/track with type: "event", or visitrack("first_alert") in the browser).

The People tab

  • Filters combine with AND: trait equals / does not equal / is set, has done event, has not done event, and a signup date range (the signedUpAt trait when you send it, otherwise first seen).
  • Event conditions and the per-person event counts use the window picked at the top (30, 90 or 365 days).
  • The counts above the table show how many people match, grouped by one trait — plan by default, any trait key on request.
  • Every filter lives in the URL, so a view can be bookmarked or shared. Export CSV downloads the same filtered list.
  • Click a person to open their visitor profile and full timeline (the most recent device).

API and MCP

GET /api/v1/people takes the same filters as query params, alongside days/from/to (the event window), traffic, format=csv and limit/cursor. "How many free users got an alert but didn't upgrade?":

code
curl -G https://visitrack.app/api/v1/people \
  -H "Authorization: Bearer YOUR_API_KEY" \
  --data-urlencode "trait.plan=free" \
  --data-urlencode "did=first_alert" \
  --data-urlencode "notDid=upgraded" \
  --data-urlencode "days=365" \
  --data-urlencode "limit=1"
# data.total is the answer; data.breakdown groups it by plan
ParamMeaning
trait.plan=freetrait equals value
trait.plan!=freetrait is anything else (missing counts as not equal)
trait.email=*trait is set
trait=plan=free;emailthe same conditions in one param, ';'-separated (what MCP tools use)
did=first_alerthas done the event in the window (repeat or comma-separate for several)
notDid=upgradedhas not done the event in the window
signedUpFrom / signedUpToISO dates, inclusive
breakdown=plantrait the counts group by

Over MCP the same resource is the get_people tool — ask your assistant "how many free users got an alert but didn't upgrade in the last year?" and it calls get_people with trait "plan=free", did "first_alert", notDid "upgraded", days 365.

Deleting a person

For erasure requests, delete a person from the People tab (Members and Admins) or with a key that has the write:config scope:

code
curl -X DELETE https://visitrack.app/api/v1/people/usr_8f2a1 \
  -H "Authorization: Bearer YOUR_WRITE_KEY"

This removes the user id and every trait from all of that person's visitor records, so they drop out of People, the API and exports. Their pageviews and events stay as anonymous history: nothing links them to the person any more, and your past traffic totals don't change. The deletion is recorded in Settings → Activity under a one-way hash — the user id and traits are not stored in the log.

Something missing? Tell us.

AI agent or LLM? Read this page as markdown.