Goals and revenue
Event, pageview and click goals, revenue props, attribution by first exposure.
A goal is the metric an experiment is judged on. Each experiment names one goal; the verdict is computed on it. Other declared goals can still be tracked, but the experiment verdict uses its selected goal.
Kinds
goals: {
signup: { type: 'event' },
purchase: { type: 'event', revenue: true },
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') (React useTrack, client.track, window.splithub.track) |
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 |
Goals can also be created in the dashboard (Settings → Goals, or "+ New goal" when creating an experiment) and are delivered to cloud clients. Add them to the local config yourself: pull does not write goal definitions. A goal in use cannot be deleted.
Revenue
track('purchase', { revenue: 49 });
With revenue: true on the goal, results include revenue per variant in verdict.sample.variants, available through the API or results --json. Revenue per visitor is revenue divided by exposures. The verdict stays on the conversion rate; revenue is a guardrail (a variant that converts more but earns less is not a win).
Attribution
A visitor converts for a variant when they sent the goal at or after their first exposure to that variant. Units are unique visitors: ten purchases by one visitor are one conversion (and the summed revenue). A goal sent before any exposure counts for nothing, which is the right behavior for "did the change cause it".
Only declared goals are tracked. In cloud mode the project must have a running experiment and available quota for ingest to accept events. Earlier goals are not retroactively attributed to a later exposure.
Props
track(goal, props) accepts a small JSON object (up to 4,096 characters when JSON-serialized). revenue is the only key with built-in meaning; the rest is stored with the event and shown in the raw-events view and the CSV export.
Pageviews in SPAs
Client-side navigation does not reload the page, so call usePageview(pathname) (React) in the layout, or client.pageview(path) with @splithub/core. In Next.js, pass usePathname() to usePageview in a client component; the provider only tracks the initial pageview.
Good goals
- One primary goal per experiment, decided before the test starts.
- As close to the change as makes sense: a headline test on the home page is judged on "clicked the primary button" or "signed up", not on "paid 30 days later".
- Counts of unique visitors, not of hits. Repeated clicks by one visitor do not make a variant better.