Comprehensive Ecommerce Attribution Stack Implementation by Marcus Hernandez Comprehensive Ecommerce Attribution Stack Implementation by Marcus Hernandez

Comprehensive Ecommerce Attribution Stack Implementation

Marcus Hernandez

Marcus Hernandez

Ecommerce Attribution Stack — From Pixel Gaps to Real ROAS

Fixed Shopify's broken attribution pipeline: real GA4 ecommerce events, server-side Meta CAPI, offline conversion import, and a dbt-powered ROAS dashboard that actually reflects where revenue comes from.

THE CHALLENGE

Most ecommerce brands running paid ads are flying blind. iOS 14.5 gutted Meta's pixel attribution. Shopify's default GA4 integration double-fires events. GCLIDs don't survive the checkout flow. The ROAS number in Google Ads and the ROAS number in GA4 disagree — often by 30–60%. Nobody knows which number to trust.
The result: campaigns that look profitable in one view look unprofitable in another. Budget decisions are made on the loudest number, not the most accurate one. Server-side solutions exist for each problem individually, but they're rarely built together into a coherent attribution stack.

THE APPROACH

Fix client-side first, then add server-side redundancy for each channel. Client-side events (browser pixel, GTM) remain the primary signal — fast, rich, contextual. Server-side (CAPI, offline import) fills the gaps created by ad blockers, consent refusal, and platform sandboxing. Deduplication via event_id prevents double-counting. The warehouse is the reconciliation layer — it sees all signals and produces the canonical ROAS.

THE BUILD

1. Shopify + GTM + GA4 Ecommerce Events

Shopify Partners dev store (EU/EUR, Bogus gateway for test purchases). GTM container (GTM-K2DLCDXP) injected via Shopify's Custom Pixel API. GA4 property (G-Y4R7G4Q93X) with Enhanced Measurement OFF — all events sent manually to prevent duplicates. 11 events implemented: page_view, view_item, add_to_cart, begin_checkout, add_payment_info, purchase, plus 5 custom engagement events. Critical fix: payment_info was firing 6× per order due to Shopify's pixel sandbox re-render cycle — deduplicated with a session-scoped guard flag. Consent mode v2 wired; page_location passing real Shopify URLs.

2. Metal Pixel + Server-Side Conversions API

Client-side Meta Pixel firing Purchase and InitiateCheckout events. Cloudflare Worker handling server-side CAPI relay — SHA-256 hashing of email and phone following Meta's normalization spec (lowercase → trim → UTF-8 → hash). fbc and fbp cookies extracted from client request and forwarded to CAPI for attribution continuity. event_id on both client and server — same ID per event prevents double-counting in Meta's deduplication window. Deployed to custom domain (www.stylists.space) with Cloudflare routing.

3. Google Ads Offline Conversion Import + Enhanced Conversions

GCLID/GBRAID/WBRAID captured via hidden form fields on lead intake. Apps Script-backed CRM Sheet (lead → appointment → sale pipeline). Two export file types: Google Ads click file (GCLID → conversion) and Enhanced Conversions for Leads file (SHA-256 hashed email + phone). GBRAID/WBRAID routed to EC-for-leads only — click file format doesn't accept app click identifiers. Key finding: Shopify's pixel sandbox blocks GCLID from reaching the purchase hit across all browser-side approaches. Offline import via order landing_site data is the only reliable Shopify → Google Ads attribution path.

4. dbt on BigQuery — Attribution Data Warehouse

dbt project on real BigQuery export (Stellapura production data — not synthetic). Staging models deduplicate raw event tables (upstream connector was writing duplicate rows — fixed at source, deduplication retained in staging as a safety net). Intermediate models: sessions_attributed (last-click, linear, position-based attribution variants), revenue_by_channel. Mart table: fct_roas_daily joining ad spend (Sheets proxy) to attributed revenue. Keyless CI via Workload Identity Federation — no service account keys in the repository. dbt docs site live on GitHub Pages.

5. Multi-Source Looker Studio ROAS Dashboard

Three-page dashboard: Website & Search (GA4 + Google Search Console blend), Paid Advertising (Google Ads + Meta via Sheets proxies), Summary/ROI. Calculated fields: ROAS (Revenue / Spend), CPL, MoM delta, platform grouping (CASE mapping session source/medium to Meta/Google/YouTube/LinkedIn/Direct/Other). Data control lets users swap GA4 property without breaking calculated fields — verified by swapping to GA4 Demo Account. UTM tracking sheet published as a public template for consistent tagging across all campaigns.

6. Klaviyo / ActiveCampaign Email Attribution

Klaviyo flows for post-purchase, abandoned cart, and win-back sequences. UTM parameters on all Klaviyo links for GA4 attribution. Klaviyo revenue data piped back to BigQuery via n8n scheduled pull — so email-attributed revenue appears in the same ROAS model as paid channels. Compare email ROAS vs paid ROAS side-by-side in Looker Studio.

7. PostHog Product Analytics + Funnel Analysis

PostHog free tier on the live brand site. Custom event taxonomy (product views, add-to-cart, checkout steps). Funnel report: visitor → PDP → add to cart → checkout → purchase. Session recordings for qualitative drop-off analysis. PostHog events bridged to GA4 via server-side relay for unified reporting. Conversion rate optimization findings documented as structured test log.

8. AgencyAnalytics — Cross-Channel Client Reporting

AgencyAnalytics connected to GA4, GSC, Google Ads, Meta Ads, Klaviyo. White-label dashboard template with custom KPIs (ROAS, CAC, LTV:CAC ratio). Automated monthly PDF report to client. Positions Marcus as a reporting layer for agencies managing multiple brand clients — turns this single build into a repeatable agency deliverable.

KEY FINDINGS

⚠ Shopify's pixel sandbox permanently blocks GCLID from the purchase event. Three different browser-side approaches tested across multiple runs — all failed. Server-side offline import via order data is the only reliable attribution path for Shopify + Google Ads
⚠ Duplicate events in BigQuery are silent and compound over time. A connector write bug was appending duplicate rows on every sync. dbt deduplication in staging caught it, but the root cause must be fixed upstream or models continuously fight the data.
⚠ GA4 saw <1% of actual traffic during the pre-consent period. Server-side pageview logs showed 8,969 visits; GA4 captured 88. Every "insight" drawn from GA4 during that window was from a 1% sample — systematically biased toward consenting users.
✓ The dbt warehouse is the only place where all attribution signals reconcile. Google Ads, Meta, GA4, and email all report different revenue numbers — the warehouse sees all of them and produces the canonical view. Without it, teams argue over dashboards instead of optimizing campaigns.

STACK

Shopify (Custom Pixel)
GTM
GA4
Meta Pixel
CAPI
Google Ads Offline Import
Enhanced Conversions
dbt
BigQuery
Cloudflare Workers
Looker Studio
Apps Script
GitHub Actions (WIF)
Klaviyo
ActiveCampaign
PostHog
AgencyAnalytics
Funnelish (VSL funnels)
Like this project

Posted Oct 21, 2026

Built a comprehensive ecommerce attribution stack for accurate ROAS reporting.