Google Analytics 4 (GA4) Integration

  • JNext lesson
  • KPrevious lesson
  • FSearch lessons
  • EscClear search

Track every GT Link Manager redirect as a custom event in Google Analytics 4 using the Measurement Protocol. This server-side approach works even when visitors have ad blockers or JavaScript disabled, ensuring complete click data in your GA4 reports.

Requirements

  • GT Link Manager 1.5+ installed and active
  • A Google Analytics 4 property with a web data stream
  • A Measurement Protocol API secret (Admin > Data Streams > your stream > Measurement Protocol API secrets)
  • Your GA4 Measurement ID (starts with G-)

Installation

  • Add the snippet below to your theme’s functions.php or a site-specific plugin
  • Replace G-XXXXXXXXXX with your GA4 Measurement ID
  • Replace your_api_secret_here with your Measurement Protocol API secret

The Code

<?php
/**
 * GT Link Manager - Google Analytics 4 (GA4) Integration
 *
 * Tracks every redirect click as a GA4 event via the Measurement Protocol.
 * Server-side — works even when users have ad blockers or JS disabled.
 *
 * Setup:
 * 1. Get your GA4 Measurement ID (G-XXXXXXXXXX) from Admin > Data Streams
 * 2. Create a Measurement Protocol API Secret from Admin > Data Streams > your stream > Measurement Protocol API secrets
 * 3. Update the constants below with your credentials
 *
 * Event name: "link_click"
 * Event params: link_name, link_slug, target_url, redirect_type, category, referrer
 *
 * @see https://developers.google.com/analytics/devguides/collection/protocol/ga4
 */

defined( 'ABSPATH' ) || exit;

// ── Configuration ────────────────────────────────────────────────────────────
define( 'GTLM_GA4_MEASUREMENT_ID', 'G-XXXXXXXXXX' );       // Your GA4 Measurement ID
define( 'GTLM_GA4_API_SECRET',     'your_api_secret_here' ); // Measurement Protocol API secret
// ─────────────────────────────────────────────────────────────────────────────

add_action( 'gtlm_before_redirect', 'gtlm_ga4_track_click', 10, 4 );

/**
 * Send a GA4 event via Measurement Protocol when a redirect fires.
 *
 * @param array  $link       Link data from the database.
 * @param string $target_url Final destination URL.
 * @param int    $status     HTTP redirect status code.
 * @param array  $headers    Response headers being sent.
 */
function gtlm_ga4_track_click( array $link, string $target_url, int $status, array $headers ): void {

	if ( GTLM_GA4_MEASUREMENT_ID === 'G-XXXXXXXXXX' || GTLM_GA4_API_SECRET === 'your_api_secret_here' ) {
		return; // Not configured yet.
	}

	// Generate or reuse a client ID from a cookie to maintain session continuity.
	$client_id = gtlm_ga4_get_client_id();

	$payload = [
		'client_id' => $client_id,
		'events'    => [
			[
				'name'   => 'link_click',
				'params' => [
					'link_id'       => (int) $link['id'],
					'link_name'     => mb_substr( $link['name'] ?? '', 0, 100 ),
					'link_slug'     => $link['slug'] ?? '',
					'target_url'    => mb_substr( $target_url, 0, 500 ),
					'redirect_type' => $status,
					'category_id'   => (int) ( $link['category_id'] ?? 0 ),
					'referrer'      => mb_substr( $_SERVER['HTTP_REFERER'] ?? '(direct)', 0, 500 ),
					'user_agent'    => mb_substr( $_SERVER['HTTP_USER_AGENT'] ?? '', 0, 200 ),
				],
			],
		],
	];

	$url = add_query_arg(
		[
			'measurement_id' => GTLM_GA4_MEASUREMENT_ID,
			'api_secret'     => GTLM_GA4_API_SECRET,
		],
		'https://www.google-analytics.com/mp/collect'
	);

	wp_remote_post(
		$url,
		[
			'body'     => wp_json_encode( $payload ),
			'headers'  => [ 'Content-Type' => 'application/json' ],
			'blocking' => false, // Non-blocking — don't delay the redirect.
			'timeout'  => 1,
		]
	);
}

/**
 * Get or create a GA4 client ID from the _ga cookie.
 *
 * Falls back to a random UUID if cookie is not present (server-side only sessions).
 *
 * @return string Client ID in GA4 format.
 */
function gtlm_ga4_get_client_id(): string {

	// Try to extract from the _ga cookie set by gtag.js / GA4 client-side.
	if ( ! empty( $_COOKIE['_ga'] ) ) {
		$parts = explode( '.', sanitize_text_field( $_COOKIE['_ga'] ) );
		if ( count( $parts ) >= 4 ) {
			return $parts[2] . '.' . $parts[3];
		}
	}

	// Fallback: generate a random client ID for server-side only tracking.
	return wp_generate_uuid4();
}

How It Works

  • Hooks into gtlm_before_redirect which fires just before every redirect
  • Sends a non-blocking wp_remote_post to the GA4 Measurement Protocol endpoint
  • Uses the _ga cookie (if present) to maintain session continuity with client-side GA4
  • Falls back to a random UUID for server-side-only sessions
  • Tracks: link name, slug, target URL, redirect type, category, referrer, and user agent

Configuration Notes

The event appears in GA4 as link_click. To see it in reports, go to Reports > Engagement > Events. You can also create custom dimensions from the event parameters (link_name, link_slug, etc.) under Admin > Custom definitions.

The request is non-blocking ('blocking' => false) so it adds zero latency to the redirect.