Skip to main content
Every experiment measures at least one thing. That thing is a goal. It might be a click on a button, a page visit, a form submission, or a custom event you fire from your own code. Each experiment picks its goals from your site’s goal library.
Goals library

Site → Goals. The library of every goal defined on this site.

What a goal is

Three pieces:
  • A name, human-readable, shows up on the results page.
  • A short key, machine-readable, used in abtestly.trackGoal('key').
  • A definition, what actually causes it to fire. Seven kinds; see Goal types.

Primary vs guardrail

An experiment has:
  • One primary goal, the one that decides “did the test win?”.
  • Any number of guardrails, goals that catch collateral damage. A primary win with a broken guardrail is not shipped.
See Primary vs guardrail for how to pick. Two goals attach automatically as guardrails on every new experiment: Increase Engagement and Decrease Bounce Rate. See System defaults.

The library

Every goal on your site lives in the library, inline goals do not exist as a separate concept. If you create a goal directly on an experiment, it goes into the library and gets marked as attached to that experiment. Other experiments can then attach the same goal. Goals in the library have a status:
  • In use, attached to at least one experiment.
  • Idle, defined but not attached.
  • Locked, attached to a live experiment or shared across more than one experiment. Locked goals cannot be edited directly. Click Clone to edit to make an editable copy.
  • System, auto-seeded, cannot be edited or deleted.

How ABTestly counts a fire

For each variant exposure, ABTestly tracks the first fire of each goal per visitor per experiment. Refires do not count again, a visitor who clicks the CTA three times counts once. This is deliberate; otherwise a visitor’s engagement inflates their arm’s conversion rate in an untrustworthy way. The exception is revenue goals. Revenue is summed across all fires, because the second purchase is a real second purchase. Revenue deduplication uses orderId so a retried beacon does not double-count.

Cross-page attribution

For system default goals and any goal on a site with SPA support, a goal fired on a page different from the one that exposed the visitor still counts. If the visitor saw the test on /pricing and converted on /checkout, the conversion is credited to the test.

The health signal

The results page shows a small health chip per goal:
  • Silent, no fires yet. Might be too early; might be broken.
  • One-sided, every fire is on one arm. Likely a selector mistake.
  • Insufficient data, fires exist but not enough for a call yet.
See Goal health for how to read and fix each.

Common pattern: primary + system guardrails

For most tests, the shape is:
  • Primary: the specific thing you care about, a CTA click, a purchase, a signup.
  • Guardrails: the two system goals (attached automatically).
That is enough to catch the “wins the CTA click but crashes engagement” class of accident without any per-test setup.