fastmon Docs

Checkout funnel

Cart, checkout, and success per visitor, counted from stage events, with the shop's cart requests beside them. On by default; a Shopify shop adds a pixel for its checkout.

The checkout funnel counts how far visitors get through your shop. It counts per visitor which stages they reached, from stage events, and records the cart requests your pages send.

Facts only

Every number is a count of something observed: a visitor loaded a cart page, a visitor loaded a thank-you page. There is no "abandoned" metric, because that would be a claim built from a missing observation. The visitor may have bought on another device, after the daily stitch rotation, or on a thank-you page without the tracker.

How a pageview gets its stage

At ingest the collector matches the sanitized page URL (origin and path, plus any query keys you opted into) against a list of patterns per stage and stamps cart, checkout, or success on the pageview. A pageview with a stage also writes a stage event, which is what the funnel counts. The tracker sends no extra field.

The built-in patterns cover Shopware 5 and 6, WooCommerce (English and German slugs), Magento 2, PrestaShop, JTL Shop 5, and Shopify. Every pattern tolerates a language or shop prefix, so /de/warenkorb and /fr/cart count like their root variants.

Matching order is fixed: success, then cart, then checkout.

The marks and stage events are stored at ingest and never recomputed. Changing the patterns affects pageviews from that moment on.

Default patterns

The patterns use the pattern syntax below.

StageBuilt-in patternsShop systems
cart*/checkout/cart*, */cart, */cart/*, */warenkorb, */warenkorb/*, */warenkorb.*Shopware, Magento 2, WooCommerce, Shopify, PrestaShop, JTL 5
checkout*/checkout, */checkout/*, */kasse, */kasse/*, */bestellvorgang, */bestellvorgang/*, */bestellvorgang.*, */bestellung, */bestellung/*, /orderShopware, Magento 2, WooCommerce, JTL 5, PrestaShop, custom German shops
success*/checkout/finish*, */checkout/onepage/success*, */order-received/*, */order-confirmation, */order-confirmation/*, */bestellabschluss, */bestellabschluss/*, */bestellabschluss.*, */checkout/success*, */thankyou, */thankyou/*, */thank-you, */thank-you/*, */danke, */danke/*, */danke.*Shopware, Magento 2, WooCommerce, PrestaShop, JTL 5, generic thank-you pages

The patterns are word-bounded: */cart matches the cart page but not /cartoons, and */thank-you does not match /thank-you-for-subscribing. /order is exact and root-only, or it would match Shopware's /account/order.

The switch runs on every site, shops or not. On a site with paths like /docs/checkout/setup, those pageviews pick up a stage; the remedy is custom patterns or the opt-out. OXID reads its cl controller. For Shopify, see Shopify checkout events.

Pattern syntax

A pattern describes the whole path, and matching ignores case. Checkout paths and URL rules take a subset of the URLPattern pathname syntax:

