# Custom events and identify

> Send custom events with properties, tag elements with data-event, identify signed-in users with traits, and use events in goals, funnels, journeys and retention.

The script defines a global object, `window.pilotfox` (or the name in the tag's `data-namespace`). Use it to send events and to tell PilotFox who a signed-in visitor is.

## Custom events

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

- The name is required, up to 128 characters.
- Properties are a flat object of up to 30 keys. Keys are up to 64 characters; values are strings (up to 512 characters), numbers or booleans. Other values are dropped, and longer strings are shortened rather than rejected.
- Each call sends one event, attached to the visitor's current session.

The Events report lists event names with counts, and reports can be filtered by an event's name or properties. The `ref` property of `checkout` events, which [links payments to visits](https://pilotfox.app/docs/revenue#how-payments-are-linked-to-visits), is listed only for people who can see sessions: share links that do not include sessions and public dashboards leave it out, and cannot filter reports by a `ref` property (of any event).

### Without JavaScript: data-event

Any element with a `data-event` attribute sends that event when clicked, with its `data-prop-*` attributes as properties:

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

### Calls before the script has loaded

Calls made before the script has run can wait in a queue; they run in order once the script has loaded the site's settings:

```js
window.pilotfox = window.pilotfox || { q: [] };
window.pilotfox.q.push(["event", "signup", { plan: "pro" }]);
```

## Identify signed-in users

```js
pilotfox.identify(user.id, { email: user.email, plan: "pro" }); // after sign-in
pilotfox.setTraits({ plan: "team" });                           // more traits for the same user
pilotfox.reset();                                               // on sign-out
```

- `identify` stores the user id (up to 255 characters) in the browser's `localStorage`, and every later event carries it. An empty id is ignored.
- Sessions on every device where you call `identify` with the same id then count as one user, and the earlier anonymous sessions of the same visitor are linked to that user too.
- Traits are a flat object of strings, numbers, booleans or `null` (`null` deletes the trait). PilotFox keeps up to 4 KB of traits per user; larger trait objects are not sent.
- Use an id that means nothing outside your app and cannot be guessed (a random id, not an email address or a sequential number): anyone can call `identify` in their own browser with any id and any traits.
- Traits set in the browser are for your reports. To [link payments](https://pilotfox.app/docs/revenue#option-3-the-email-fallback) from Stripe, Dodo Payments or Polar by email, send the `email` trait from your server (below).
- The Users report lists identified users and anonymous visitors, with each user's traits and sessions. Editors can [erase a user's data](https://pilotfox.app/docs/privacy#erasing-a-users-data).

## Server-side events

Events that happen on your server (a webhook, a background job) can be sent with an organization API key that has the `ingest:write` permission:

- `POST https://pilotfox.app/api/v1/ingest/events` with `{ "events": [ … ] }`, up to 500 events per request. Each event has the same fields as the browser's, plus, all optional, the visitor's `anonymous_id` or their `ip` and `user_agent`, and a timestamp `ts` (up to 7 days in the past). An event sent without them is counted under your server's IP address and no user agent, so such events share one visitor, located where your server is.
- `POST https://pilotfox.app/api/v1/ingest/identify` links an `anonymous_id` (or an `ip` and `user_agent`; one of the two is required here) to a user id, with traits. An `email` trait sent this way is the one PilotFox uses to [link payments by email](https://pilotfox.app/docs/revenue#option-3-the-email-fallback).

The [API reference](https://pilotfox.app/api/docs/) has the exact request bodies. 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 or events) in order, within one session or within a time window across sessions, and show how many reach each step, where they drop off and how long 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 by day, week or month.
- **Segments** save a set of filters to apply to reports later.
