# Events, goals and revenue

An event is anything your app sends with `track(name, props?)`. A goal is an event marked as one, and it is what an experiment is judged on. Each experiment names one goal; the verdict is computed on it. Other goals can be read beside it as [secondary metrics or guardrails](/docs/config).

## Events

```tsx
const track = useTrack();
track('Video Played', { id: 3 });
```

One call for every event: React `useTrack`, `client.track` in `@splithub/core`, `window.splithub.track` with the drop-in script. Any name is recorded; nothing to declare first. Names use letters, digits, spaces and `_ . : / -`, up to 64 characters. With an analytics property on the provider, every event shows up in its reports; see [Analytics](/docs/analytics).

## Goals

Name any event as an experiment's goal (`--goal "Video Played"` on `create`) and it is a goal: a name that is not in `goals` becomes an event goal keyed by its slug (`video-played`). Declare a goal in the config when you want a label, a value, revenue, a page visit or a click:

```ts
goals: {
  signup:         { type: 'event', name: 'Sign up' },
  purchase:       { type: 'event', revenue: true },
  'video-played': { type: 'event', event: 'Video Played', value: 2 },
  pricing_view:   { type: 'pageview', path: '/pricing' },
  docs_any:       { type: 'pageview', path: '/docs/*' },
  cta_click:      { type: 'click', selector: 'a[href="/start"]' },
}
```

| Type | Fires when |
|---|---|
| `event` | your code calls `track('signup')`, or `track('Video Played')` for a goal with `event: 'Video Played'` |
| `pageview` | a page with that path is viewed; `*` suffix matches a prefix |
| `click` | an element matching the selector is clicked; bound automatically by the SDK and the script |

A click goal is sent as a goal when the element is clicked; raw clicks are not recorded as events. `name` is a label for people, `value` is what one conversion is worth in analytics reports when the event carries no `revenue` prop. Goals count as conversions in every analytics property unless the property's `goals` list narrows them.

Goals can also be made in the dashboard (Settings → Events, the goal switch on an event, or "+ New goal" when creating an experiment) and are delivered to cloud clients. `pull` does not write goal definitions into the file; add them yourself if you want them there. A goal in use cannot be deleted.

## Revenue

```tsx
track('purchase', { revenue: 49 });
```

With `revenue: true` on the goal, results include revenue per variant, and in SplitHub Cloud revenue per visitor (visitors who did not pay count as 0) compared with the control by Welch's t-test. Read it through the API or `results --json`. The verdict stays on the conversion rate; to make sure a variant that converts more does not earn less, add the revenue goal as a guardrail.

## Attribution

A visitor converts for a variant when they sent the goal **at or after their first exposure** to that experiment. In SplitHub Cloud this is decided at ingest; self-hosted stores apply the same rule when they read. Units are unique visitors: ten purchases by one visitor are one conversion (and the summed revenue). At most 50 of one goal per visitor per day are kept. A goal sent before any exposure counts for nothing, which is the right behavior for "did the change cause it". Earlier goals are not retroactively attributed to a later exposure.

In cloud mode ingest accepts events while the project has a running experiment or property and quota left. Goals from visitors who never saw an experiment do not reach any experiment; an analytics property still records the event.

## Props

`track(name, props)` accepts a flat JSON object up to 4 KB (4,096 characters when JSON-serialized); above that, the SDK keeps what fits, `revenue` first. `revenue` is the only key with built-in meaning; the rest is stored with the event and shown in analytics reports, the raw-events view and the CSV export. Keep personal data (emails, names) out of props.

## Pageviews in SPAs

The provider sends a pageview on mount, and the client reports every client-side navigation (history and hash routes) as a pageview after that, so pageview goals fire on route changes without extra code. `usePageview(path)` (React) or `client.pageview(path)` reports a page by hand, for example when navigation tracking is turned off with `trackNavigation: false`.

## Good goals

- One primary goal per experiment, decided before the experiment starts.
- As close to the change as makes sense: a headline experiment on the home page is judged on "clicked the primary button" or "signed up", not on "paid 30 days later". Put the later outcome in `metrics`.
- Counts of unique visitors, not of hits. Repeated clicks by one visitor do not make a variant better.
