PilotFoxDocs

Events and identify

Send custom events with properties, tag elements with data-event, and identify signed-in users with traits.

The script's global object, window.pilotfox (or the name in the tag's data-namespace), sends custom events and tells PilotFox who a signed-in visitor is.

Custom events

pilotfox.event("signup", { plan: "pro" });
pilotfox.event("download", { file: "report.pdf", size_mb: 2.4, beta: true });

Each call sends one event, for the current page and the visitor's current session. Nothing is sent on a page that data-skip covers or while the visitor is opted out.

PartLimit
NameRequired, not blank. Up to 128 characters; a longer name is cut.
PropertiesA flat object of up to 30 keys; further keys are dropped.
Property keysUp to 64 characters; a longer key is dropped with its value, and so are __proto__, constructor and prototype.
Property valuesStrings (cut to 512 characters), finite numbers or booleans. Other values (null, objects, arrays, NaN) are dropped.

Limits are applied by cutting or dropping, never by refusing the event: the call above with { nested: { a: 1 }, tags: ["x"] } added still sends file, size_mb and beta.

The Events report lists event names with counts and their properties, and reports can be filtered by an event's name or properties.

The ref property

The checkout event's ref property links payments to visits. Its values are listed only for people and keys that can read sessions (sessions:read), and only they can filter reports by a ref property, of any event. Share links that do not include sessions and public dashboards can do neither.

Without JavaScript: data-event

A click on an element with a data-event attribute (or inside one) sends that event, with the element's data-prop-* attributes as string properties:

<button data-event="signup" data-prop-plan="pro" data-prop-source="hero">Start free trial</button>

This click sends the event signup with { "plan": "pro", "source": "hero" }. HTML lowercases attribute names, so data-prop-planName sends the property planname. It works whatever the tracker options say, and a tagged element sends only its event (no click or outbound event as well).

Calls before the script has loaded

The script loads with defer, so your own code may run first. Calls made before then can wait in a queue:

window.pilotfox = window.pilotfox || { q: [] };
window.pilotfox.q.push(["event", "signup", { plan: "pro" }]);
window.pilotfox.q.push(["identify", "user-123", { plan: "pro" }]);
  • Each entry is a method name and its arguments. pageview, event, identify, setTraits, reset, optOut, optIn, startReplay and stopReplay can be queued; anything else is ignored.
  • With a custom data-namespace, use that name instead of pilotfox.
  • The queued calls run in order once the script has loaded the site's settings, before the initial pageview: an identify queued this way is already on that pageview.

Once the script has run, calls on window.pilotfox work directly. Calls made before the site's settings have arrived wait too and run in order with the queued ones. The settings request gets 10 seconds (in browsers with AbortSignal.timeout); past that, the safe defaults apply and the calls run.

At most 100 waiting events

Once 100 calls are waiting for the settings (the queued ones included), further event() calls are dropped, so a burst of events on a slow connection cannot pile up. Every other call (optOut(), reset(), identify(), pageview(), stopReplay() and the rest) always waits and runs in order, so a visitor's opt-out is never lost to the cap.

Identify signed-in users

pilotfox.identify(user.id, { email: user.email, plan: "pro" }); // after sign-in, and on load when signed in
pilotfox.setTraits({ plan: "team", seats: null });               // update the same user's traits
pilotfox.reset();                                                // on sign-out
  • identify(userId, traits?) stores the user id in the browser's localStorage (pilotfox:uid), and every later event carries it. The id is cut to 255 characters; an empty or blank id is ignored.
  • It also tells PilotFox's server (POST /api/i) to link this browser's visitor to the user. Sessions on every device where you call identify with the same id then count as one user, and the visitor's earlier anonymous sessions are linked to that user too. Identifying in the middle of a session does not start a new one.
  • setTraits(traits) updates the traits of the stored user; it does nothing before identify.
  • reset() forgets the stored user id in this browser. Later events are anonymous again.
  • getVisitor() returns { uid }, the stored user id or null.
  • While the visitor is opted out, identify stores nothing and sends nothing.

Traits

  • A flat object of strings, numbers, booleans or null. null deletes that trait; objects and arrays are dropped.
  • Traits merge into what PilotFox already has for the user, and it keeps up to 4 KB of them per user: a new value that would not fit is skipped, and the stored ones stay.
  • A traits object over 4 KB (as JSON) is not sent at all: identify then sends the user id alone, and setTraits sends nothing.

Use an id that cannot be guessed

Anyone can call identify in their own browser with any id and any traits. Use an id that means nothing outside your app (a random id, not an email address or a sequential number), and treat traits set in the browser as display data, not as proof of anything.

For the same reason, an email trait set in the browser is never used to link payments by email. Send it from your server instead, with server-side identify.

The Users report lists identified users and anonymous visitors, with each user's traits and sessions. Editors can erase a user's data.

Server-side events and identify

Events that happen on your server (a webhook, a background job) and identify calls you want to trust can be sent with an organization API key that has the ingest:write permission:

EndpointWhat it does
POST /api/v1/ingest/eventsUp to 500 events per request, matched to the visitor by an anonymous_id or the visitor's ip and user_agent, with an optional timestamp up to 7 days in the past.
POST /api/v1/ingest/identifyLinks a visitor to a user id, with traits. Its email trait is the one used to link payments.

See Server-side ingest. API keys must stay on your server; never put one in a web page.

Using events in reports

  • Goals count sessions that reached a page (by path pattern), sent a custom event (optionally with property conditions), clicked an outbound link, clicked an element, submitted a form or copied text. Each goal shows its conversions and conversion rate, and one goal can be the dashboard's main goal.
  • Funnels follow 2 to 10 steps (pages, custom events, outbound link clicks, clicks, form submissions or copies) in order, and show how many reach each step, where they drop off and the median time each step takes.
  • Journeys show the most common paths through your pages.
  • Retention groups users by when they were first seen and shows how many come back.
  • Segments save a set of filters to apply to reports later.

On this page