Getting StartedGuideIntermediate

Migrating from Google Tag Manager: an inventory-first plan that keeps conversions counting

A step-by-step migration from GTM web containers to Track — container export and a reviewed inventory, translating tags, triggers and variables into a tracking plan, running both in parallel with deduplication, cutting over per destination, and what has no equivalent by design.

By
Track editorial team
Published
Last reviewed
Reading time
4 min read

Key takeaways

  • Start with the container export and a reviewed inventory: one row per tag with vendor, trigger, variables and a classification; nothing is created from it automatically.
  • Translate tags and triggers into the events and destinations of a tracking plan with typed properties, consent purposes and versioned mappings.
  • Run both systems in parallel with deduplication, starting server-side only per destination, then cut over one destination at a time and retire the container.
  • Custom HTML/JavaScript tags, consent overrides, tag sequencing and DOM scraping have no equivalent by design — that logic moves into the site's own code.

Step 1: export and inventory

Export the container (Admin → Export Container). The JSON lists every tag, trigger, variable and folder. Build the inventory from it — a spreadsheet is enough — with one row per tag: vendor, tag type, trigger, variables read, and a classification:

  • Recognised vendor tag (GA4, Google Ads, Meta, TikTok, LinkedIn, Microsoft, Pinterest, Snapchat, Reddit, X, Taboola, Outbrain, Criteo, affiliate pixels) with a matching destination template.
  • Data layer push grouped by event name, with the variables each tag reads.
  • Custom HTML tag, classified as vendor snippet with a known equivalent, first-party helper (scroll depth, form listeners), or unknown.
  • Paused tags and tags without recent firings (GTM's tag metadata shows when a tag last fired), flagged as retirement candidates.

The inventory is the migration's source of truth. Nothing is created from it automatically; you review each row and decide.

Step 2: translate into a tracking plan

GTM thinks in tags and triggers; Track thinks in events and destinations. The translation:

GTM conceptTrack concept
dataLayer.push({event: 'purchase', ecommerce: {...}})tsq.push(['track', 'purchase', {...}]) with the canonical commerce schema
Trigger "Custom Event equals purchase"the event itself; destinations subscribe by event name
Trigger "Click — All Elements" with CSS filtera declarative click rule (selector, event name, allowed properties)
Data layer variablea property in the event schema, typed and validated
Lookup tablea mapping table in the destination, versioned and diffable
Consent initialisation tagthe CMP integration; consent is read, never set
GA4 config + event tagsone GA4 destination with event mappings, browser and server
Google Ads conversion tag per actionone Google Ads destination with one mapping per conversion action

The plan lists every event with its properties, its consent purpose and the destinations it feeds. Critical events are marked so the health score watches them.

Step 3: parallel run with deduplication

Do not switch off GTM on day one. Install the Track SDK alongside it. The SDK observes GA4-shaped data layer pushes without executing anything, so a container that already pushes purchase with an ecommerce object feeds both systems from the same push.

For each destination, start with server-side only in Track while the GTM browser tag keeps firing:

  • For Google Ads and GA4, purchases carry the same transaction id on both paths and the vendor deduplicates on it.
  • For platforms that deduplicate on event id (Meta, TikTok, Microsoft, Pinterest, Snapchat, Reddit) run the server path in test mode first, compare counts in the vendor's test view, then cut over directly — do not run both live with different ids.

The destination monitor shows acceptance per destination; when it matches the GTM tag's numbers, the browser tag is redundant.

Step 4: cut over per destination

For each destination, in this order: switch Track to hybrid (its own browser template plus server), pause the GTM tag, watch the vendor's event count for two days, then delete the GTM tag. Analytics destinations first, advertising destinations one at a time, affiliate networks last because their postbacks need the click-id store warmed up for the cookie window.

Step 5: retire the container

When every tag is paused and the vendor counts match, remove the GTM snippet. Keep the exported container in the migration record; the audit log shows who cut over what and when.

What has no equivalent, on purpose

  • Custom HTML and custom JavaScript tags. Track executes no site-authored code. Vendor snippets become declarative templates; first-party helpers become declarative rules; anything else is a decision to make explicitly, usually by moving the logic into the site's own code where it belongs.
  • Consent overrides. No tag can be set to fire regardless of consent.
  • Tag sequencing and firing priorities. Events are routed by policy, not raced.
  • Regex-based scraping of the page into variables. Properties come from the data layer or declarative rules, not from DOM text.

Mark each of these in your inventory so you know before you start how much of the container is real tracking and how much is accumulated scaffolding.

Primary sources

Documentation and standards this article is based on.

  1. Google Tag Manager Help — Export and import containerssupport.google.com

Was this article helpful?

Responsible editor

Track editorial team

Product & engineering

The people building Track: engineers and analysts who work on server-side tracking, consent tooling and connector integrations every day.