Littledata MonitorAI guide

Shopify checks — what the audits mean

These checks read the Shopify store itself, so they apply to every merchant regardless of which analytics or email platforms are connected.

How to read results

Outcome Meaning
Error Proven problem, costing money or damaging something now.
Warning Worth fixing.
Info FYI.
Success Rule passed.
Unknown Missing data, missing scope, or nothing to compare.

Bot checkouts

What we look for: a script creating checkouts with invented shoppers. Each one produces a real Shopify customer record and a real abandonment event, so any connected email platform will try to message an address that does not exist — inflating bounce rates and burning sending reputation. This is the cause; the Klaviyo Spam profiles created check sees the effect.

Because it reads the store rather than an ESP, it fires whatever the merchant sends email with, and it catches floods that never reach a marketing list at all.

What we read: one REST call to checkouts.json?limit=250, never paginated, needing only read_orders (satisfied by write_orders). Flat cost across store sizes.

Why it scores a cluster, not the store

Store-wide averages do not work, and this was measured rather than assumed. Across ten stores, the signals that look obvious all failed to separate a known flood from healthy stores:

Signal Known flood A healthy store beat it
Landing-page concentration 0.55 cornish-bed-company 0.60
No referrer and no cart attributes 0.58 kinvara-skin-care 0.86
Single-line-item share 0.74 tenpin-2 0.93
Low gmail share 0.28 cornish-bed-company 0.14

A small store with one hero product looks identical to a bot flood on every one of them.

What works is a within-store contrast. Bot checkouts carry no referrer and no theme-written cart attributes, because no storefront JS ran — so we split the store’s own checkouts on that (“dark” half), cluster the dark half by landing page, and score the largest cluster against the rest of the same store. The dark half alone proves nothing and is used only to find the candidate cluster, never as evidence.

Headless and custom storefronts are all-dark by construction — no theme JS means no referrer and no cart attributes for any shopper — so darkness can never convict. Every cohort is selected and scored by identity (generated-address structure); an all-dark store full of real customers has nothing for the identity signals to find, and the fleet’s darkest clean store (86% dark) correctly scores SUCCESS.

Rotation cover: floods that spread across many entry pages (the measured campaign already uses up to 7) can fragment every per-landing cluster below the 20-checkout floor. A second cohort — dark checkouts with generated addresses outside the main cluster (the “residue”) — is scored on its own: ≥20 of them whose addresses read as drawn from a provider pool is a primary signal, whatever the landing pages look like.

Signals

Signal Tier Clean-fleet baseline (306 clusters)
Cluster addresses following a generated name template Primary ≥40%, corroborating ≥25% p50 2.6%, p99 19%
Addresses spread evenly over a few free providers Primary 0 clean clusters trip it
Addresses that spell out the billing name submitted with them Corroborating ≥80% p50 33%, p99 75% — real emails contain real names, so this can never convict alone
Entered through one cart-permalink URL with no browsing Corroborating ≥60% p99 0%
Every checkout holds exactly one item Corroborating ≥95% p90 97% — weak, corroborates only
Effectively none accepted marketing Corroborating ≤5% opted in weak, corroborates only; the bullet names the exact count

Cart permalinks are legitimate — ad “buy now” links use them — so that signal only ever corroborates.

Two signals were retired after review (#644), and neither loss costs detection because both were already listed as measurement-rejected:

The message states the scale; furtherInfo carries the forensics. The message says how many of the store’s recent abandoned checkouts look suspicious (the landing cluster plus the rotated residue, since both cohorts are the same flood) and offers Bot Protection — nothing more. It used to open with the primary signal clauses, which meant a merchant met “generated-looking addresses and 97% have an address that spells out the billing name” before being told what was happening, and there can be six such clauses. furtherInfo lists every signal as a bullet — red for the primary ones that carry the verdict, orange for the corroborating ones — plus the cluster context the message leaves out (the shared landing URL, the residue’s spread across entry pages).

Error and Warning are correct severities here because Littledata can fix it: Bot Protection filters these fakes out of ad and email targeting, and the check links to its help article.

Rules:

Outcome Rule
Error ≥2 primary signals and ≥2 corroborating.
Warning Any single primary signal.
Info A firing verdict (either row above) on a store where every connected destination has bot filtering (Connection.settings.filterUnidentifiedEvents) enabled — the fakes exist, but Littledata is already filtering them from all the merchant’s marketing channels, so the message reports what was filtered instead of asking the merchant to act. One unprotected destination keeps full severity, and the message names it as what Bot Protection would filter these events from — “turn on Bot Protection to filter these fake events from Google Analytics 4 and Segment so you don’t waste budget chasing ghosts”. That used to be a second sentence naming the same channels again, which restated the offer it followed.
Success No cluster of ≥20 scriptable checkouts, or no primary signal.
Unknown No Shopify token, missing read_orders, API unreachable, or fewer than 40 recent checkouts carrying an email.

Corroborators alone never flag: the sweep tried “three weak signals agreeing” and every store it added was a false positive — single-product stores trip one-item, no-opt-in and (before it was retired) few-totals together as a matter of course.

Fleet validation

Thresholds were calibrated by a read-only sweep of the whole fleet (3,424 stores, 1,262 scored, 306 with a scoreable cluster), then verified against hand labels: 36/36 confirmed floods detected (13 Error, 23 Warning), 0/8 confirmed false positives flagged, 0 unexplained new flags. The sweep also showed the August 2026 campaign is running on ~36 stores, not the 3 originally known.

Caveats

Shopify only returns retained abandoned checkouts — far fewer than the checkouts actually started in a period (266 retained against ~3,200 real Checkout Started events in one six-day window we measured). That is enough to detect a cohort but the count is never a flood size. It also means the check reflects the current state: a flood that ended a week ago has aged out of the retained set and reads Success, which is correct but worth knowing when a merchant asks about a past incident.

The endpoint is the legacy REST one; GraphQL’s AbandonedCheckout exposes no landingSite, referringSite or noteAttributes, and abandonmentByAbandonedCheckoutId returns null for ordinary abandoned checkouts. If REST is withdrawn, the fallback is GraphQL minus the landing-page and cart-attribute signals — which the measured evidence does not depend on.


Shopify Markets active

See the check’s own message; it reports whether Littledata’s Markets connection is live and which markets a store runs.

Traffic from Amazon

GA4 storefront traffic from Amazon and/or orders through the Amazon sales channel, compared against a cross-store benchmark.