# Goals

Pageview, click, custom event, revenue, and GA4 goal types.

A goal is the action you want to measure — a page reached, a button clicked, a purchase made. Each test can have multiple goals, but only one is marked primary. The primary goal drives statistical significance and the win/lose call on the results page; secondary goals are tracked for reference.

Goals are how Otter turns "a visitor saw variant B" into "variant B is winning." Every test needs at least one goal, and exactly one of them is the primary — the goal whose conversion rate (or revenue per visitor) drives the statistical decision on the results page. Secondary goals are reported alongside but do not affect whether a variant wins.

Choose the goal type that captures the conversion you care about as close to where it happens as possible. A click is a weaker signal than a checkout. A pageview of the "Thanks for signing up" page is stronger than a click on the signup button. A revenue event is the strongest signal of all because the dollar value is built in.

## Goal types

### Pageview (`pageview`)

Counts a conversion when the visitor lands on a specific URL. Works on hard navigations and on SPA route changes (the SDK re-evaluates the URL on every route push).

**Required configuration:**

- `url` — The destination URL. Matched by origin + pathname case-insensitively. If you include ?query or #hash on the goal URL, those must also match.

**Fires:** Automatically by the SDK whenever the visitor URL matches the configured target.

### Click (`click`)

Counts a conversion when the visitor clicks any element matching a CSS selector. The SDK watches the DOM with MutationObserver and a short retry interval, so elements added after page load are still tracked.

**Required configuration:**

- `selector` — Any valid CSS selector — e.g. .signup-button, #checkout-cta, button[data-action="purchase"].

**Fires:** Automatically on the first click of any matching element. Subsequent clicks in the same session are deduplicated.

### Custom Event (`custom_event`)

Counts a conversion when your application code emits a named event via the SDK. Good for funnels that span multiple pages or non-click interactions like "video watched" or "form submitted".

**Required configuration:**

- `event_name` — The exact event name your code passes to optimo.track(). Case-sensitive.

**Fires:** When your site calls `optimo.track("event_name", { ...properties })`.

### Revenue (`revenue`)

A custom event with monetary value attached. Drives revenue-per-visitor and Welch's t-test analysis. optimo.revenue() is a shortcut that fires the "Purchase" event with value/currency — to use a different event name, call optimo.track() directly.

**Required configuration:**

- `event_name` — The event name to listen for. Defaults to "Purchase" if you use optimo.revenue().
- `currency` — Optional. ISO currency code sent with the event. Revenue reports convert source event currencies into the goal reporting currency.

**Fires:** When your site calls `optimo.revenue({ value, currency, ...})` or `optimo.track("event_name", { value, currency, ...})`.

### GA4 Event (`ga4_event`)

Uses a privacy-safe Google Analytics 4 funnel total as a goal. Requires an active GA4 web stream connection; results are delayed, all-user aggregates and finalize for seven days after completion.

**Required configuration:**

- `ga4_event_name` — The event name as it appears in your GA4 property (e.g. purchase, generate_lead, sign_up).

**Fires:** Server-side, when Otter refreshes the aggregate exposure-to-conversion funnel in the connected GA4 property.

## Goal library

Each project has a goal library — a set of reusable goal definitions you can drop into a new test in one click. When the project has saved goals, the wizard shows them as chips above the goals editor (labeled *Quick add from your goal library*). One click adds a new goal pre-filled with the saved name, type, and config; from there you can mark it primary, tweak it, or remove it like any other goal.

The library is scoped to a single project — each project keeps its own — so a goal you save in your marketing-site project won't appear in your app-checkout project. That keeps libraries focused on the conversions that actually matter for each surface.

Today, saving and removing entries in the library is API-driven rather than wizard-driven — there isn't a manage-templates screen in the dashboard yet. If your team would benefit from one, let support know; it's on the roadmap and customer demand decides ordering.

## Primary goal and significance

Only the primary goal is used to declare a winner. If you don't mark one, the results page treats the test as inconclusive until you do. Switching the primary goal after a test starts is allowed but will recompute significance from the new goal's conversions, which can change the apparent "winning" variant — generally a sign you should rerun the test with the right goal from the start.

