xDiscount is on the Shopify App Store. Founding merchants lock in lifetime founder pricing.
Docs

Insights

Analytics

Four tiles, a chart of any one metric, a discount type filter and a By day table, plus what the storefront pixel collects and where the exact revenue is.

Opening the Analytics page

1

Open the app

Open xDiscount from Apps in your Shopify admin.

Go to Analytics

Click Analytics in the app’s sidebar.

Pick a range

Use the date button at the top. It is labelled with the range you are looking at, Last 7 days when the page first opens, and clicking it lists Today, Last 7 days, Last 30 days and Last 90 days, with a custom range below the divider.

Narrow the metrics if you want to

Beside the date button, the All metrics chip narrows what the chart can plot and which columns the By day table shows. Click it for a small card of three choices: All metrics, Storefront metrics (approximate) for product views, added to cart and checkouts seen, or Shopify metrics (exact) for discounted orders and revenue. The four tiles never narrow, and your choice is remembered on this browser.

To set a custom range, type a From and a To date as YYYY-MM-DD and click Apply. Cancel, or Escape, discards dates you typed but did not apply, so the button never labels a range that was not actually fetched. Reversed dates are swapped, not rejected. Days are UTC calendar days, the same way they are counted everywhere else in the app.

The range lives in the page address, so a reload or a shared link lands on the same numbers, and it is the same range the Performance strip on Home uses. Moving between the two screens does not change it. The date button is greyed out while numbers are loading, and picking a range re-reads everything on the page together, so tiles, chart and table always cover the same window. While a new range loads, what is already on screen stays put and dims slightly, with a small spinner beside the date button.

There is no per-discount breakdown. What you get is four tiles, a chart of any one of them and a day-by-day table.

The Analytics page, the storefront pixel and the campaign order field are included on every plan, Free included. Nothing on this screen is held back for an upgrade.

How far back the history goes

History reaches back 250 days at most. If a custom range starts earlier than that, the page shows what it has and an information banner says where the range really starts: “History goes back 250 days, so this range starts on …”

The four tiles

The first row of the page is four plain cards, always in this order: the metric’s name, and the figure under it. Money first, then orders, then the two ratios.

TileWhat it countsWhere it comes fromExact?
RevenueThe checkout total of discounted checkouts the pixel saw, in your store’s currencyStorefront pixelApproximate
Discounted ordersOrders where xDiscount actually reduced the priceShopify’s own order webhookExact
Average order valueRevenue divided by discounted ordersDerived from the two aboveNot applicable
Conversion rateDiscounted orders divided by product viewsDerivedNot applicable

The shopper’s journey, Product views, Added to cart, Checkouts started and Checkouts seen, is on the page too, as the chart’s metric choices and as columns of the By day table below. A few things are worth knowing about how those are counted:

  • Added to cart counts units. A shopper adding three of the same item adds 3 to the number, not 1.
  • Checkouts started carries no money. Nothing has been charged at that point, so counting a total there would be counting a sale that may never happen. The gap between Checkouts started and Discounted orders is your checkout abandonment, and it is the one number on this page Shopify’s own discount reports cannot give you.
  • Product views and Added to cart are not filtered to discounted products. They count activity across your product pages, so they are a traffic baseline to read the later steps against, not a count of shoppers who saw an offer. That is why the chart says Product views, not “offer views”, and why Conversion rate is orders over all product views, a store-wide rate rather than an offer’s.

The Revenue tile has one honest exception. If Shopify counted discounted orders in the range but the pixel saw none of those checkouts, the tile does not print 0.00. It shows a dash, and hovering it, or reading it with a screen reader, says “Not captured. The storefront pixel saw none of these checkouts.” A zero would claim nobody paid. The truth is that the figure was never recorded.

Within a range that has activity, a real zero is shown as a zero. A range with no activity at all is a different case, covered in The other states this page can show below.

The chart

Under the tiles is a line chart of one metric at a time. Its heading is the metric’s name, and the Chart metric dropdown in the top-right corner switches between Product views, Added to cart, Cart viewed, Checkouts started, Checkouts seen, Discounted orders and Revenue. The dates the chart covers are printed beneath it.

  • One point per day, zero days included. Quiet days are drawn as zeros, never skipped.
  • Hover along the plot and a crosshair snaps to the nearest day, with a readout of that day’s date and value. The same readout works from the keyboard: focus the chart, then use Left and Right to walk day by day, Escape to clear.
  • Only the latest point carries a printed value. Every other day is in the readout and in the By day table below.
  • A metric with nothing to draw in this range shows a sentence instead of an empty axis, for example “No product views between Sep 9, 2026 and Sep 15, 2026.”

