Thirteen storefronts on the same Netorigo Ltd. tenant. The shared catalog, the shared checkout, the shared finance — all of it comes with a cost: how do you measure per-domain conversion separately without running 13 separate Plausible instances? The answer is the X-Storefront-Domain header and one analytics_events table from which every question can be answered.
The problem in other SaaS tools
A classic single-tenant analytics solution (Plausible, Fathom, GA4) measures per property. With 13 storefronts you buy 13 properties, configure 13 dashboards, and two months later no one looks at them. The comparison — "How does Nortinia perform versus Mediaorigo?" — devolves into CSV exports and three Excel cells.
We needed something different: one data table, many dimensions.
The header as a dimension
Every storefront knows its own domain (from Next.js's host header or a STOREFRONT_DOMAIN env var). Every analytics event sends an X-Storefront-Domain: nortinia.com header to the BE. The BE controller reads it, validates it (whitelist: the tenant's 13 known domains), and stores it in the storefront_domain column of the analytics_events row.
Now a single SQL query handles everything:
SELECT
storefront_domain,
COUNT(*) FILTER (WHERE event_type = 'page_view') AS views,
COUNT(*) FILTER (WHERE event_type = 'add_to_cart') AS adds,
COUNT(*) FILTER (WHERE event_type = 'order_completed') AS orders
FROM analytics_events
WHERE tenant_id = 'netorigo-kft'
AND created_at >= NOW() - INTERVAL '30 days'
GROUP BY storefront_domain
ORDER BY orders DESC;
One GROUP BY produces the 13-row comparison table. The next query can break it down by (storefront_domain, traffic_source) — something that would take three separate exports in a classic SaaS analytics tool.
What's in the table
The analytics_events table has 24 columns in total, but the most important ones are:
id(uuid)tenant_id(always mandatory)storefront_domain(the key dimension)session_id(anonymous cookie ID)event_type(page_view,add_to_cart,checkout_start,order_completed,rfq_submit,voice_session_start, etc.)event_data(JSONB: product SKU, price, referer URL, etc.)user_id(optional — only if logged in)created_atcountry_code(from Cloudflare header)device_type(mobile/tablet/desktop)path(which URL the buyer was on)
13 storefronts generate about 8,000 events per day on average (modest scale — small company, B2B focus), so ~3M rows per year. PostgreSQL handles that easily with a BRIN index on created_at plus a BTREE on (tenant_id, storefront_domain, event_type). Partitioning only becomes necessary above 50M rows — many years away.
What the CMO typically asks
Our marketing team and tenant CMO clients typically ask these questions, each of which is answerable by a single SQL (or in a single dashboard):
- "Which storefront had the best Black Friday conversion?" —
WHERE created_at BETWEEN '2025-11-28' AND '2025-12-01',GROUP BY storefront_domain, look at theorders/viewsratio. - "Nortinia.com mobile vs. desktop conversion?" —
WHERE storefront_domain = 'nortinia.com',GROUP BY device_type. - "Total tenant-level conversion in the last 30 days?" —
WHERE tenant_id = 'netorigo-kft', cross-domain. - "Which storefront gets the most voice sessions?" —
WHERE event_type = 'voice_session_start',GROUP BY storefront_domain. - "Which product is sold on three or more storefronts at once?" —
JOIN products,GROUP BY product_id HAVING COUNT(DISTINCT storefront_domain) >= 3.
The difference from Plausible
The Plausible / GA4 advantage is a single dashboard that opens in 5 seconds. The disadvantage of our model is precisely that there's no out-of-the-box pretty dashboard — an internal analytics tool (Metabase, or the Netorigo Admin's "Reports" tab) provides the visualization. The upside is: any question can be answered with 5 minutes of SQL, not just the ones the SaaS vendor pre-built.
Closing
13 storefronts + one header + one table + one GROUP BY = all multi-storefront analytics problems solved. X-Storefront-Domain is a 26-character header, but it carries the entire value proposition for every tenant joining the ecosystem.