---
url: /integrations/google-tag-manager.md
---
# Google Tag Manager

Evolve loads one GTM container and pushes canonical events to its `dataLayer`. Analytics, Meta, LinkedIn, Pinterest and Google Ads tags live in that container, not in the theme. The package ships a container export with those five platforms wired to the events, so a new site is a matter of importing it and filling in the IDs. How consent and emission behave is on [Tracking and consent](/site/tracking-and-consent).

## Set up a container

1. **Create** a GTM container for the site (Web).
2. **Import** `vendor/racerfish/evolve/theme/gtm_container.json` under Admin > Import Container, into a new workspace, merge. It brings the tags, triggers and variables for GA4, Meta pixel, LinkedIn Insight, Pinterest and Google Ads.
3. **Edit the five platform variables** in the GTM UI with the client's IDs: the GA4 measurement ID, the Meta pixel ID, the LinkedIn partner ID (and conversion IDs), the Pinterest tag ID, the Google Ads conversion ID and labels. Delete the tags of platforms the client does not use.
4. **Preview** the workspace against the staging site with `TRACKING_EMIT=true`, click through a form submission and check that the tags fire on the events below.
5. **Publish** the container.
6. **Set the container ID** on the site: `GTM_ID=GTM-XXXXXXX` in the `.env`, or in the panel under Settings > Tracking. The snippet is rendered server-side; no theme rebuild is needed.

The container's tags should keep their consent checks: Evolve sets the Consent Mode default before GTM loads, and the banner updates it.

## Where the IDs come from

| Platform | Where to find the ID |
|---|---|
| GA4 | Analytics Admin > Data Streams > Web, "Measurement ID" (`G-...`) |
| Meta pixel | Events Manager > Data Sources, the pixel's ID |
| LinkedIn | Campaign Manager > Analyze > Insight Tag, partner ID; conversions under Conversion Tracking |
| Pinterest | Ads > Conversions > Pinterest Tag, tag ID |
| Google Ads | Goals > Conversions, each action's conversion ID and label |

## Events the theme pushes

Every push has an `event` name and a payload that follows the GA4 recommended events, so GA4 tags can forward them unchanged and the other platforms map them.

| Event | Fired by |
|---|---|
| `page_view` | every page load |
| `form_submit`, `form_error` | the form component on submit and on validation failure |
| `generate_lead` | a successful form submission (also sent server-side) |
| `sign_up` | registration flows |
| `view_item`, `add_to_cart`, `remove_from_cart`, `begin_checkout`, `add_payment_info`, `add_shipping_info` | the shop |
| `purchase` | a completed order (also sent server-side) |
| `search` | site search |
| contact interaction and booking completion | click-to-call, mail links, booking flows |

Any element can declare its own event with an `x-track` attribute holding a JSON payload, for example the social icons' outbound clicks. Custom code calls `window.gtmTrack(name, params)`. The exact payload of every event is specified in `theme/GTM_CONVERSION_SPECS.md` in the package.

## Migrating a project from the per-platform adapters

Projects built before 2.6 loaded GA4, the Meta pixel, LinkedIn and Pinterest through theme adapters fed by `window.*_TRACKING` globals. Those globals still render behind `TRACKING_LEGACY_VARIABLES=true`. The migration replaces direct SDK calls and `x-track` payloads with `dataLayer` pushes, removes the adapter files and the SDK loaders, imports the container and finally turns the flag off. The step-by-step guide is `theme/GTM_LEGACY_MIGRATION.md` in the package.

## Verifying

* Live: the page source contains `googletagmanager.com/gtm.js?id=GTM-...`. Staging shows it only with `TRACKING_EMIT=true`.
* In the browser console, `google_tag_manager` is defined and `dataLayer` lists the consent default followed by the page events.
* GTM Preview mode (Tag Assistant) connects to the site and shows which tags fired on which event, and the consent state at that moment.
* GA4 DebugView shows the `generate_lead` once from the browser and once from the server with the same event ID when both paths are on.
