Send Webhooks to Server-Side Google Tag Manager (sGTM)
Forward webhooks to a server-side Google Tag Manager container, reshape events for an sGTM client, and debug them safely in Preview mode.
Server-side Google Tag Manager can receive more than browser analytics hits. With the right server-side client, it can also accept backend events such as completed orders, subscription changes or CRM updates. The missing piece is often payload compatibility: the source sends one webhook shape, while the sGTM client expects another path, body and set of headers.
Webhook Relay can receive the original event, transform it into the contract expected by your sGTM client, and forward it to the tagging server. It also gives you delivery logs and a controlled way to route development events into an active Preview session.
Architecture
commerce / billing / CRM webhook
|
v
Webhook Relay input
validate + reshape
|
v
sGTM tagging server
|
v
client -> tags -> vendors
Google's server-side tagging introduction explains the core model: a client claims an incoming HTTP request, turns it into event data, and then tags use that event. A generic webhook will not automatically become an sGTM event. Your container must have a client that recognizes it.
Before you start
You need:
- A published server-side GTM container.
- A tagging-server URL, ideally on a first-party custom domain.
- A client that accepts your chosen path and payload, or a documented protocol you can transform into.
- A Webhook Relay bucket with a public input and the tagging-server URL as its output.
This example assumes a custom client claims POST /events with JSON shaped like this:
{
"event_name": "purchase",
"event_id": "evt_123",
"timestamp": "2026-09-06T08:30:00Z",
"user_id": "user_456",
"value": 49.95,
"currency": "EUR"
}
Change the path and fields to match your client. Do not copy this contract into production unless your sGTM container is configured to accept it.
1. Create the public webhook input
Create a public destination and set its destination to your tagging server, for example:
https://metrics.example.com
Copy the generated Webhook Relay input URL and register it with the service sending the original webhook.
2. Transform the provider payload
Suppose the source sends an order event:
{
"id": "ord_123",
"type": "order.completed",
"created_at": "2026-09-06T08:30:00Z",
"customer": { "id": "user_456" },
"total": { "amount": 49.95, "currency": "EUR" }
}
Attach this JavaScript function to the sGTM output:
const source = JSON.parse(r.body)
if (source.type !== "order.completed") {
r.stopForwarding()
return
}
const event = {
event_name: "purchase",
event_id: source.id,
timestamp: source.created_at,
user_id: source.customer && source.customer.id,
value: source.total && source.total.amount,
currency: source.total && source.total.currency
}
if (!event.event_id || !event.user_id || !event.currency) {
r.stopForwarding()
return
}
r.setMethod("POST")
r.setPath("/events")
r.setRawQuery("")
r.setHeader("Content-Type", "application/json")
r.setBody(JSON.stringify(event))
This filters unrelated events, maps names explicitly, and rejects incomplete purchases before they reach the tagging container. The event ID gives downstream tags a stable value for deduplication.
3. Route a webhook into sGTM Preview mode
Open your server container and click Preview. Google's server-side debugging guide shows how Tag Assistant displays incoming requests, the client that claimed them, event data and tag execution.
For a non-browser request to join that preview session, attach the preview-session header value captured for the active Tag Assistant session. Keep it out of the function source:
const previewHeader = cfg.get("GTM_PREVIEW_HEADER")
if (previewHeader) {
r.setHeader("X-Gtm-Server-Preview", previewHeader)
}
Add GTM_PREVIEW_HEADER under the function's configuration variables. Treat it as short-lived development configuration, remove it from the production output after testing, and never hard-code a captured session value in a shared function.
X-Gtm-Server-Preview is preview-session transport data, not an authentication mechanism or a permanent container setting. Recapture it when the Tag Assistant session changes and keep the destination protected independently.
If you operate your own tagging infrastructure, Google separates the tagging server from a preview server and documents the required environment variables in its manual setup guide. Keep the preview service private where possible and expose the public tagging endpoint through your normal load balancer.
4. Debug the event in Tag Assistant
Send one test event, then inspect:
- Requests: confirm the
/eventsrequest appeared. - Client: confirm the intended client claimed it.
- Event data: compare names, types and required identifiers.
- Tags: verify which tags fired and why others did not.
- Webhook Relay delivery: compare the transformed request with the sGTM response.
If the request reaches sGTM but no client claims it, fix the path, content type or custom-client logic. If it never appears in Tag Assistant but the production server responds, refresh the Preview session and its header value.
Privacy and reliability checklist
- Send only fields required by the tags. Avoid copying the entire source webhook.
- Remove email addresses, names and other direct identifiers unless your consent and vendor configuration permit them.
- Verify the source webhook before transforming it. See webhook signature verification.
- Preserve a stable event ID so retries do not become duplicate conversions.
- Filter non-production events or route them to a separate sGTM container.
- Inspect failures in the webhook logs view before changing tags.
Common problems
The tagging server returns 2xx, but no tag fires
A load balancer can accept a request even when no sGTM client claims it. Use Preview mode to inspect client selection and verify the request path and format.
Preview works, but production does not
Preview can hide missing published changes. Publish the latest container version and test the normal output without the preview header.
One source event creates duplicate conversions
Webhook delivery is retryable. Pass the source event ID through the transform and configure downstream tags or APIs to deduplicate it.
The function contains an analytics secret
Move it into a configuration variable and read it with cfg.get(...). This keeps reusable source code separate from account-specific credentials.
For more mapping and validation patterns, continue with the webhook transformation cookbook or inspect a raw sample first with Webhook Bin.