> **Goal tips:**
>
> - **Pick the goal closest to the value you actually want.** A click is a weaker signal than a checkout. A "Thanks for signing up" pageview is a stronger signal than a click on the signup button. Where you can, anchor the goal as close to the moment of value as possible.
> - **One primary, two to four secondaries.** The primary drives the win/lose call; secondaries give context. Tracking too many goals dilutes attention and invites cherry-picking after the fact.
> - **Use Revenue when there's real money attached.** Conversion-rate goals miss the difference between "more orders" and "more revenue". If the test could plausibly change average order value, score it on revenue.
> - **Avoid switching the primary mid-test.** It's allowed but recomputes significance from a different metric, which can flip the apparent winner. If you find yourself wanting to switch, that's usually a sign the test should be rerun.

## Frequently asked questions

### Which goal type should I pick?

Use Pageview when your conversion is reaching a specific URL (thank-you page, account-created page, /pricing). Use Click for button-level conversions (signup CTA, add-to-cart). Use Custom Event for funnels spanning multiple pages or non-click events like video plays, form submissions, or scroll depth. Use Revenue when the conversion has monetary value. Use GA4 Event when the conversion already lives in your existing analytics.

### How many goals can I track per test?

There's no hard limit. We recommend three to five total — one primary and two to four secondaries. Too many goals create noise and dilute focus. Pick the one that truly defines success as your primary and let the others track context.

### What does primary vs secondary goal mean?

The primary goal drives the win/lose call on the results page. Statistical significance is computed for the primary goal only. Secondary goals are tracked and reported separately so you can see, for example, whether a variant that won on clicks also won on revenue — but they don't affect the winner declaration.

### Why aren't my click goals firing?

Three usual suspects: (1) the CSS selector doesn't match — test it in DevTools with document.querySelectorAll(); (2) the element is rendered after page load and the SDK hasn't seen it yet (the SDK retries for several seconds via MutationObserver, but very late renders can miss); (3) the click is on a child element and event delegation isn't catching it. The browser console shows [Optimo] click-goal evaluations when ?optimo-debug is enabled.

### How does revenue tracking work?

Call optimo.revenue({ value: 49.99, currency: 'USD' }) on your order-confirmation page. That records the sale against the version the visitor saw. Revenue is then summed per version and used to compute revenue-per-visitor, which is the metric the results page scores for revenue-goal tests. Basic reload safety is built in — reloading the same confirmation page in one session won't double-count.

### How do I stop the same purchase being counted twice?

Include your order's ID when you record the sale — for example optimo.revenue({ value: 49.99, currency: 'USD', order_id: 'ORDER-1234' }). Otter then counts that order only once for the visitor, even if they reload the confirmation page, bookmark it, or come back to it later. You can use order_id, transaction_id, or purchase_id — whichever your store already has. If you'd rather supply your own unique value, pass idempotency_key instead. This matters most for stores where the confirmation page can be revisited; if yours can't be, the built-in reload safety is usually enough.

### Which currency does a revenue goal report in?

By default it uses your project's Default revenue currency, so all your revenue tests stay consistent. When you add a revenue goal in the wizard there's a "Use project currency" switch (on by default) — turn it off to set a custom currency for just that goal. Either way, payments made in other currencies are converted automatically. See the Revenue & Currency guide for the details.

### Can I switch the primary goal after the test starts?

Yes, but it recomputes statistical significance from the new goal's data, which can flip the apparent winner. If you find yourself wanting to switch primaries mid-test, that's usually a signal you should have picked a different goal upfront — consider rerunning the test.

### What happens if I don't mark any goal as primary?

The results page treats the test as inconclusive until you do. Variants still get assigned, conversions are still tracked, but no winner is declared. You can mark a primary at any time and the score updates with the next refresh.

### Do GA4 goals require any extra setup?

Yes. The project needs an active GA4 connection (configured under Project Settings → Integrations). Without it, GA4 goals fail validation when you try to launch the test. Once connected, Otter syncs new events from your GA4 property server-side every few minutes.

### What's the goal library?

It's a per-project list of saved goal definitions. When the project has any saved goals, the wizard surfaces them as &ldquo;Quick add from your goal library&rdquo; chips above the goals editor. Clicking a chip adds a new goal pre-filled with the saved name, type, and config so you don't have to type the same selector or event name across many tests. The library is project-scoped — your marketing-site project and your app-checkout project keep separate libraries.

### How do I add goals to the library?

Today, library management is API-driven — there isn't yet a manage-templates screen in the dashboard. If you'd like one, let support know; it's on the roadmap and we prioritize by customer demand. Until then, the chips will appear in the wizard whenever an admin has added entries via the API.

---

Canonical page: https://www.otterab.com/docs/building-tests/goals
