Every affiliate publisher hits the same wall. Your network dashboard says you earned $4,180 last month, GA4 says you earned $0, and nothing in either report tells you which article, keyword or traffic source actually produced the sale. That gap is the affiliate attribution blind spot, and it is the reason most bloggers scale the wrong pages.
This guide shows you exactly how to track affiliate revenue in Google Analytics (GA4), step by step: tagging outbound partner links, firing custom click events, passing a sub ID that survives the redirect, and streaming commission data back into your property so revenue sits next to the session that created it. There’s a good explainer over at partnerize.com.
Why Your Affiliate Dashboard and Google Analytics Never Match
Before touching a tag, understand what is actually breaking. GA4 is not “wrong”, it simply loses visibility the second a visitor leaves your domain.
| Cause of the mismatch | What happens | Fix covered below |
|---|---|---|
| Cross-domain gap | The merchant is a third-party domain, so your GA4 cookie stops at the click | Sub ID bridge (Step 4) |
| Delayed conversions | Cookie windows of 30 to 90 days mean the sale lands weeks after the session | Commission import (Step 6) |
| Reversed and pending orders | Networks show pending amounts that later get cancelled | Status field + refund events |
| Ad blockers and consent refusals | Clicks fire at the redirect layer but never reach GA4 | Server-side or redirect logging |
| Different counting logic | GA4 counts events, the network counts approved transactions | Reconciliation table (Step 8) |
Realistically you should target 85 to 95 percent match between GA4 and your network, not 100 percent. Anyone promising perfect parity is selling something.

The Three-Layer Framework
Affiliate tracking in GA4 only works when three layers talk to each other:
- Click layer: a custom event that records who clicked what, where, and on which page.
- Identity layer: a sub ID (also called clickref, sid, u1, afftrack) that carries your GA4 client ID and session ID into the network.
- Revenue layer: commission data pushed back into GA4 through the Measurement Protocol or joined in BigQuery.
Skip layer two and you will forever have clicks with no revenue. Skip layer three and you will forever have revenue with no source.
Step 1: Turn On Enhanced Measurement (And Know Its Limits)
GA4 already collects a click event for outbound links if enhanced measurement is enabled. An extended version exists for anyone curious.
- Go to Admin > Data streams and open your web stream.
- Click Enhanced measurement and enable Outbound clicks.
- Save.
You now get click events with the parameters link_url, link_domain, link_classes and outbound = true.
Why this is not enough:
- It fires on every outbound link, including sources you cite and social profiles, so affiliate data is buried in noise.
- You cannot tell whether the click came from a comparison table, a sidebar banner or an in-text mention.
- If your links go through a cloaker such as
yoursite.com/go/brand/, the click is internal and enhanced measurement ignores it completely. - No revenue is attached, ever.
Treat it as a baseline sanity check, then build a proper event on top.

