Shopify Custom Reports: Turning GA4 and Sales Data Into Decisions, Not Dashboards
Store owners do not need another pretty dashboard — they need to know which decision to make. How I build custom Shopify reports joining GA4, order data and catalog exports into merchandising and upsell calls.
Nobody needs another dashboard
I have never once been asked for a dashboard and actually needed to build one.
What people ask for is a dashboard. What they need is an answer to a question they have not phrased yet: which products should be in the hero slot next month? Is the upsell app earning its fee? Why did revenue drop 8% when sessions went up?
A dashboard answers none of those. It displays numbers and leaves the reasoning to a human who is already busy. A custom report answers one question, ends in a recommendation, and gets thrown away when the decision is made.
This is how I build them, and why it is the part of ecommerce engineering that almost nobody offers.
Why store analytics lie by default
Before any report is trustworthy, three things have to be true, and on most stores none of them are.
1. Your channel data is not fragmented. I found an account where Klaviyo's utm_source was set to resolve to the list or segment name. Every send produced a unique source value. GA4 attributed every click correctly and then never aggregated them — the email channel had shattered into dozens of one-off rows, each too small to notice.
Email looked like a rounding error. It was one of the biggest channels. The fix is static utm_source, utm_medium=email, and detail carried in utm_campaign.
2. Your tag is actually installed, everywhere. A second storefront in that same operation had no analytics tag at all on its theme, and its email platform had UTM tagging entirely switched off. Two independent failures, both required to fix, and fixing only one changes nothing. Always verify with view-source, not with a settings screen.
3. You know which numbers are reporting gaps and which are lost money. In that same audit, revenue was being captured perfectly inside Klaviyo via Shopify's Placed Order metric the whole time. The GA4 hole was a reporting problem. A wholesale welcome flow was doing about US$32.7K per 30 days that GA4 could not see.
Conflating those two causes panic and bad decisions. Say it explicitly in the report: this money exists, we just cannot see it here, and here is where it is visible.
The join that makes reports useful
Shopify and GA4 each know half the story.
- Shopify knows what was ordered, by whom, at what margin, with what tags, from what catalog state.
- GA4 knows how they arrived, what they looked at, and what they did not buy.
Neither is enough on its own. The reports that actually change behaviour come from joining them — usually a Shopify order/product export plus a GA4 export, joined on product handle or SKU, then aggregated the way the decision needs rather than the way either tool defaults to.
My working stack is intentionally dull: Shopify or Matrixify export → CSV → Python (pandas) or DuckDB → a small table and three sentences. No warehouse until there is a reason for a warehouse.
DuckDB in particular is underrated for this. It queries CSV files directly, so a catalog audit is one query against an export with no ingestion step.
-- Active, in stock, and not buyable on the online store
SELECT "Variant SKU", "Title", "Variant Inventory Qty"
FROM read_csv_auto('products_export.csv')
WHERE "Top Row" = true
AND lower("Status") = 'active'
AND "Published" = false
ORDER BY "Variant Inventory Qty" DESC;
That query, on a real store, returned 164 products across two storefronts — 86 and 78 — that were active, correctly priced, in stock, and completely unbuyable. 35 were carrying inventory. One had 5,469 units sitting idle.
Nobody would ever have found those by looking at a dashboard. Revenue charts do not show you the product that could not be bought.
One caveat I always attach: the Published column reflects only the Online Store channel. A true multi-channel publication audit needs the Admin API publications query.
Reports that produced actual decisions
The URL-to-traffic map. A full inventory of roughly 2,072 URLs per store — about 4,144 across both — with page type, title and last-modified date, joined against organic performance: traffic per month, keyword count, traffic share, top query with volume and position, and primary intent, per URL.
Decisions it produced: which pages a migration must redirect first; which collection pages deserve content investment; and a "ranking but not in inventory" list of 33 URLs earning organic traffic that nobody knew existed — including legacy product URLs from a discontinued material line and a bare http:// homepage. Those are exactly the pages a replatform quietly loses.
The page-two report. High-volume queries sitting at positions 11–19. Not a metric — a work queue, sorted by expected traffic gain. It answers "what should I write next month" in one sorted column.
Catalog health as a recurring audit. Missing required metafields, missing compare-at prices (a migration artifact — the old platform had no such field), image counts below the retail-channel minimum, products with no collection membership, variant option axes used inconsistently. Each of these is a one-line filter over an export and each one, left alone, degrades a feed somewhere downstream.
Retail readiness by attribute. For syndicated catalogs, a completion score per channel. The trick is reading it as a diff, not a grade: 331 of 361 does not mean "94% good," it means 30 specific SKUs did not map, and the cause is almost always one product family whose asset filenames follow a different convention. The report's output is thirty SKUs, not a percentage.
Flow-level revenue per recipient. After a Klaviyo rebuild, seven-day flow revenue broke down as roughly $212 per recipient on the cart reminder, $109 on browse abandonment, and $80 on the checkout reminder. Revenue per recipient — not total revenue — is what tells you which flow to expand and which to leave alone, because total revenue just tells you which segment is biggest.
The operational spreadsheet is a legitimate deliverable
Not every report should be a report. Sometimes the deliverable is a spreadsheet that replaces a manual process, and engineers are snobby about this to their own cost.
One operation I inherited ran on an 18 MB, 48-tab Excel workbook that computed sellable quantity for seven channels. It was single-user, unversioned, unscheduled and unauditable — and it correctly ran a real business for years.
Replacing it was worth doing. But the intermediate step that delivered value in week one was not the pipeline — it was a read-only reporting layer over the same data, so people could finally answer "why is this SKU zero on Amazon?" without opening the workbook and taking the file lock.
Ship the answer before you ship the architecture.
What a good custom report looks like
Every report I hand over has the same four parts:
- The question, in one sentence, in the client's words.
- The table. Usually fewer than 50 rows. If it is longer, the question was too broad.
- The recommendation. What I would do, stated as an action, not an observation.
- The caveat. What this data cannot tell you, and what would be needed to answer that.
The last one is what makes the first three trustworthy. A report with no stated limits is a report someone will over-extend into a decision it cannot support.
And the format is deliberately cheap: a table and three sentences, delivered in whatever the client already reads. Not a BI tool they have to log into. The best report is the one that gets read on a phone between meetings and changes what happens that afternoon.
Why this matters commercially
Most people selling Shopify work sell themes. Almost nobody sells the ability to look at a store's own data and say what to do about it.
That is the difference between a Shopify developer and an ecommerce operations engineer — and it is where the interesting problems, and the interesting contracts, actually are. The catalog is a database, the storefront is a search system, the marketing stack is a pipeline, and all three produce data that nobody is reading.
Start reading it.
I build custom Shopify reporting — GA4 joined with order and catalog data, Python catalog-health tooling, and operational spreadsheets that replace manual work. See [Shopify development services](/shopify-expert) or [hire a Shopify developer](/hire-shopify-developer).
Direct: [WhatsApp +55 11 98851-2788](https://wa.me/5511988512788) · [contato.matheusabrahao@gmail.com](mailto:contato.matheusabrahao@gmail.com)
Need a senior engineer who thinks like an operator?
I take on a small number of Shopify operations and senior engineering engagements each quarter. If your store needs catalog hygiene, technical SEO, performance, or marketing automation done right — let's talk.
Continue reading
Shopify Canonical URLs: The Duplicate Content Trap in Collections and Filters
How Shopify canonical URLs actually work, why collection-scoped product URLs and filter parameters multiply your index, and the theme-level fixes that hold.
Shopify Schema Markup: What Actually Earns Rich Results Now
FAQ rich results are gone. What still earns them: the structured_data Liquid filter, Product vs ProductGroup, and the required merchant listing fields.