Acquisition

S3 Sensitivity Science · Company dashboard

Acquisition by channel

Spend, sessions, orders, CAC, ROAS and conversion rate per channel for the chosen Window, read from the production dataset. Unknown is a row like any other, carrying its real orders and revenue, and every row resting on fewer than five orders is marked and still shown — so a channel that does not work reads differently from a channel whose orders are not being attributed.

Window
Marketing data covers 27 May 2026 5 Aug 2026 across 12 channels

This page's coverage is wider than /company's on purpose. It runs on analytics.channel_reporting, which carries sessions and ad spend from 27 May 2026 — before the first order on 16 June 2026 — because a business buys traffic before it sells anything. /company runs on analytics.orders and ends at the last order date. So All time here opens earlier and can end a day later, and the two pages are describing the same trading with different bounds rather than disagreeing.

What tripped on this page

The acquisition flags, and only those: the same rules the panel on /company runs, filtered to the section this page shows. Each is computed over the Window above, against the same rowset the table below divides, so a card and the row it names cannot print different numbers.

WARNING 2

acquisition 166.8
Performance Max spent £166.80 with no new order to divide it by
Performance Max carries £166.80 of spend and 0 new orders over the window — 1 order in total, none of them a first — so CAC, spend ÷ new orders, has no denominator. The bar is £100 of spend.
acquisition 204.5
Paid Search - Generic CAC is £204.49
£408.98 of spend ÷ 2 new orders over the window, against a bar of £150.

These are the acquisition cards from /company, computed here over this page's Window rather than that page's. The two controls do not carry the same bounds and are not meant to: /company ends its ranges at the last order date and this page ends at the last day the marketing mart carries, so All time here opens on 27 May 2026 against 16 June 2026 there. Each panel states the window it ran over, which is what keeps two honest answers from reading as a disagreement.

Every card names the counts its rule divided and the bar it crossed, and none of them says what to do about it — that is the line ADR 0007 draws between a computed flag and generated prose. A CAC resting on a single new order is marked, not hidden: the detail line prints the denominator, the same way a row under five orders is marked and kept in the table below.


This window, blended

Every channel added together, for the Window above. These are the figures a per-channel column cannot carry: MER is only meaningful across all channels, and the blended CAC and conversion rate are what the table below decomposes.

Window: Last 30 · 7 Jul 2026 → 5 Aug 2026 30 of 30 days carried marketing data, across 12 channels.

Sales
£2,185.89
Last 30 · 7 Jul 2026 → 5 Aug 2026
shopify_total_sales, the house numerator every ratio on this page divides (ADR 0008).
Spend
£6,324.70
Last 30 · 7 Jul 2026 → 5 Aug 2026
Ad spend across every channel. It lands on its own rows in the mart and is folded in by channel, not filtered out.
MER
0.35
Last 30 · 7 Jul 2026 → 5 Aug 2026
MER is Sales ÷ spend across ALL channels, which is the only level it means anything at — so it is shown here once and never as a column in the table below.
CAC
£61.40
Last 30 · 7 Jul 2026 → 5 Aug 2026
Spend ÷ new orders (order_index = 1) — cost per FIRST order, not per order.
Conversion rate
3.29%
Last 30 · 7 Jul 2026 → 5 Aug 2026
Shopify order rows ÷ GA4 sessions, both on the same mart row. Never GA4’s own purchase event, which double-fires from 3 July 2026 and reads about twice the true rate.

MER appears once, here, and never as a column. It is roas's arithmetic — Sales ÷ spend — but the registry keeps the two as separate names because MER describes the whole business and ROAS describes a channel. A per-channel MER column would be that channel's ROAS under a name claiming to speak for everything, which is how a dashboard ends up disagreeing with itself.

Blended over this window: £2,185.89 ÷ £6,324.70 = 0.35 — every channel's Sales over every channel's spend, summed before dividing.

