Fathom Analytics click tracking for your short links works entirely server-side: GT Link Manager fires the event during the redirect, so ad blockers never see it and every click counts. No JavaScript, no cookie implications, just an event in your Fathom dashboard for each branded link click.
Requirements
- GT Link Manager 1.5+ installed and active
- A Fathom Analytics account
- Your Fathom Site ID (found in Settings > Sites)
Installation
- Add the snippet below to your theme’s
functions.phpor a site-specific plugin - Replace
ABCDEFGHwith your Fathom Site ID
The Code
<?php
/**
* GT Link Manager - Fathom Analytics Integration
*
* Tracks redirect clicks as events in Fathom Analytics via the Events API.
* Server-side — works without client-side JavaScript.
*
* Setup:
* 1. Get your Fathom Site ID from Settings > Sites
* 2. Update GTLM_FATHOM_SITE_ID below
*
* Fathom tracks events as "pageviews with event data". Each redirect registers
* as a page view on the short link path, with an event name for filtering.
*
* @see https://usefathom.com/docs/api
*/
defined( 'ABSPATH' ) || exit;
// ── Configuration ────────────────────────────────────────────────────────────
define( 'GTLM_FATHOM_SITE_ID', 'ABCDEFGH' ); // Your Fathom Site ID
// ─────────────────────────────────────────────────────────────────────────────
add_action( 'gtlm_before_redirect', 'gtlm_fathom_track_click', 10, 4 );
/**
* Send a tracking event to Fathom when a redirect fires.
*
* Uses Fathom's /api/track endpoint which accepts server-side events.
*
* @param array $link Link data.
* @param string $target_url Destination URL.
* @param int $status HTTP status code.
* @param array $headers Response headers.
*/
function gtlm_fathom_track_click( array $link, string $target_url, int $status, array $headers ): void {
if ( GTLM_FATHOM_SITE_ID === 'ABCDEFGH' ) {
return; // Not configured yet.
}
$request_url = home_url( sanitize_text_field( $_SERVER['REQUEST_URI'] ?? '/' ) );
$referrer = sanitize_text_field( $_SERVER['HTTP_REFERER'] ?? '' );
$user_agent = sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ?? '' );
// Fathom's collect endpoint (same one the JS snippet uses).
$payload = [
'sid' => GTLM_FATHOM_SITE_ID,
'url' => $request_url,
'r' => $referrer,
'name' => 'Link Click: ' . ( $link['name'] ?? $link['slug'] ?? '' ),
'h' => 0, // Not a hostname-change event.
];
$forward_headers = [
'Content-Type' => 'application/x-www-form-urlencoded',
];
if ( $user_agent ) {
$forward_headers['User-Agent'] = $user_agent;
}
$client_ip = gtlm_fathom_get_client_ip();
if ( $client_ip ) {
$forward_headers['X-Forwarded-For'] = $client_ip;
}
wp_remote_post(
'https://cdn.usefathom.com/script.js', // Fathom's collect endpoint.
[
'body' => http_build_query( $payload ),
'headers' => $forward_headers,
'blocking' => false,
'timeout' => 1,
]
);
// Alternative: Use Fathom's beacon-style tracking via a simple GET request.
// This is more reliable for server-side use.
$beacon_url = add_query_arg( $payload, 'https://usefathom.com/api/event' );
wp_remote_get(
$beacon_url,
[
'headers' => $forward_headers,
'blocking' => false,
'timeout' => 1,
]
);
}
/**
* Get the real client IP.
*
* @return string|null
*/
function gtlm_fathom_get_client_ip(): ?string {
$headers = [ 'HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR' ];
foreach ( $headers as $header ) {
if ( ! empty( $_SERVER[ $header ] ) ) {
$ip = strtok( sanitize_text_field( $_SERVER[ $header ] ), ',' );
if ( filter_var( trim( $ip ), FILTER_VALIDATE_IP ) ) {
return trim( $ip );
}
}
}
return null;
}How It Works
- Hooks into
gtlm_before_redirectto capture every redirect - Fathom tracks events as pageviews with event data attached
- Each redirect registers as a page view on the short link path with a named event for filtering
- Forwards User-Agent and client IP for accurate visitor counting
- Uses both Fathom’s collect endpoint and beacon-style tracking for reliability
Configuration Notes
Events appear in your Fathom dashboard under the Events section. Each event is labeled Link Click: {link name} so you can filter and segment by individual links.
The snippet uses non-blocking HTTP requests so there is no added latency to the redirect itself.
If you’re comparing privacy-first options, the Plausible and Simple Analytics integrations follow the identical pattern, so switching later is a ten-minute job.