Skip to content
Gaurav TiwariDocs

How to Track Affiliate Clicks in GA4

Updated October 19, 2026

GA4 can tell you which posts get traffic, but not which affiliate links people click. Its automatic outbound click tracking ignores links to your own domain, so a /go/ link never shows up, and you’re left guessing which product boxes earn their space.

To track affiliate clicks in GA4, you send an event from the server each time a branded link redirects. The event carries the link’s slug and destination, so GA4 can report clicks per link next to your page views, with no extra JavaScript on the page.

GT Link Manager runs the redirect, and it fires a hook called gtlm_before_redirect just before it sends the visitor on. A small must-use plugin listens to that hook and posts the event to GA4 through the Measurement Protocol, Google’s API for sending events from a server.

Before you write any code, it is wise to check whether you need GA4 for this at all. GT Link Manager has its own click reports, and for many sites they answer the question faster.

Pick GA4 or the Built-In Reports

Both routes count clicks on your branded links. The difference is where the data lives and what it sits next to.

NeedBuilt-in AnalyticsGA4 event
SetupOne checkboxAPI secret, a PHP file and a custom dimension
Where reports liveGT Links → Analytics in wp-adminYour GA4 property
Referring post for each clickYes, in Clicked fromOnly if you add it as a parameter
Bots and your own clicksExcluded automaticallyExcluded by the code below
Joins with sessions, conversions and ads dataNoYes

I’d start with the built-in reports. Turn them on under GT Links → Analytics → Settings with Enable advanced analytics. They need no cookies or visitor scripts, and they keep individual clicks for 7 days and daily reports for 90 days by default.

GT Link Manager Click analytics settings with Enable advanced analytics ticked, Keep reports for set to Forever and Include countries ticked

Choose GA4 when you need clicks inside the same reports as your sessions and conversions, or when a team already lives in GA4.

Before You Start

For the GA4 route, you need:

  • A GA4 property with a web data stream, and its Measurement ID, which starts with G-.
  • A Measurement Protocol API secret. In GA4, go to Admin → Data streams, open your web stream and create one under Measurement Protocol API secrets.
  • File access to your site, through SFTP or your host’s file manager, to add a file to wp-content/mu-plugins.

Add the Tracking Code

A must-use plugin loads on every request and can’t be switched off by accident from the Plugins screen. That suits tracking code.

  1. Create the folder wp-content/mu-plugins if it doesn’t exist.
  2. Create a file in it named gtlm-ga4.php.
  3. Paste the code below and replace the 2 placeholder values at the top.
  4. Save the file. WordPress loads it straight away, with nothing to activate.
<?php
/**
 * Plugin Name: GT Link Manager to GA4
 * Description: Sends a link_click event to GA4 for each branded link redirect.
 */

defined( 'ABSPATH' ) || exit;

const GTLM_GA4_MEASUREMENT_ID = 'G-XXXXXXXXXX';
const GTLM_GA4_API_SECRET     = 'your-api-secret';

add_action( 'gtlm_before_redirect', function ( $link, $target_url ) {
	// Skip HEAD checks, logged-in editors and obvious bots.
	if ( 'GET' !== ( $_SERVER['REQUEST_METHOD'] ?? '' ) || current_user_can( 'edit_posts' ) ) {
		return;
	}
	$agent = strtolower( (string) ( $_SERVER['HTTP_USER_AGENT'] ?? '' ) );
	if ( '' === $agent || preg_match( '/bot|crawl|spider|slurp|preview|monitor/', $agent ) ) {
		return;
	}

	// Reuse the visitor's GA4 client ID when the _ga cookie exists.
	$client_id = wp_generate_uuid4();
	if ( isset( $_COOKIE['_ga'] ) && preg_match( '/^GA\d\.\d\.(\d+\.\d+)$/', (string) $_COOKIE['_ga'], $m ) ) {
		$client_id = $m[1];
	}

	$event = array(
		'client_id' => $client_id,
		'events'    => array(
			array(
				'name'   => 'link_click',
				'params' => array(
					'link_slug'   => (string) $link['slug'],
					'link_name'   => mb_substr( (string) $link['name'], 0, 100 ),
					'destination' => (string) wp_parse_url( $target_url, PHP_URL_HOST ),
				),
			),
		),
	);

	// Send the event after the visitor has been redirected.
	add_action( 'shutdown', function () use ( $event ) {
		if ( function_exists( 'fastcgi_finish_request' ) ) {
			fastcgi_finish_request();
		}
		$url = add_query_arg(
			array(
				'measurement_id' => GTLM_GA4_MEASUREMENT_ID,
				'api_secret'     => GTLM_GA4_API_SECRET,
			),
			'https://www.google-analytics.com/mp/collect'
		);
		wp_remote_post(
			$url,
			array(
				'headers' => array( 'Content-Type' => 'application/json' ),
				'body'    => wp_json_encode( $event ),
				'timeout' => 5,
			)
		);
	} );
}, 10, 2 );