These tiles carry no prior-period pills. The honest-comparison rule — a comparison is shown only where the whole prior period sits inside trading history — is applied by the headline tiles on /company, against the trading history in analytics.orders. This strip is the window's blended arithmetic and the decomposition below is what the page is for, so it states its window and stops. Each tile still resolves through components/presentationState.js, so a window that narrows the order count below the five-order bar marks these figures on its own.


By channel

Channel grain, not channel group: folding Paid Search - Brand, Generic and Uncategorised into one row would hide the distinction this page exists to draw. Every ratio is summed then divided over the Window above, and a ratio with no usable denominator prints an em rule with its reason on the same row.

Orders across channels
136
Headline orders
136
=
Difference
0
Of which Unknown
41

The channel rows sum to the headline order count for the same days, with Unknown counted in — measured against analytics.orders over the same window rather than asserted, so a break in either mart shows up here as a difference instead of as a plausible wrong number.

No Results

fewer than 5 orders in the window, so every ratio on the row rests on that denominator. The row is still shown in full, in its natural position — a thin figure is marked, never hidden. 7 of 12 rows on this table carry it.

Reading the em rules. A is a rate whose denominator is zero, and the Basis column on the same row names which denominator went missing. It is never £0, never 0% and never . Performance Max is the live case on the all-time window: £287.23 of spend and no new orders at all, so cost per first order has nothing to divide by. Printing £0 there would say acquisition was free and printing would say it was infinitely expensive; the data supports neither, and only the row itself — spend beside a zero — supports anything. The same rule gives ROAS an em rule on every channel with no spend, and AOV and repeat order share an em rule on a channel with no orders. Those two figures are a worked example on the all-time window, not live values; the row above is the live one.

Why every ratio column is text, and why the table does not sort. A NULL in a numeric column renders as an empty cell, which reads as "nobody filled this in" rather than "this cannot be computed". Formatting each ratio in the fence is what lets the em rule be an em rule; the columns are right-aligned so the table still reads as figures. The cost is that a text column sorts alphabetically, which would rank £1,529.89 above £118.97, so column sorting is off here and the rows stay in the order the fence states — most orders first, Sales breaking a tie.

new_customer_conversion_rate divides by total sessions, not new sessions, and the mart's new_sessions column is deliberately not on this table. A GA4 first-visit session and a customer's first order are different populations — a first-time buyer often converts on a returning session — so dividing new orders by new sessions divides two unrelated populations. The registry says so explicitly and the column is left out rather than left available to be picked up by mistake.

Conversion rate is Shopify order rows over GA4 sessions, both taken off the same mart row. GA4's own purchase event is never used as an order count: it double-fires from 3 July 2026 and reads roughly twice the true rate.


Unknown is a row, not a residual

Unattributed orders are real orders with real revenue. They are shown as their own channel, with their own sessions, orders and Sales, rather than netted off the totals or redistributed across the channels that can be named.

Unknown carries 41 orders, 783 sessions and £494.20 in this window — 30.1% of every order on the page.

That share is the point. channel_reporting_reattributed exists in the dbt project and is deliberately not what this page reads: it carries no analytics tag, so it is never promoted to the production dataset, and reattribution is deferred on purpose (PRD044 §7). Redistribution earns its keep once there are more channels to redistribute credit between, which is not the case with nine channels carrying an order between them. Until then, Unknown as its own row keeps pressure on the mapping gap rather than smoothing it away — and it is the same count the unattributed-orders flag on /company trips on, so the two pages cannot disagree about how much of the business cannot be judged.

Nothing on this page is suppressed. Thin rows are marked and kept, Unknown is shown with its real figures, and a rate with no denominator prints an em rule with its reason. Suppression is reserved for figures that would be actively misleading (CONTEXT.md, Small-n marking), and a channel resting on one order is thin, not misleading — hiding it would remove the only evidence that the channel exists.

Data baked at

The deployed site is static with no runtime connection to BigQuery, so this rebuild is the data refresh, and the stamp above is the only on-page evidence that the numbers moved.