Analytics

The Attribution Rebuild We Do on Every DTC Engagement

A step-by-step walkthrough of exactly how we rebuild attribution for DTC brands — the tables, the joins, the deduplication logic. Not theory. The actual process.

10 min read
By SearchTuners
Illustration for The Attribution Rebuild We Do on Every DTC Engagement

The problem every DTC brand has: Google says the ad spend generated $1.2M in revenue. Meta says $890K. TikTok says $340K. Their combined reported revenue is $2.43M — but the actual monthly revenue from Shopify is $1.6M. Somewhere along the way, everyone counted the same purchases multiple times, and none of the numbers ties back to reality.

This is the process we run on every new DTC engagement to fix it. It is not conceptual. It is a specific data pipeline: order data becomes the source of truth, click IDs get matched against orders, and every purchase is attributed exactly once. Here is how it works end to end.

Step 1: Establish Order Data as the Ground Truth

Everything starts with a clean feed of Shopify (or your equivalent) order data. Not a report from Shopify Analytics — the actual orders table, pulled via API or via a data warehouse connector. You need: order ID, timestamp, revenue, customer email, and — critically — the landing page the customer first hit before ordering (or the referrer captured on first visit).

For most Shopify stores, this data is available via the Shopify Admin API or through a tool like Fivetran syncing into BigQuery/Snowflake. If your marketing team does not have access to the raw orders table, that is the first problem to fix. Everything else depends on it.

Step 2: Capture Click IDs at First Landing

When a user clicks a Google ad, the URL gets a GCLID parameter. Meta uses FBCLID. TikTok uses TTCLID. Microsoft uses MSCLKID. These are unique click identifiers — the platform's way of matching a specific click to a specific outcome.

The critical step: capture these IDs the first time a user lands on your site, and persist them for the entire session — and ideally across sessions in a first-party cookie. Most Shopify stores capture them at checkout but not at first landing, which means all the mid-funnel touchpoints are lost.

  • Use a small JavaScript snippet in your theme's <head> to read URL parameters on landing.
  • Store all four click IDs (GCLID, FBCLID, TTCLID, MSCLKID) in a first-party cookie with a 90-day expiry.
  • On checkout, write whichever click IDs are present into hidden fields on the Shopify order object using the order's note_attributes.
  • Configure your Shopify theme to preserve these note attributes through the entire checkout, including if the user uses Shop Pay or express checkout.

Step 3: Match Orders Back to Click IDs

You now have a dataset that looks like:

  • orders.order_id, orders.revenue, orders.gclid, orders.fbclid, orders.ttclid, orders.msclkid, orders.first_touch_utm_source, orders.timestamp

For each order, exactly one channel gets attribution. The rule we use: last non-direct click wins. If GCLID is present, Google gets the order. If not but FBCLID is present, Meta gets it. If neither but there is a UTM source of 'organic', organic gets it. Direct traffic (no click ID, no UTM) is attributed to whichever was the most recent paid touch in the last 90 days — usually pulled from a session-level events table.

The reason last non-direct wins is not because it is the "correct" attribution model. It is because it produces a single, consistent, deduplicated attribution that no platform can double-count. Data-driven and multi-touch models are useful for strategy, but for the ROAS-per-channel number you send to Google and Meta as feedback, last non-direct is what makes the numbers reconcilable.

Step 4: Send Cleaned Conversions Back to the Platforms

This is where the rebuild pays off. Instead of letting Google and Meta each track their own conversions independently (which produces double-counting), you send them your deduplicated version. Only orders attributed to Google get sent to Google Ads. Only orders attributed to Meta go to Meta.

For Google Ads: Enhanced Conversions for Web + Offline Conversion Import

Enhanced Conversions for Web catches purchases in real time but is still client-side. To get server-side accuracy, use Offline Conversion Import: upload a CSV (or use the API) with GCLID + conversion value + timestamp for each attributed order. Do this daily. Google will match the GCLID back to the original click and update its bidding signals with the correct value.

For Meta: Conversions API (CAPI)

Set up CAPI via a first-party server (either through Shopify's native Meta pixel + CAPI integration or through a custom endpoint). Send purchase events with the FBCLID and hashed email/phone. Do not double-fire the client-side pixel and CAPI without deduplication — set an event_id that matches between them so Meta discards the duplicate.

38%
Median reduction in reported ad revenue
Post-rebuild vs. sum of platform-reported
11%
Increase in actual acquisition-attributable revenue
Correctly attributed to their true source
4-8w
Time for the rebuild to fully compound
Bidding algorithms need this long to recalibrate

What Changes Once the Rebuild Is Live

The reported ROAS for every channel initially drops — often significantly. Google that was reporting 6.2× ROAS now shows 4.4×. Meta that was reporting 4.1× shows 3.0×. TikTok that was reporting 5.5× shows 1.8× because it turns out TikTok was picking up a lot of last-click credit for retargeted purchases that were originally driven by other channels.

This is the correct baseline. From here, actual optimization is possible. Google is now optimizing on real Google-driven revenue. Meta is optimizing on real Meta-driven revenue. Budget shifts made based on this data actually move the P&L, not just the dashboards.

This whole process takes 5-10 business days to implement cleanly and 4-8 weeks for the bidding algorithms to fully recalibrate. Most agencies do not do this work because it does not produce a good-looking chart in a monthly report. What it does produce is durable acquisition performance that survives platform algorithm changes, iOS updates, and cookie deprecation.