Events

What events are, how they reach Improve, and how to use them to measure a test.

An event is a signal your website sends to Improve when a visitor does something meaningful: viewing a page, clicking a button, signing up, or completing a purchase. Events are how Improve knows whether a test is working: by counting the visitors who reach your goal, per variant.

Events are test-independent: an event just records that a visitor (an anonymous visitor id) did something. Improve attributes it to a test (and to the variant that visitor saw) server-side, by joining the event against the visitor's exposures. That's what lets Improve compare variants fairly.

How events flow

Your website  →  Improve  →  Events list  →  attached to a test  →  Results
  1. Your site fires an event when something happens (e.g. a visitor clicks "Buy now"). This is done by a developer with the SDK, or (once it's set up) automatically from Google Tag Manager.
  2. Improve records it and, the first time it sees a new event name, adds it to your Events list automatically. You never have to pre-register events.
  3. You attach events to a test to define what counts as a start, a step, and a conversion.
  4. Improve calculates results (conversion rate and the funnel) for each variant.

Default: track page views like Google Analytics

Before setting up anything else, wire up one event on every page: a GA4-style page_view, fired once per page load, with the current path as its scope. This is the single most useful event to have flowing: it doubles as the default start event for new tests, and it's what powers the Unique visitors per day chart and Popular pages overview on the Events page.

TrackPageView.tsx
'use client'

import { useEffect } from 'react'
import { usePathname } from 'next/navigation'
import { usePostAnalytic, useTestValue } from './improve'

export const TrackPageView = () => {
	const postAnalytic = usePostAnalytic()
	const pathname = usePathname()

	useEffect(() => {
		postAnalytic('page_view', pathname) // pathname is the required scope
	}, [pathname, postAnalytic])

	return null
}

Mount <TrackPageView /> once, near the root of your app inside the ImproveProvider (see the React / Next.js SDK docs), so it fires on every route without any per-page setup. If a test also reads a variant on the same page (useTestValue / useFlagValue), this page_view is attributed to it automatically through that exposure, no extra wiring needed.

Popular pages reads the page path from the scope on page_view events. If you already send a custom pageview event under a different name, rename it to page_view (or add this one alongside it) to light up that report.

Exposure: how events get attributed to a test

Because events are test-independent, Improve needs a separate signal to know which test and variant a visitor belongs to. That signal is an exposure: the SDK emits one automatically the first time a visitor reads a variant, namely a getTestValue / useTestValue (or getFlagValue / useFlagValue) call that resolves a non-holdout value. The server then attributes that visitor's subsequent events to the test and variant they were exposed to.

The practical consequence: a visitor must read a test's variant for their events to count toward that test. Visitors who are excluded by the test's audience, or who fall into the allocation holdout, are never exposed, so their events aren't attributed to the test. Make sure the code path that fires your events also reads the variant.

The Events list

Open the Events page in the dashboard to see every event Improve has received for the current organisation and environment. They're grouped so you can tell what's live:

  • Recent events: seen in the last 24 hours (these are active and safe to build tests on).
  • Inactive events: seen before, but not recently.
  • Untracked events: names that exist (for example, attached to a test) but haven't been received yet. If a brand-new event stays here, it usually means it isn't firing on your site yet.

Don't see your event? Trigger it on your site once and refresh; new event names appear here automatically the first time they're received.

Setting up events on a test

When you create or edit a test, the Events section defines the conversion funnel (the ordered journey you want visitors to take). Each step is an event + scope pair — both required, e.g. page_view + homepage:

  • Start event: the entry point that puts a visitor "into" the test, e.g. page_view scoped to homepage. This is your 100% baseline.
  • Metric events: optional in-between steps, in order, e.g. add_to_cart scoped to product_page, then begin_checkout scoped to checkout. Each one becomes a step in the funnel.
  • Conversion event: the final goal, e.g. purchase scoped to checkout.

Only events matching both the event name and its scope count toward a step — that's what lets the same event name mean different things in different places (a button_click scoped to homepage_hero_login is a different funnel step from one scoped to homepage_hero_register). The start step is the exception: it always counts every visitor exposed to the test, regardless of what fires afterward.

As you type the event name, Improve suggests names from your Events list; the scope field then suggests scopes actually seen for that event name, so you can pick combinations you know are firing.

You don't have to use metric steps. A simple test just needs a start and a conversion event.

Conversions and the funnel

The conversion rate is the share of visitors who reach your goal (conversions ÷ starts), calculated separately for each variant so you can see which one performs best.

When you add metric steps, the test Monitor also shows a multi-step funnel per variant: the percentage of visitors who continue from one step to the next. For example:

page_view (homepage) → add_to_cart (product_page) 10% → begin_checkout (checkout) 30% → purchase (checkout) 5%

Read that as: of everyone who started, 10% added to cart; of those, 30% reached checkout; of those, 5% purchased. Comparing the same funnel across variants shows you exactly where one variant pulls ahead or drops off.

Revenue and order value

Events can carry a numeric value: typically an order total on your conversion event. Pass it (with a currency) in the payload to postAnalytic:

postAnalytic('purchase', 'checkout', { value: 72.05, currency: 'USD' })

When a test's events carry a value, the Monitor shows total revenue and average order value per variant alongside the conversion rate, so you can catch a variant that converts more often but at a lower order value, or vice versa. Values are summed as-is, so use a single currency per test.

Naming tips

Every event is an event name + scope pair — keep the action generic and reusable in the name, and put the specifics in the scope. That split is what lets one button_click event mean "the login button on the homepage hero" in one place and "the register button" in another, instead of needing a new event name for every button.

Event names

  • Start with page_view: see Default: track page views above. Every other tip here follows the same idea: reuse Google's naming, don't invent your own.
  • Use snake_case: add_to_cart, sign_up, purchase. This matches Google Analytics 4 and Google Tag Manager conventions, so the same event names work end-to-end if you also send events to GTM.
  • Prefer the standard GA4 names where one fits: page_view, view_item, add_to_cart, begin_checkout, purchase, sign_up, search, generate_lead. Reusing GA4's recommended event names means your data lines up with any GTM/GA4 tagging you already have.
  • Keep names short and consistent: reuse the same name everywhere that action happens. One purchase event is far more useful than purchase, Purchase, and buy_now.
  • Name the action, not the place: cta_click is more reusable than homepage_blue_button_click — the place belongs in scope, not the name.

Scope values

  • Name the place, not the action: homepage_hero_login, checkout, product_page. The action is already the event name; scope answers "where" or "which one."
  • Pick a stable identifier, not display text: a button's scope shouldn't change when someone edits its copy. Use a slug tied to the button/block/page itself, the same way page_view's scope is a URL path rather than a page title.
  • Reuse scopes across events when they refer to the same place: a page_view and a form_submit on the same signup page can both use signup as their scope, making it easy to see the whole funnel for that page at a glance.

Once your events are flowing and attached to a test, see What to A/B test for ideas on what to run.

On this page