Step 2: Mark Your Affiliate Links So They Are Machine-Readable
Consistency here saves hours later. Pick one convention and apply it site-wide:
<a href="https://www.merchant.com/product?aff=yourid"
class="aff-link"
data-aff-partner="merchant-name"
data-aff-network="awin"
data-aff-placement="comparison-table"
rel="sponsored nofollow noopener"
target="_blank">Check current price</a>
Three things matter:
- A shared class (
aff-link) so one trigger catches all links. - Data attributes for partner, network and placement. Placement is the parameter that will later tell you that your comparison tables convert four times better than your intro paragraphs.
- rel=”sponsored” because Google requires it and because it doubles as a fallback selector.
If you use a link cloaker plugin, add the class to the plugin’s global link settings so every /go/ link inherits it automatically.
Step 3: Fire a Custom affiliate_click Event in Google Tag Manager
A generic click event is useless for analysis. Build a dedicated one.
3.1 Create the variables
In GTM, create three Data Layer or DOM Element / Custom JavaScript variables that read your attributes. The quickest method is an Auto-Event Variable of type Element Attribute:
| Variable name | Type | Attribute |
|---|---|---|
| aff – partner | Auto-Event Variable | data-aff-partner |
| aff – network | Auto-Event Variable | data-aff-network |
| aff – placement | Auto-Event Variable | data-aff-placement |
3.2 Create the trigger
Trigger type Click – Just Links, with “Wait for Tags” enabled (2000 ms) and the condition:
Click Classes contains aff-link
If you do not control the markup, use Click Element matches CSS selector with a[rel*="sponsored"], a[href*="/go/"].
3.3 Create the GA4 event tag
Event name: affiliate_click. Recommended parameters:
| Parameter | Value | Why it matters |
|---|---|---|
| affiliate_partner | {{aff – partner}} | Compare merchants side by side |
| affiliate_network | {{aff – network}} | Match against network reports |
| affiliate_placement | {{aff – placement}} | Find your highest earning link positions |
| link_url | {{Click URL}} | Debugging and deep-link checks |
| page_location | {{Page URL}} | Article-level revenue attribution |
| aff_subid | {{aff – subid}} | The key that joins GA4 to your network |
Publish, then verify in DebugView that the event fires once per click, not twice (a duplicate usually means both enhanced measurement and your custom tag are counted, which is fine as long as you report on affiliate_click only).
3.4 Register the custom dimensions
Parameters are invisible in reports until you declare them. Go to Admin > Custom definitions > Create custom dimension and register affiliate_partner, affiliate_network, affiliate_placement and aff_subid as Event-scoped dimensions. Data starts collecting from that moment forward, it is not retroactive, so do this first.
Finally, mark affiliate_click as a key event (the GA4 name for what used to be called a conversion) under Admin > Key events. This unlocks it in attribution reports.
Step 4: Pass a Sub ID So the Network Can Send Data Back
This is the step almost every tutorial skips, and it is the one that actually closes the loop. Nearly every network accepts a free-text tracking parameter that is echoed back in the transaction report.
| Network | Sub ID parameter |
|---|---|
| Awin | clickref (plus clickref2 to clickref6) |
| Impact | subId1, subId2, subId3 |
| CJ Affiliate | sid |
| ShareASale | afftrack |
| Rakuten Advertising | u1 |
| Amazon Associates | ascsubtag (SiteStripe tracking ID as fallback) |
| Digistore24 | cid / tid |
| PartnerStack, Refersion, in-house programs | Usually sub_id or ref, check the partner docs |
Inject your GA4 identifiers into that parameter on click:
<script>
gtag('get', 'G-XXXXXXXXXX', 'client_id', function(clientId) {
gtag('get', 'G-XXXXXXXXXX', 'session_id', function(sessionId) {
var subid = clientId + '_' + sessionId;
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ event: 'aff_subid_ready', aff_subid: subid });
document.querySelectorAll('a.aff-link').forEach(function(link) {
try {
var u = new URL(link.href);
u.searchParams.set('clickref', subid); // rename per network
link.href = u.toString();
link.setAttribute('data-aff-subid', subid);
} catch (e) {}
});
});
});
</script>
Practical notes from real deployments:
- Most networks cap the sub ID at 50 to 100 characters. A client ID plus session ID is around 30, so do not also append the full URL. Use a short page slug or a numeric post ID instead.
- Avoid personal data. A client ID is a pseudonymous cookie value, an email address is not allowed.
- Run the script after consent is granted if you operate under GDPR, and let unconsented users click a clean link.
- If you use a cloaker, append the sub ID at the redirect level in PHP so it works even when JavaScript is blocked.

