First-Party Mode Setup
Google’s First-Party Mode enhances data privacy and security by allowing your website to serve Google Tag Manager (GTM) requests directly from your own domain instead of relying on googletagmanager.com. This setup improves tracking accuracy by reducing the impact of third-party tracking restrictions, ensuring smoother data collection for analytics and advertising purposes.
Getting Started
Google provides a detailed First-Party Mode setup guide that walks through the configuration process. The first step involves defining key settings, including the domain where GTM will operate, your Google Tag ID, and the path that will handle tracking requests.
- Domain: This is the website that will serve GTM requests, ensuring a first-party data context.
- Google Tag ID: This is your GTM or GA4 measurement ID, used to link analytics tracking to your configuration.
- Path: A specific route (e.g.,
/metrics) that will be used to forward tracking requests to Google's servers.
Routing Traffic
For your website to properly serve GTM requests, you need to route all tracking traffic through a custom endpoint. In this case, we use the /metrics path to act as a relay between your website and Google’s servers.
During setup, select "Other" as the CDN type. This allows full control over how requests are forwarded from your domain.
Setting Up a Simple Router
To handle GTM requests efficiently, you need to create a lightweight router script that captures incoming requests and forwards them to Google’s First-Party Mode endpoint. The router ensures that all tracking events are seamlessly relayed while keeping tracking data associated with your domain.
This script should be placed inside your /metrics folder, allowing all requests to /metrics/ to be properly handled.
How it works:
- It captures incoming tracking requests sent to
/metrics/.
- The script then forwards those requests to Google’s First-Party Mode servers.
- The response from Google is returned to the browser, ensuring tracking functions normally.
Setting the GTM Snippet
Once First-Party Mode is set up, the GTM snippet must be modified so that it loads from your own domain instead of from googletagmanager.com. This ensures that all tracking requests remain first-party.
Configuring the GTM Snippet
Update your GTM snippet as follows:
<script async src="https://ecommercedemostore.com/metrics/gtm.js?id=GTM-KX7HKZ4"></script>
Testing & Validating
To verify that First-Party Mode is functioning correctly, use the test links below to simulate different pageviews and confirm tracking activity.
Troubleshooting
If tracking isn’t working as expected, check for the following common issues:
- Requests are not being forwarded: Ensure that
/metrics/index.php is properly handling requests.
- Console errors: Check your browser console for network errors or missing resources.
- Tracking data missing in GA4: Confirm that GTM is loading from
ecommercedemostore.com/metrics/.
Router Code
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$path = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
$query = isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != '' ? '?' . $_SERVER['QUERY_STRING'] : '';
// Construct the target URL
$url = 'https://GTM-KX7HKZ4.fps.goog' . $path;
// Initialize cURL session and set options
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Host: GTM-KX7HKZ4.fps.goog'));
// Execute the request
$response = curl_exec($ch);
// Handle errors
if (curl_errno($ch)) {
echo 'Request Error:' . curl_error($ch);
exit;
}
// Get the HTTP status code and headers
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);
// Close cURL session
curl_close($ch);
// Forward the headers exactly as received
$header_lines = explode("\r\n", trim($headers));
foreach ($header_lines as $header_line) {
if (!empty($header_line) && !preg_match('/^Transfer-Encoding:/i', $header_line)) {
header($header_line);
}
}
// Output the body content only
echo $body;
?>