A few parts of this code are doing important work:

  • The shutdown step. gtlm_before_redirect runs before the redirect headers go out, so anything slow inside it makes the visitor wait. The code only queues the event there. The request to GA4 runs at shutdown, after GT Link Manager has sent the redirect.
  • fastcgi_finish_request(). On PHP-FPM, which most hosts run, this closes the connection to the visitor before the GA4 request starts. On other setups, the request still runs after the redirect is written, but the browser may wait for it to finish.
  • The filters at the top. curl -I checks, link checkers, crawlers and your own test clicks never reach GA4, so the numbers stay close to real people.

The GT Link Manager Google Analytics 4 (GA4) Integration reference lists more event parameters, such as the referrer and category ID.

Make the Parameters Show in Reports

GA4 records the link_slug and destination parameters, but its standard reports won’t show them until you register them.

  1. In GA4, go to Admin → Custom definitions.
  2. Click Create custom dimension.
  3. Name it “Link slug”, set the scope to Event and enter link_slug as the event parameter.
  4. Repeat for destination if you want clicks grouped by store.

Custom dimensions apply only to events received after you create them, so create them on day 1.

Check It Works

Google offers a validation endpoint that checks an event without recording it. Run this in a terminal with your own ID and secret:

curl -s -X POST "https://www.google-analytics.com/debug/mp/collect?measurement_id=G-XXXXXXXXXX&api_secret=your-api-secret" -H "Content-Type: application/json" -d '{"client_id":"123.456","events":[{"name":"link_click","params":{"link_slug":"test"}}]}'

An empty validationMessages list means GA4 accepts the event shape. Then test the real path:

  1. Log out, or use a private window, because the code skips logged-in editors.
  2. Click a branded link from one of your posts.
  3. Look for link_click under Reports → Engagement → Events. Standard reports can take a day to fill in.

When Events Don’t Arrive

SymptomLikely causeFix
Nothing in GA4 after a dayWrong Measurement ID or API secretCheck both, then run the validation command again
Your own clicks don’t showYou were logged inTest from a private window
Clicks appear but the slug column is emptyThe custom dimension was created after the clicksWait for new clicks, since GA4 doesn’t backfill
Redirects feel slowThe host doesn’t run PHP-FPMKeep the GA4 call at shutdown and keep the timeout short
A PHP error after adding the fileA paste error, often a missing <?php lineFix the file, or rename it to .txt to switch it off

What It Won’t Do

This setup counts redirects. It doesn’t see what happens on Amazon or any other store:

  • No sales or commissions. Those stay in your affiliate dashboard. GA4 sees the click, not the purchase.
  • Not unique people. A visitor without a _ga cookie gets a fresh ID on each click.
  • No perfect bot filter. The user-agent check catches the common crawlers, not every script.
  • No history. Events start from the day you add the file.

If the same click should also ping your team, How to Get a Slack Message When a Link Gets Clicked uses the same hook and the same shutdown pattern.

Share

Was this helpful?

Still stuck? Open a support ticket