PartMatchesExample
*Any characters, / included*/checkout/*
:nameExactly one path segment/:lang/:slug
(de|en)One of the listed words/:lang(de|en)/cart
{...}?Its content or nothing/cart{/}?
anything elseItself, ? and = included*?cl=thankyou*

A pattern without a literal ? matches the path alone, so /checkout also matches /checkout?step=2. A pattern with a ? matches path and query together. One part per pattern may match in more than one way, such as a * before the end or a (...). A pattern that breaks a rule, such as a pasted regular expression, is refused on save.

Cart interactions

The URL stages see pages. A visitor who adds a product from a listing or a drawer cart never loads a cart page, so the funnel also records cart interactions: a first-party POST to a known cart endpoint, read from the fetch/XHR telemetry the tracker already collects. Where the endpoint reveals it, the interaction carries a kind.

KindEndpoints (POST)Shop systems
add/checkout/line-item/add, /checkout/ajaxaddarticlecart, /checkout/cart/add/*, */cart/add, */cart/add.js, /wp-json/wc/store/v1/cart/add-itemShopware 6, Shopware 5, Magento 2, Shopify, WooCommerce (Store API)
change/checkout/line-item/update, /checkout/line-item/change-quantity/*, */cart/change, */cart/change.js, */cart/update, */cart/update.js, /wp-json/wc/store/v1/cart/update-itemShopware 6, Shopify, WooCommerce (Store API)
remove/checkout/line-item/delete/*, /wp-json/wc/store/v1/cart/remove-itemShopware 6, WooCommerce (Store API)
other/cartPrestaShop, Shopify Hydrogen

On Shopify a quantity of 0 is a remove and arrives as change. The kind of an other row lives in the request body, which fastmon never reads.

Cart interactions need collect_fetch_xhr (on under Standard). With it off, the URL stages still work and the cart counts stay empty. Adds that go out as a classic form POST (OXID, WooCommerce single-product pages) are invisible to fetch/XHR.

Cart interactions are reported beside the funnel steps, never as one.

Stage events and sampling

The funnel counts events only. A pageview's checkout_stage does not count as a stage on its own. A visitor reaches a stage through any event with one of these names, whatever sent it:

StageEvent names
cartview_cart
checkoutbegin_checkout
successorder_placed, purchase
  • Checkout pages write a stage event with source collector for every pageview with a stage. These need checkout tracking, a shop, and a stored stitch, and they cannot be edited or deleted.
  • The Shopify pixel sends begin_checkout and order_placed, see Shopify checkout events.
  • Your own events count too, such as a GA4 purchase from the dataLayer. A buyer with order_placed and purchase counts once.

Events are never sampled, so the steps, cohort sizes, stage series, and purchases are exact at any rate. visitors_total and the cart interactions come from sampled pageviews and are estimates. The conversion rate divides exact buyers by estimated visitors.

Filters

  • Site, country, device, and the other edge dimensions narrow the events exactly.
  • Page filters (URL, page type, login state, connection, viewport class) narrow the events by the page they were sent from, exactly. Events stored before 2026-10-16 carry no page and match none.
  • Campaign and referrer match the visitor's entry pageview. On a sampled application the result is an estimate, and meta.sampling.estimated_metrics says so.
  • Refused with 422: the technical page filters (navigation type, protocol, cache status, origin host, error origin, third-party category), a metric range, checkout_stage, and the identity session.

What the numbers mean

  • Conversion rate: visitors with a success over all visitors in the window, the number GA4 and Shopify report. Hold it against the usual 1 to 3 % shop benchmark. visitors_total is the denominator, and each point of the series carries its own visitors.
  • reach_rate per step: the share of the first step. It can exceed 100 %, because a visitor can enter a later step without the earlier one being observed (a deep link, a drawer cart, an express checkout).
  • Visitors per step. Each visitor counts once per step they reached in the window, grouped on the visitor identity (stitch by default, see Visitors and sessions). Nothing per visitor is stored; the grouping happens at query time.
  • Bucketed by entry. In the series a visitor lands in the bucket of their first funnel row, not of their success. Bucket visitors do not add up to the window total. A day is final once the day, the 24-hour stitch window, and the ingest lag have passed.
  • Add-to-cart rate (cart_interaction_rate): visitors who used the cart over all visitors, typically 5 to 6 %. Read it as a floor wherever the shop's cart calls are invisible to fetch/XHR.
  • Visitors whose cart calls failed (cart_interaction_error_visitors): against cart_interactions, the share of shoppers who hit a broken cart.
  • Time to purchase (time_to_success_seconds): seconds from funnel entry to the first success, as p50, p75 and p90.
  • Success is a page or an event, not a payment. Without a Shopify pixel or a purchase event, a shop whose thank-you page does not load the tracker shows checkouts without successes. That is the most common setup issue.
  • A rate that could not be measured is absent. If the visitor count times out, the response keeps its steps and omits visitors_total and conversion_rate rather than reporting 0 %.

Shopify checkout events

Shopify runs its checkout on its own infrastructure, where your theme script never loads, so the URL stages end at the cart. A custom pixel reports three checkout steps as events: checkout entered, payment submitted, order placed. Setup, and what limits the coverage, is in Track the Shopify checkout.

What changes in the funnel once the pixel runs:

  • checkout and success come from events, with no pageview on either. Visitors seen only in the checkout join visitors_total.
  • payment_submitted_visitors is a fact beside the steps: visitors who submitted payment. It is absent, not 0, when no event was read for the window.
  • Purchases are a lower bound. Shopify does not fire its checkout completed event for most Shop Pay and Apple Pay orders. A visitor with a payment and no success most likely bought through a wallet.
  • Content blockers stop the pixel. EasyList's EasyPrivacy list blocks Shopify's custom-pixel sandbox path, and uBlock Origin ships that list by default. Those visitors contribute storefront pageviews but no checkout events, so the conversion rate reads low. See content blockers.
  • Cart to checkout can exceed 100 %. A buyer who went straight into the checkout never loaded a cart page.
  • Page filters match the pixel's events by page type checkout, viewport class, and connection class. Events from before 2026-10-18 carry none of them.
  • A login state filter answers 422 on a scope with a Shopify application, since the pixel reads no customer data. The dashboard shows no orders then and offers "Remove login filter".
  • No pageviews in the checkout. A buyer seen only in the checkout counts in a cohort without Web Vitals, and the sessions explorer does not show the Shopify checkout.

The events carry the step, the visitor's country, device, browser, viewport, connection and traffic class, and the edge identifier. No URL, session id, or order value: the Shopify checkout is counted, not measured.

Where it shows up

  • Analytics dashboard. Orders and Conversion are headline metrics. Orders draws the success series with cart and checkout as context lines. Conversion draws the rate against the previous period, and its tooltip names the visitors behind each point.
  • Checkout card. The steps, the cart requests by kind, the visitors whose cart broke, and the time to purchase.
  • Buyers compared. A card at the bottom, closed by default, compares visitors with a seen purchase against those who reached the checkout without one. It loads only when opened.
  • Stage chart. Visitors per stage over time, counted when they reached it, against the previous period.
  • checkout_stage filter. Cart, checkout, and ordered are fixed options in the filter bar, the chips, and the command palette. On the metric pages Web Vitals per funnel stage is a filtered query.
  • Explorer. Group by Checkout Stage, chart Cart Actions and Failed Cart Actions, and read stage and kinds as columns. A "Checkout" preset brings stages over time and LCP per stage.
  • Visitors. Filter the list to everyone who reached a stage or issued a cart interaction. On the journey each pageview carries a Funnel chip colored by stage.
  • Business Impact. Where the funnel has data, the page shows the same conversion rate instead of the estimate derived from LCP and INP.

The checkout numbers follow the page's filters. The checkout panel names a filter it cannot use, with a button to remove it. They show only on a shop: an application whose platform is unknown counts as one until shop.active is false.

Settings

The switch and the patterns live on the application under Settings → Shop & page types, and on the API under shop.checkout (see Applications).

  • checkout_tracking is on by default and is the opt-out. It covers the URL stages and the cart interactions together. Marking is forward-only, so turning it off leaves a gap you cannot fill later.
  • Per-stage paths. Each stage either inherits the built-in patterns (the default, null) or replaces them wholesale. There is no merge. Up to 10 patterns per stage, each up to 200 characters, lowercase printable ASCII, in the pattern syntax. Improvements to the built-in list reach every site that did not override that stage.
  • Requirements. Counting visitors per stage needs the stored stitch; without it, or under the identity session, the funnel endpoints answer 422. Cart interactions additionally need collect_fetch_xhr.

Query-based checkouts (OXID and others)

OXID keeps the whole checkout on index.php and names the step in the cl query parameter. On an OXID application the stored URL keeps cl, as in /index.php?cl=thankyou, and the funnel needs no setup: basket is the cart, user, payment and order the checkout, thankyou the success. Custom *?cl=* patterns still come first, and a stage with its own path list, including [], gets nothing from the controller.

A generic ?step= checkout needs the key in collect_query_values_for and custom patterns such as *?step=payment*.

Privacy

The stage is a four-value label computed from the URL the site already stores; the cart interaction is a flag computed from fetch/XHR paths it already stores. Neither adds a field to the beacon or visitor entropy, and a stage event copies only what the pageview row already holds. The funnel is computed at query time in every collection mode, including anonymous.

What the Shopify pixel carries is listed under Shopify checkout events, your own events under Privacy.

API

  • POST /organizations/{org_id}/analytics/funnels/checkout: the steps with visitor counts and reach_rate, the window conversion_rate and visitors_total, the cart interaction counts by kind, time_to_success_seconds, and the series bucketed by funnel entry. See the reference.
  • POST /organizations/{org_id}/analytics/funnels/checkout/cohorts: visitors with an observed success against those who reached the checkout without one. Per group, the Web Vitals over the whole journey and per stage, plus how many cart calls went out, how slow they were and how many failed. See the reference.
  • POST /organizations/{org_id}/analytics/funnels/checkout/stages: the visitors who reached each stage per hour or day, checkout events included, for the stage chart. compare_to adds a second window, in the same forms as on /analytics/query. A comparison reaching back before a Shopify pixel was installed shows the installation as a rise.
  • POST /organizations/{org_id}/analytics/funnels/checkout/journeys: the pageviews around a visitor's hit on a given step, with the visitor's checkout events beside pages. With full_journey: false, pages holds the pages the stage events were sent from. See the reference.
  • POST /organizations/{org_id}/analytics/visitors accepts contains_checkout_stage and contains_cart_interaction as filters, and the stage comes from events. Under the identity session it answers 422 for contains_checkout_stage and leaves out outcome, ordered_visitors, and checkout_visitors. The visitor detail answers events beside pages.
  • POST /organizations/{org_id}/analytics/events lists the checkout events beside your own, newest first, so a test order can be held against the Shopify order list. See Custom events.
  • checkout_stage is a filter and exclude dimension on every analytics endpoint that takes filters (exclude: {checkout_stage: ['']} keeps only funnel pageviews), and a group-by dimension in POST /analytics/query. cart_interactions and cart_interaction_errors are metrics there (and therefore usable in notification rules) and metric ranges. POST /analytics/beacons projects checkout_stage, the two counters, and the cart_interaction_kinds map onto each row.

What's next

On this page