Step 5: Use UTM Tags the Right Way (Inbound, Not Outbound)
Here is where a lot of publishers hurt themselves: never put UTM parameters on your outbound affiliate links. UTMs are read by the destination site’s analytics, not yours, and merchants sometimes strip or misroute them. Use sub IDs for outbound, UTMs for inbound.
Tag every link that brings traffic to your site:
| Traffic type | utm_source | utm_medium | utm_campaign |
|---|---|---|---|
| Newsletter promo | newsletter | 2026-08-vpn-roundup | |
| Guest post or placed backlink | partnersite.com | referral | guestpost-hosting-guide |
| Paid social | paid_social | q3-review-retargeting | |
| YouTube description | youtube | video | unboxing-series |
Rules that keep the data clean:
- Lowercase everything. GA4 treats
Emailandemailas two channels. - Stick to the standard medium values (
email,referral,cpc,paid_social,affiliate) so GA4’s default channel grouping recognises them. - Never UTM-tag internal links. It resets the session and wipes the original source.
- Keep a shared spreadsheet of your naming conventions. Future you will thank present you.
Step 6: Push Commission Data Back Into GA4
Now the payoff. Export your network transactions (most offer a CSV export or an API), find the sub ID column, and send each commission to GA4 with the Measurement Protocol.
Endpoint
POST https://www.google-analytics.com/mp/collect
?measurement_id=G-XXXXXXXXXX
&api_secret=YOUR_API_SECRET
Create the API secret under Admin > Data streams > your stream > Measurement Protocol API secrets.
Payload
{
"client_id": "1786543210.1755840000",
"events": [
{
"name": "affiliate_commission",
"params": {
"session_id": "1755840000",
"transaction_id": "AWIN-88231",
"value": 42.50,
"currency": "USD",
"affiliate_network": "awin",
"affiliate_partner": "merchant-name",
"commission_status": "approved",
"engagement_time_msec": 1
}
}
]
}
Split the client_id and session_id back out of the sub ID you stored, and you have revenue attached to the exact session, device and channel that produced it.
Three things to get right
- Event name. Using
purchasemakes the money appear automatically in Monetization reports, but it will pollute your ecommerce data if you also sell your own products. If you run a pure content site,purchaseis convenient. Otherwise useaffiliate_commissionand build a custom metric. - Timing. Events sent with a backdated
timestamp_microsare only accepted within roughly 72 hours. Since commissions are confirmed weeks later, send them without a timestamp and rely onclient_idandsession_idfor the join. Attribution reporting will be approximate, which is why serious operators also mirror everything into BigQuery. - Reversals. When a network cancels a transaction, send a matching
refundevent with the sametransaction_id, or re-send withcommission_status: "declined"and filter it in your reports.
Free alternative: BigQuery
The GA4 to BigQuery export is free on standard properties. Load your network CSV into a table, join on the sub ID, and you get exact revenue by landing page, channel, device and campaign with none of the Measurement Protocol timing constraints. It is more work upfront and by far the most accurate route. This reference is the one worth keeping handy.
Done-for-you alternative
Tools such as wecantrack, AnyTrack or Affilimate handle the sub ID injection and the postback automatically for dozens of networks. Expect a monthly fee, but if you manage more than five programs the time saved usually justifies it.
Step 7: Build the Reports That Actually Change Decisions
Data with no report is just storage cost. Create these three explorations under Explore:
Report 1: Revenue per article
- Rows: Landing page + query string
- Values:
affiliate_clickcount, commission value, sessions - Add a calculated column for EPC (earnings per click) and RPM (revenue per 1000 sessions)
Report 2: Placement performance
- Rows:
affiliate_placement - Values: clicks, click-through rate, commission value
- Typical finding: comparison tables and above-the-fold buttons carry 60 to 80 percent of revenue while accounting for 20 percent of links
Report 3: Channel to commission path
- Rows: Session default channel group, Session source / medium
- Values: commission value, conversion rate
- This is the report that tells you whether the backlinks and campaigns you are paying for return real money, not just sessions
The reconciliation table you should keep monthly
| Metric | Network | GA4 | Match rate |
|---|---|---|---|
| Clicks | 12,430 | 11,180 | 90% |
| Transactions | 184 | 171 | 93% |
| Commission | $4,180 | $3,905 | 93% |
If a match rate drops sharply month over month, something broke in your tagging. Treat it as a monitoring metric.

