Skip to content
Gaurav TiwariDocs

GT Link Manager Matomo (Piwik) Integration

Updated October 17, 2026

Matomo click tracking through the HTTP Tracking API gives you full link analytics in an instance you own. This integration fires server-side on every GT Link Manager redirect, so your self-hosted Matomo records each click with no client JavaScript and no data leaving infrastructure you control.

Requirements

  • GT Link Manager 1.5+ installed and active
  • A Matomo instance (self-hosted or cloud)
  • Your Matomo Site ID (Settings > Websites)
  • (Optional) An auth token for enhanced tracking with IP and geo-location (Settings > Personal > Security > Auth tokens)

Installation

  • Add the snippet below to your theme’s functions.php or a site-specific plugin
  • Set GTLM_MATOMO_URL to your Matomo instance URL (no trailing slash)
  • Set GTLM_MATOMO_SITE_ID to your Matomo Site ID
  • (Optional) Set GTLM_MATOMO_TOKEN for IP-based geo-location tracking

The Code

<?php
/**
 * GT Link Manager - Matomo (Piwik) Integration
 *
 * Tracks redirect clicks as events in Matomo via the HTTP Tracking API.
 * Server-side — no JavaScript required.
 *
 * Setup:
 * 1. Set your Matomo instance URL (no trailing slash)
 * 2. Set your Site ID (visible in Matomo under Settings > Websites)
 * 3. (Optional) Set an auth token for enhanced tracking (IP, location)
 *    Get it from Matomo: Settings > Personal > Security > Auth tokens
 *
 * Event category: "Redirect"
 * Event action:   "Link Click"
 * Event name:     Link name or slug
 * Event value:    Redirect HTTP status code
 *
 * @see https://developer.matomo.org/api-reference/tracking-api
 */

defined( 'ABSPATH' ) || exit;

// ── Configuration ────────────────────────────────────────────────────────────
define( 'GTLM_MATOMO_URL',      'https://matomo.example.com' ); // Matomo instance URL (no trailing /)
define( 'GTLM_MATOMO_SITE_ID',  1 );                            // Matomo Site ID
define( 'GTLM_MATOMO_TOKEN',    '' );                            // Auth token (optional, for IP/geo)
// ─────────────────────────────────────────────────────────────────────────────

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

/**
 * Send a tracking event to Matomo when a redirect fires.
 *
 * @param array  $link       Link data.
 * @param string $target_url Destination URL.
 * @param int    $status     HTTP status code.
 * @param array  $headers    Response headers.
 */
function gtlm_matomo_track_click( array $link, string $target_url, int $status, array $headers ): void {

	if ( GTLM_MATOMO_URL === 'https://matomo.example.com' ) {
		return; // Not configured yet.
	}

	$request_url = home_url( sanitize_text_field( $_SERVER['REQUEST_URI'] ?? '/' ) );

	$params = [
		// Required.
		'idsite' => GTLM_MATOMO_SITE_ID,
		'rec'    => 1,

		// Page context.
		'url'        => $request_url,
		'urlref'     => sanitize_text_field( $_SERVER['HTTP_REFERER'] ?? '' ),
		'action_name' => 'Redirect: ' . ( $link['name'] ?? $link['slug'] ?? '' ),

		// Event tracking.
		'e_c' => 'Redirect',                                  // Event category
		'e_a' => 'Link Click',                                // Event action
		'e_n' => $link['name'] ?? $link['slug'] ?? 'unknown', // Event name
		'e_v' => $status,                                      // Event value

		// Custom variables (slot 1-5 available).
		'cvar' => wp_json_encode( [
			'1' => [ 'Link Slug', $link['slug'] ?? '' ],
			'2' => [ 'Target URL', mb_substr( $target_url, 0, 200 ) ],
			'3' => [ 'Category ID', (string) ( $link['category_id'] ?? 0 ) ],
		] ),

		// Visitor context.
		'ua'    => sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ?? '' ),
		'lang'  => sanitize_text_field( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '' ),
		'rand'  => wp_rand(),
		'apiv'  => 1,

		// Generate a visitor ID from IP + UA for consistency.
		'_id' => substr( md5( ( $_SERVER['REMOTE_ADDR'] ?? '' ) . ( $_SERVER['HTTP_USER_AGENT'] ?? '' ) ), 0, 16 ),
	];

	// Add client IP if auth token is set (required for accurate geo-location).
	if ( ! empty( GTLM_MATOMO_TOKEN ) ) {
		$params['token_auth'] = GTLM_MATOMO_TOKEN;
		$client_ip = gtlm_matomo_get_client_ip();
		if ( $client_ip ) {
			$params['cip'] = $client_ip;
		}
	}

	wp_remote_post(
		trailingslashit( GTLM_MATOMO_URL ) . 'matomo.php',
		[
			'body'     => $params,
			'blocking' => false,
			'timeout'  => 1,
		]
	);
}

/**
 * Get the real client IP.
 *
 * @return string|null
 */
function gtlm_matomo_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_redirect to fire on every redirect
  • Sends event tracking data: category = Redirect, action = Link Click, name = link name
  • Uses Matomo custom variables (slots 1-3) for link slug, target URL, and category ID
  • Generates a consistent visitor ID from IP + User Agent for session tracking
  • When an auth token is provided, sends the real client IP for accurate geo-location

Configuration Notes

Events appear in Matomo under Behaviour > Events. You can filter by the event category Redirect to see all link clicks. Custom variables are visible in Visitors > Custom Variables.

The auth token is optional but recommended for accurate geo-location data. Without it, Matomo will use the server’s IP instead of the visitor’s IP for location detection.

The event payload mirrors the GA4 integration, so running both during a migration is fine. For fully local tracking without Matomo, see the click log table.

Share

Was this helpful?

Still stuck? Open a support ticket