Affiliate Tracking on Shopify: A Guide And Things To Watch Out For
Note: Some details of the process listed below have changed. In particular, ReferDigital now uses Tagely to track affiliate traffic and conversions. As a result, the ReferDigital pixel has now been replaced by the Tagely tracking pixel and its associated events. To set these up, please follow the instructions in your ReferDigital account after you set up your campaigns. Also see this updated tutorial: Installing Tagely and ReferDigital on Shopify Sites: An Updated Guide And Things To Watch Out For
If you’re running your ecommerce store on Shopify, you might be wondering how to set up external affiliate marketing platforms such as ReferDigital to work with your Shopify store. This guide is for you.
Affiliate tracking typically requires the use of a piece of code called a tracking pixel, which you install on your website – your ecommerce store in this case. Depending on your choice of affiliate tracking platform, the tracking pixel may need to be installed on all pages of your website, or just on the conversion page where a completed action you wish to track occurs. In the case of an ecommerce store, this would be the page displayed to users when a purchase is completed, the purchase being the action you’d like to track. Shopify calls this the Order Status page.
To demonstrate, we’ll be using ReferDigital as the affiliate tracking platform in this post The concepts and gotchas to watch out for described here are however applicable to any other affiliate tracking platform as well.
Firstly, let’s start with Shopify’s own recommended procedure:
That’s the guide Shopify provides to setting up affiliate platforms and similar scripts such as analytics ones to work with Shopify, tracking conversions in your Shopify store and reporting them back to the platforms via the tracking pixels you place on the order status page. If you haven’t read through it yet, this would be a good time to do so. And note the warning at the top:
Note that this is very much the case – if you run into any issues whatsoever when implementing your tracking pixels, Shopify support will simply direct you to hiring an expert rather than attempting to solve the issue themselves. How do we know? We’ve tried asking them when we ran into issues and that’s what they came back with. So we went ahead and figured things out ourselves, and hence this blog post with our learnings.
Jumping right into the meat of things, here’s the crux of the article:
Liquid is Shopify’s own templating engine, described in detail here: https://shopify.dev/api/liquid. The example above is of a generic tracking pixel, which requires the total price of the order, a unique order ID, and the order’s currency to be passed back to the tracking platform via the tracking pixel. Shopify’s solution is to use the shop Liquid object and the order Liquid object to accomplish this task. This may not be obvious at first glance, but {{ order_number }}
is really shorthand for {{ order.order_number }}
, {{ total_price | money_without_currency }}
is shorthand for {{ order.total_price | money_without_currency }}
and {{ currency }}
is shorthand for {{ shop.currency }}
. According to Shopify, these objects are available in the order status page and when Shopify encounters them when rendering the page, they’ll fill in the tracking pixel with the actual values as required for passing back to the affiliate platform.
So far so good. Except of course that if you try this you’ll run into a couple of major issues and it won’t work. Let’s dig in.
Firstly, let’s make this a real-world example with a real-world tracking pixel. We’ll use ReferDigital’s tracking pixel for shopping cart campaigns, which are the most suitable campaigns for tracking shopping cart conversions like Shopify’s. For more information setting those campaigns up on ReferDigital’s side, you can read this tutorial: https://trackingtalk.com/setting-up-lead-generation-and-shopping-cart-campaigns-on-referdigital/.
As described in that tutorial, the tracking pixel for a shopping cart campaign on ReferDigital looks like this:
<img style="display:none;" src="https://referdigital.com/t/track/51/ORDER-VALUE/TRANSACTION_ID/OPTIONAL_TEXT/VANITY_CODE">
Note that you would have a different number than 51 in your case – 51 is the campaign ID on ReferDigital. ReferDigital would prefill this number in for you when it generates the tracking pixel after you set up your campaign, so you’ll know what it is.
The implementation instructions on ReferDigital go on to say:
This should be placed between the opening and closing body tags on your website page that thanks the customer for completing a purchase.
Your website needs to replace the fields in CAPS with the appropriate values:
ORDER-VALUE should be replaced with the actual shopping cart value including decimal point and cents but no dollar signs. Eg. 58.34. This would mean $58.34 if your campaign currency is USD.
TRANSACTION_ID is mandatory and should be a unique url-encoded ID which identifies this transaction in your system.
OPTIONAL_TEXT is any further text that you want to record with this referral, url-encoded.
VANITY_CODE pass along any vanity code, if a vanity code applies. Must be url-encoded. OPTIONAL_TEXT must be set to some value to pass a VANITY_CODE.
We won’t need the OPTIONAL_TEXT and VANITY_CODE fields for the purposes of this example, and ReferDigital stores the campaign currency when the campaign is set up, so the currency doesn’t need to be passed back for each conversion with the tracking pixel. So the only applicable Liquid objects we’ll need from Shopify’s tutorial are {{ total_price | money without currency }}
for the ORDER-VALUE field and the {{ order_number }}
field for the TRANSACTION_ID.
Going ahead and substituting these, you would reasonably conclude at this point that the tracking pixel would need to be as follows:
<img style="display:none;" src="https://referdigital.com/t/track/51/{{ total_price | money without currency }}/{{ order_number }}">
And where should you put that in? Shopify’s tutorial says the Additional Scripts text box, so that’s where it should go:
So we copy the tracking pixel we’ve built and populated as above in to that Additional scripts text box under Settings > Checkout in our Shopify store, save it, and wait for the conversions to come in. Then we go to ReferDigital and see the referral history to see what we’re receiving there. (Note that referrals would only be tracked there if they’re conversions actually due to an affiliate, as you’d expect. Conversions due to other traffic wouldn’t show up.) And that’s where you’d notice the problems. There’s two of them we noticed to be exact:
- The most obvious one – sometimes the fields we’ve populated –
order_number
andtotal_price
– don’t report back correctly from Shopify and are left blank. This one was a bit tough to diagnose and fix. The hardest bugs are the intermittent ones. When things are consistently wrong, that actually makes them easier to fix. - Going from the occasions on which the
order_number
does report back, sometimes there’s multiple entries for each order in the referral history, with different IP addresses. (ReferDigital would block referrals with the same IP addresses at similar times as being likely duplicates, but would allow them through as valid if they’re coming from different IP addresses.) So, another nasty intermittent bug.
Problem #2 is easier to fix because it’s documented as a potential pitfall in the Shopify. It stems from the fact that the order status page in Shopify isn’t just loaded at the time of conversion. It’s also referred back to by Shopify when, as the name implies, users want to check the status of their orders, to see whether it shipped, what the tracking number is, etc. So this page could be loaded several times for each order (i.e. with the same order_number
), and the page loads often come from different devices with different IP addresses. For example, users could place the order on their desktop computers at home over their home internet connections, and later check the status on their mobile phones on their cellular connections.
Here’s the fix for this one – it’s documented in the Shopify tutorial too in a Tip box:
It turns out that, more than a tip, this is really an essential thing to do if you don’t want to end up with a referral history full of duplicates. Which you certainly don’t want, or you’d end up owing affiliates multiple commissions for the same transaction. As per the second tutorial linked to there in that tip, the solution is inserting more Liquid code to tell Shopify to load the external tracking pixels on just the first time the order status page is loaded:
The key here is that we now used the first_time_accessed
variable to check whether this, in fact, the first time the order status page is accessed, and make loading the tracking pixel(s) conditional on its value. In the section where the conversion scripts you want to run only once go, you’d place the tracking pixel, i.e. ReferDigital’s tracking pixel for this example.
Doing this effectively solves problem #2. Now we only have a single referral showing up in the history, as required. Good.
What about problem #1? That one’s not documented anywhere in the Shopify tutorials as far as we can see, and it turns out the Shopify tutorial that recommends using the order Liquid object on the order status page with external tracking scripts is somewhat flawed. You have to dig deep into the Liquid documentation to find out why. The tricky part is that there’s no hint of a problem if you just look at the order_number
attribute under the order Liquid object documentation. For example, here’s the description of order_number
there:
Everything seems fine and dandy there. But now take a look under the checkout object documentation:
This certainly sheds more color on what’s going on. It turns out that depending on the payment provider, the order object might not actually exist yet when the order status page is first accessed. In other words, user payments, through credit cards and such, sometimes take time to process, and when the order status page first loads that processing may not yet be complete – and often isn’t in fact. This is a problem for us, since we’re now using the first time that page is loaded as the time we load the tracking pixel. And note that attempting to modify the conditional Liquid code we’ve now inserted in the Additional scripts box to load the pixel on the second or third time to get around this problem wouldn’t always work – there’s no guarantee the user would ever return to this page again after the first time for any particular order.
So what’s the answer to this particular issue? It turns out the checkout object is in fact always available on the order status page, and that’s the one to use. The attributes for this object contain much the same information as the order object, except that we have to steer clear of using checkout.order_number
, which as we’ve seen isn’t always available.
Here’s the tracking pixel using the checkout object attributes instead:
<img style="display:none;" src="https://referdigital.com/t/track/51/{{ checkout.total_price | money without currency }}/{{ checkout.id }}">
Note that instead of the order_number
attribute, we’re using the checkout.id
attribute instead. This is a long and unique transaction ID attached to each transaction in Shopify. It differs from the order_number but serves a similar purpose – to uniquely identify the transaction in ReferDigital’s referral history in a way that it can be cross-checked against the transaction in Shopify.
And this works! Problems #1 and #2 are both solved, and you’re off to the races. Happy tracking!