Step 8: QA Checklist Before You Trust the Numbers
- Open DebugView and click three different affiliate links. Confirm
affiliate_clickfires once each with all parameters populated. - Inspect the destination URL after the click and confirm the sub ID parameter is present and not truncated.
- Place one real test transaction, then look for your sub ID in the network report within 24 to 48 hours.
- Send a test Measurement Protocol event and validate it with the Event Builder / validation server before running a bulk import.
- Check that custom dimensions are registered and returning values rather than “(not set)”.
- Set data retention to 14 months under Admin > Data settings > Data retention.
- Test on mobile. Some cloaker plugins and consent banners behave differently on touch devices.
Common Mistakes That Silently Destroy Affiliate Data
- Registering custom dimensions after collecting data. Nothing is backfilled, you lose that history permanently.
- Firing the event on mousedown without “wait for tags”. Fast browsers navigate away before the hit is sent, and you undercount by 10 to 20 percent.
- Sending revenue as a string. The
valueparameter must be a number."42.50"with quotes is silently dropped. - Forgetting currency. Without
currency, GA4 discards the value on purchase-type events. - Tagging internal links with UTMs. Every click restarts the session attribution and your organic traffic magically becomes “email”.
- Ignoring consent mode. If you operate in the EU, run Consent Mode v2 so modelled conversions fill part of the gap for users who decline cookies.
Putting It Together
Once revenue lives inside GA4 next to your acquisition data, the questions you can finally answer change completely: which article earns the most per thousand visitors, whether organic or referral traffic converts better for a given merchant, and which link placements deserve to be replicated across the site.
That last point matters most for growth. When you can see the exact commission value produced by each traffic source, investing in the pages and the backlinks that feed your highest EPC articles stops being guesswork. At DigBacklink we see the same pattern across publishers: the sites that scale are the ones that pointed authority at the pages their analytics proved were profitable, not the ones they assumed were.
FAQ
Can you track affiliate revenue in Google Analytics for free?
Yes. GA4, Google Tag Manager, the Measurement Protocol and the BigQuery export are all free at standard volumes. The only cost is your time building the sub ID bridge and importing network transactions. Paid tools automate the same workflow.
Does GA4 track affiliate links automatically?
Partly. Enhanced measurement records outbound clicks, but it cannot distinguish affiliate links from ordinary external links, it misses cloaked links on your own domain, and it never captures revenue. A custom affiliate_click event is required.
Should I use the purchase event or a custom event for commissions?
Use purchase if affiliate income is your only revenue stream and you want the data to appear in Monetization reports with no extra setup. Use a custom event such as affiliate_commission if you also run ecommerce, so the two revenue types stay separate.
Why do my GA4 clicks not match my affiliate network clicks?
Ad blockers, consent refusals, bot filtering differences and users who open links in new tabs before the tag fires all create variance. A 5 to 15 percent gap is normal. Anything larger points to a trigger timing issue or a missing tag on part of your site.
How do I track affiliate revenue when the sale happens weeks later?
Store the sub ID (client ID plus session ID) at click time, then send the commission back through the Measurement Protocol or join it in BigQuery once the network confirms it. The sub ID is the only durable link between the two systems because the third-party cookie is not.
What is the best way to keep track of multiple affiliate programs?
Standardise the sub ID format across every network, use the same event schema for all of them, and add affiliate_network as a dimension. One GA4 report then replaces logging into eight dashboards, and you can compare EPC across programs directly.
Is Google Analytics being replaced?
GA4 is the current version and Universal Analytics data is long gone. Many affiliates run GA4 alongside a privacy-focused tool such as Plausible or Matomo for cookieless traffic counts, but GA4 remains the free option with the deepest attribution and BigQuery integration.
