How I Built a Shopify Attribution Pipeline (UTM & Click IDs → Orders)
A real-world case study showing how attribution data (UTM, gclid, fbclid) was captured, persisted, and sent to Shopify orders for accurate marketing attribution. This guide walks through the architecture, implementation, and tracking strategy used in a live TinyBot client project.
Table of contents▼
Introduction
Most Shopify stores struggle with accurate attribution.
Marketing teams run campaigns across:
- ▸Google Ads
- ▸Facebook Ads
- ▸Organic traffic
But when an order is created in Shopify, the original attribution data is often lost.
In this project with a U.S. marketing agency (TinyBot), the goal was clear:
Capture attribution parameters from the first visit and attach them directly to Shopify orders.
This allows the agency to know exactly which campaign generated each purchase.
The Problem
When users land on a Shopify store, attribution data exists only in the URL parameters.
Example:
?utm_source=google&utm_medium=cpc&utm_campaign=summer_sale&gclid=123abcBut Shopify's default system has problems:
- UTM parameters disappear after navigation
- Returning users lose attribution data
- Orders don't always contain the original marketing source
- Multi-step checkout breaks attribution
For marketing agencies managing paid ads, this creates incorrect reporting and wasted budget decisions.
Strategy: Capture → Persist → Attach to Order
To solve this, I built a three-layer attribution system.
Layer 1 → Capture Attribution Data
When the user lands on the website, we capture:
- ▸utm_source
- ▸utm_medium
- ▸utm_campaign
- ▸utm_content
- ▸utm_term
- ▸gclid
- ▸fbclid
These values are stored in browser localStorage
Attribution Capture & Persistence Script
Instead of storing only UTM parameters, the tracking system captures multi-platform click IDs, browser cookies, and campaign parameters, then persists them inside localStorage and sends them to Shopify cart attributes.
This allows attribution data to survive:
- ▸page navigation
- ▸returning visitors
- ▸multi-step Shopify checkout
The script is injected directly into the Shopify theme:
Location
Shopify Admin
→ Online Store
→ Themes
→ Edit Code
→ theme.liquid
→ Insert after <head>What Data the Script Captures
1. Ad Platform Click IDs
These identifiers allow revenue to be traced back to ad platforms.
Google Ads → gclid, gbraid, wbraid
Meta Ads → fbclid
TikTok → ttclid
Microsoft Ads → msclkid
LinkedIn → li_fat_id
Pinterest → epik
Snapchat → sc_click_id
Twitter/X → twclid
Reddit → rdtclid
Taboola → tblci
Outbrain → ob_click_id2. Browser Tracking Cookies
Some platforms create first-party cookies used for attribution.
_fbp → Meta browser identifier
_fbc → Meta click identifier
_ttp → TikTok tracking cookie3. UTM Campaign Parameters
Standard campaign tracking parameters are also captured.
utm_source
utm_medium
utm_campaign
utm_term
utm_content
utm_id
utm_source_platform
utm_creative_format
utm_marketing_tacticThe Attribution Script
(function () {
function getParam(name){
try { return new URLSearchParams(location.search).get(name); }
catch(e){ return null; }
}
function getCookie(name){
try{
var m = document.cookie.match(
new RegExp('(?:^|; )'+name.replace(/[$()*+./?[\\\]^{|}-]/g,'\\$&')+'=([^;]*)')
);
return m ? decodeURIComponent(m[1]) : null;
} catch(e){ return null; }
}
function setLS(key,obj){
try{ localStorage.setItem(key, JSON.stringify(obj)); }
catch(e){}
}
function getLS(key){
try{
var v = localStorage.getItem(key);
return v ? JSON.parse(v) : null;
} catch(e){ return null; }
}
function merge(a,b){
a = a || {};
Object.keys(b || {}).forEach(function(k){
if(b[k] !== null && b[k] !== undefined && b[k] !== ""){
a[k] = b[k];
}
});
return a;
}
})();Attribution Persistence Strategy
The script uses localStorage instead of cookies for persistence.
Why?
| Method | Limitation |
|---|---|
| Cookies | Can be blocked or overwritten |
| HttpOnly cookies | Not readable by JavaScript |
| URL parameters | Lost after navigation |
| localStorage | Reliable client-side persistence |
The data is stored as a structured object:
{
"click_ids": {
"gclid": "abc123",
"fbclid": "xyz456"
},
"cookies": {
"_fbp": "fb.1.123456789"
},
"utm": {
"utm_source": "google",
"utm_campaign": "summer_sale"
},
"meta": {
"landing_url": "https://example.com/?utm_source=google"
}
}Sending Attribution to Shopify Orders
Once attribution is stored, the script flattens important fields and sends them to Shopify cart attributes.
This ensures the values are attached to the order once checkout completes.
fetch('/cart/update.js', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
attributes: flatAttributes
})
});Example attributes stored in Shopify:
utm_source : google
utm_medium : cpc
utm_campaign : summer_sale
gclid : Cj0KCQj...
landing_url : https://example.com/?utm_source=googleThese attributes appear directly inside the Shopify order admin panel.

Why This Architecture Works
This approach solves multiple attribution problems simultaneously.
| Problem | Solution |
|---|---|
| UTM disappears after navigation | localStorage persistence |
| Multi-platform ads | multi click-ID capture |
| Checkout attribution loss | Shopify cart attributes |
| Cross-platform reporting mismatch | consistent attribution storage |
For marketing agencies running campaigns across multiple platforms, this creates a reliable attribution pipeline from click → order.