The chart is a viewing preference. Switching it changes nothing about the page address or the data, only which line you are looking at.

Why “Checkouts seen” and “Discounted orders” disagree

They will differ, and that is expected:

“Checkouts seen” comes from the storefront and is approximate: ad blockers and shoppers who decline analytics are not counted. “Discounted orders” comes from Shopify itself and is exact.

Checkouts seen is a storefront signal, and so is Checkouts started. Both are missed whenever a shopper runs an ad blocker, declines analytics tracking in your store’s privacy settings, or closes the tab before the beacon leaves. Nothing is retried.

The two are different moments. Checkouts started is reaching the checkout, and Checkouts seen is the pixel witnessing it completed. A shopper who abandons is counted in the first and not the second.

Discounted orders arrives on a Shopify-signed order webhook. An order is counted only when the order carries an xDiscount discount and your store has at least one discount registered with Shopify. That is the same test your billing uses when it counts an order against your plan’s included orders, so the two are counting the same orders.

Which number to trust

Treat Discounted orders as the number of record. Use the three pixel steps for shape and trend, not for accounting.

Filtering by discount type

Beside the date range is a filter chip. It starts on All and offers your four discount types:

ChoiceWhat the page then shows
AllEverything your storefront recorded, plus every discounted order
PercentageOnly activity on products covered by a percentage discount
Fixed amountOnly activity on products covered by a fixed-amount discount
Buy X get YOnly activity on products covered by a Buy X get Y discount
Free shippingOnly activity on products covered by a free-shipping discount

Every number on the page follows the chip: the tiles, the chart and the By day table.

How an event gets its type. A product belongs to one discount, so a product page view, an add to cart, or a checkout resolves to exactly one kind. A product no discount covers counts under All and under no type, which is why the four types will not account for all of your product views. That is your untargeted catalogue, and it is meant to be there as a baseline.

The four types add up to more than All

That is correct, not a rounding error. One checkout can contain a percentage product and a Buy X get Y product. It is one checkout under All, and it is honestly counted under both types, because “checkouts that contained a percentage discount” is the question the filter asks. All is measured in its own right, never added up from the four.

Archiving frees a product. An archived discount no longer covers its products, so activity on them stops appearing under that type, exactly as the discount form stops reserving them.

After you change a discount’s type, new events follow the new type within about a minute. Nothing already recorded is rewritten. A day that happened under the old type stays where it was, because it is what happened.

The By day table

Below the chart, By day lists one row per day with eight columns:

DayProduct viewsAdded to cartCart viewedCheckouts startedCheckouts seenDiscounted ordersRevenue
  • Newest day first.
  • Days with nothing on them are shown as zeroes rather than skipped, so a quiet week looks quiet instead of being squeezed out of the list.
  • Days are whole calendar days (UTC) recorded on our side, not on the shopper’s device clock, so a shopper with a badly set clock cannot land in yesterday’s row. If your store runs on a different timezone, a day here will not line up exactly with the same day in Shopify’s own reports.
  • Every number the chart draws is in this table, so nothing on the page depends on colour or hover.

How the storefront pixel contributes

xDiscount installs a Shopify web pixel for you when the app is installed. You do not add it, configure it or maintain it, and there is no setting for it in the app.

It subscribes to exactly five storefront events and nothing else:

EventWhat is sent
Product viewedThe product ID and variant ID
Product added to cartThe product ID, variant ID and quantity
Cart viewedThe product IDs in the cart — no quantities, no money
Checkout startedThe product IDs in the checkout — no money, since nothing has been charged yet
Checkout completedThe currency code, the order total, and the title and type of each discount applied

Everything is folded into one daily total per store as it arrives. Nothing is kept as an individual shopper’s event trail.

It is fire-and-forget. A beacon that fails is dropped, never retried. A queue of pending telemetry inside a storefront is not worth what it would cost your shoppers in page speed. This is why the storefront counts are honestly labelled approximate.

Very busy stores

A very busy store can send more events in a minute than we accept from one store, and the excess is dropped rather than queued. This only ever nudges the pixel-sourced numbers downward. Discounted orders is untouched by it.

Privacy: what xDiscount never collects

The pixel declares itself as analytics only. In your store’s customer privacy settings that means:

PurposeDeclared
AnalyticsYes
MarketingNo
PreferencesNo
Sale of dataDisabled

Shopify only runs the pixel for visitors who have consented to every purpose it declares. Declaring marketing would have quietly dropped the pixel for every shopper who allowed analytics but declined marketing, so it is declared false. The pixel does no advertising, no retargeting, no sharing and no selling.

The pixel never collects, and cannot collect:

  • No shopper identity, so no name, email, phone number or customer record.
  • No IP address, no device identifier, no browser fingerprint input.
  • No per-visitor tracking ID, so one shopper’s views cannot be stitched into a session or followed across visits.
  • No page URLs, no referrers, no search terms.
  • No cookies or browser storage of its own.

What actually leaves the storefront is the short list in the table above: product and variant IDs, a quantity, an order total and currency, and discount titles. They are treated as opaque text on arrival, nothing is ever looked up from them, no pricing and no entitlement, and they are not kept. What is written down is the day’s running totals for your store, and nothing else.

If a customer asks what the app tracks

Product and cart activity in totals per day, and no information about who they are.

Where the revenue numbers are

The Revenue tile, the Revenue option in the Chart metric dropdown and the Revenue column in the By day table are all the storefront’s figure: the checkout totals the pixel saw on discounted checkouts. It is labelled approximate everywhere it appears, and the tile says why in its own words, “Storefront figure from discounted checkouts (approximate). Your Shopify reports have the exact number.” It misses the same checkouts Checkouts seen misses, so it will read low, and it is never used for billing.

The number of record is in Shopify. Shopify already reports discount revenue natively and does the money arithmetic on its own records, and a figure from us that differed by a cent would just read as a bug and cost you an afternoon reconciling it. So xDiscount tags the orders it discounts, and you slice your own Shopify reports by them.

How it works:

  1. When xDiscount reduces the price on an order, that order is stamped with the name of the discount that did it.
  2. The stamp lands on an order field called xDiscount campaign, which is set up in your store when the app is installed.
  3. In Shopify Analytics, group or filter a sales report by order.metafields.xdiscount.campaign.

The field name is exactly order.metafields.xdiscount.campaign. The Analytics page no longer repeats it, so keep this page to hand when you build the report.

Points to be aware of:

  • Only orders xDiscount actually discounted are stamped. Orders it did not touch stay blank rather than being lumped into a misleading bucket.
  • Your own manual discounts are never stamped into this field, even if they were on the same order.
  • Discount names longer than 120 characters are shortened in the stamp. A report dimension with thousands of near-identical values is unusable, so the value is kept short. The full name stays on the discount itself.
  • The field is read-only in the admin. It is written by the app, and an edit would be overwritten.
  • Shopify can decline to make the field groupable in reports on a given store. If that happens the field is still created, the stamp is still written and still visible on the order, it just cannot be used as a report dimension there.

The other states this page can show

StateWhat you seeWhat it means
LoadingFour placeholder tiles and a blank chart-sized blockThe first read of the page is in flight. Later range switches keep the old numbers on screen and dim them instead
No activityNo activity in this range, naming the dates, with an Open settings buttonNothing at all has been recorded in the selected range. No tiles, chart or table are drawn, because a wall of zeros would be indistinguishable from a broken pipeline
Read failedA red banner headed Couldn’t load your analytics with a Try again buttonWe could not read your numbers

The failure banner reads: “Your discounts are unaffected, this page only reads what has already been recorded.” That is the important part. This page only reads, so a failure here never stops a discount from applying at checkout.

The empty state explains itself, “Nothing was recorded between … and …. Numbers appear once shoppers see your discounts, the offer card has to be added to your theme for views and cart activity to be counted.”, and points you at Settings, where the Storefront offer card section has an Add to theme button. The offer card is what shows shoppers a discount on the product page, before they reach checkout, and it is included on every plan, Free included.

Reading the page well

  • Compare like ranges. Switch between Last 7 days, Last 30 days and Last 90 days rather than reading one window in isolation, and use a custom range to line up with a specific promotion.
  • Compare the storefront counts with Discounted orders. The counts move with your traffic. The ratio between them moves with your offer.
  • Judge performance on Discounted orders. It is the exact number, and the one counted against your plan’s included orders.
  • Expect the storefront counts to miss some shoppers. Ad blockers and declined consent are normal, and they only ever undercount.
  • Go to Shopify Analytics for money questions, grouped by order.metafields.xdiscount.campaign. The Revenue tile is for trend, not for accounting.