Google Tag Manager
Complete guide: Web Container (client-side) and Server Container (server-side). Importing the pre-configured containers, checking the values, publishing, tag architecture, consent, GA4 transport, CAPI destinations, Enhanced Conversions.
Fill them in from the matching guides (Connectors section at the top of each guide).
1Role / Purpose
GTM is the central hub of the tracking stack. It receives DataLayer events (injected by Addingwell), handles consent (Cookiebot CMP), gates the marketing tags, and routes hits to the server container (sGTM) through a first-party custom domain.
Shopify Store
↓
Addingwell (DataLayer + Custom Pixel + GTM injection)
↓
┌─────────────────────────────────────────────────┐
│ GTM Web Container (client-side) │
│ Consent, marketing tags, GA4 transport │
└─────────────────────────────────────────────────┘
↓ GA4 hits via server_container_url
┌─────────────────────────────────────────────────┐
│ GTM Server Container (server-side) │
│ GA4 Server, Meta CAPI, Google Ads EC, etc. │
└─────────────────────────────────────────────────┘| Container | Role | Hosted on |
|---|---|---|
| Web (client-side) | Consent, marketing pixels, GA4 config/transport, forwarding to sGTM | Browser (through Addingwell) |
| Server (server-side) | CAPI destinations, Enhanced Conversions, first-party tracking | Custom domain (tags.mystore.com) |
Both containers ship pre-configured and complete. Every tag, trigger, variable and vendor template is included. Credentials are interpolated from Connectors at download time.
2Web + Server Architecture
How the Web Container is organised
GTM Web Container ├── Consent Initialization │ └── Cookiebot CMP (Denied defaults) │ ├── GA4 Config / Transport │ └── GA4 tag → server_container_url → sGTM │ ├── Marketing Tags (waiting for consent) │ ├── Meta Pixel (PageView, ViewContent, AddToCart, Purchase) │ └── Google Ads Remarketing │ ├── DataLayer Triggers │ ├── page_view, view_item_list, view_item │ ├── add_to_cart, remove_from_cart, view_cart │ └── begin_checkout, purchase │ └── Variables ├── DataLayer Variables (ecommerce.*) ├── Consent State Variables └── Connectors Variables
How the Server Container is organised
sGTM Server Container ├── Client │ └── GA4 Client (receives hits from the Web Container) │ ├── Tags │ ├── GA4 Server Tag → Google Analytics │ ├── Meta Conversions API Tag → Meta │ └── Google Ads Server Conversions Tag → Google Ads │ ├── Triggers │ └── Based on the GA4 event_name (purchase, page_view, etc.) │ └── Variables ├── Event Data Variables (transaction_id, value, etc.) └── User Data Variables (email, phone: hashed)
Full Web → Server flow
GTM Web → GA4 transport → server_container_url
↓
sGTM Server Container
↓
┌───────────────┼───────────────┐
↓ ↓ ↓
GA4 Server Meta CAPI Google Ads EC
↓ ↓ ↓
google-analytics graph.facebook googleads.gPrinciples
- Every tag has its own DataLayer trigger
- Marketing tags are gated on consent
- GA4 acts as transport to the sGTM through the first-party custom domain
- No tag fires without an explicit trigger
- Client-side and server-side share the same event_id for deduplication
3GTM Web Container
Import procedure
Download the Web container below
GTM Web → Admin → Import Container
Workspace: Default
Mode: Merge → Overwrite conflicting tags, triggers, and variables
What the container holds
DataLayer & triggers
Addingwell feeds the DataLayer, not the theme. Events reach GTM automatically.
| DataLayer event | GTM trigger | Associated tags |
|---|---|---|
| page_view | CE - page_view | GA4, Meta PageView |
| view_item | CE - view_item | GA4, Meta ViewContent |
| add_to_cart | CE - add_to_cart | GA4, Meta AddToCart |
| begin_checkout | CE - begin_checkout | GA4, Meta InitiateCheckout |
| purchase | CE - purchase | GA4, Meta Purchase, Google Ads Conversion |
Consent Mode v2
1. Consent Initialization
└── Cookiebot → Denied defaults
(ad_storage, analytics_storage, ad_user_data, ad_personalization)
2. Visitor accepts/declines
└── Cookiebot → consent_update
3. Gated tags
└── Built-in Consent checks before each tag fires| Tag | Required consent |
|---|---|
| Cookiebot CMP | None (Consent Initialization) |
| GA4 Config | analytics_storage (Advanced Consent Mode) |
| Meta Pixel | ad_storage + ad_user_data |
| Google Ads Remarketing | ad_storage + ad_personalization |
Advanced Consent Mode
GA4 uses Advanced Consent Mode: even without consent it sends anonymised pings (no cookies). Marketing tags are strictly blocked without consent.
GA4 Config / Transport
The GA4 Config tag initialises GA4 and sets up hit transport to the server container (sGTM) through the custom domain.
| Parameter | Value | Role |
|---|---|---|
| Measurement ID | G-XXXXXXXXXX | GA4 identifier |
| server_container_url | https://tags.mystore.com | sGTM custom domain (first-party) |
| send_page_view | false | Disabled: handled by the page_view trigger |
DataLayer event (e.g. purchase)
↓
GA4 Event Tag (purchase)
↓
GA4 Config (server_container_url)
↓
https://tags.mystore.com (sGTM)
↓
Server-side destinationsserver_container_url
server_container_url routes GA4 hits to the sGTM instead of google-analytics.com. That is what enables the adblocker bypass and first-party tracking.
Client-side marketing tags
| Platform | Tag | Events |
|---|---|---|
| Meta | Meta Pixel | PageView, ViewContent, AddToCart, InitiateCheckout, Purchase |
| Google Ads | Remarketing | Page view + audiences |
- Client-side: enriches first-party signals (_fbp, _fbc, ttclid cookies, …)
- Server-side (sGTM): sends conversions through the API (resilient, deduplicated)
- event_id / transaction_id deduplication prevents doubles
- The two channels complement each other to maximise signal
Reminder — Consent Mode
Consent Mode v2 (every default at Denied) is handled by the Cookiebot CMP tag in GTM. That tag loads the banner, sets the defaults, sends consent updates and fires the conditional triggers.
4GTM Server Container
Import procedure
Download the Server container below
GTM Server (through Addingwell) → Admin → Import Container
Workspace: Default
Mode: Merge → Overwrite conflicting tags, triggers, and variables
What the container holds
sGTM routing flow
GA4 Client (receives the Addingwell transport requests) ├── GA4 Server → Forward to GA4 ├── META – CAPI → Conversions API (Full server-only) │ └── fbp/fbc 1P cookies, event_id, user_data ├── GADS – Conv (x10) → Enhanced Conversions │ └── purchase, add_to_cart, begin_checkout, view_item, etc. ├── Addingwell Monitoring → Logs & analytics └── Automatic enrichment: • User data through the GA4 Event Settings Variable • event_id for Meta deduplication • Consent Mode v2 signals
First-party custom domain
- Hits go to tags.mystore.com instead of google-analytics.com
- Adblockers do not block first-party requests
- Cookies are first-party (unaffected by ITP)
- Better attribution and longer cookie lifetimes
DNS tags.mystore.com → CNAME → sGTM hosting GTM Web GA4 Config → server_container_url = https://tags.mystore.com Result Every GA4 hit travels through the custom domain
HTTPS required
The custom domain must be served over HTTPS. The sGTM provider (Addingwell, Stape, …) manages the SSL certificate automatically.
Server-side destinations
| Destination | sGTM tag | API | Events |
|---|---|---|---|
| Meta | Meta Conversions API | graph.facebook.com | PageView, ViewContent, AddToCart, Purchase |
| Google Ads | Google Ads Conversions | googleads.googleapis.com | purchase (Conversion Action) |
Deduplication
| Platform | Deduplication key |
|---|---|
| Meta | event_id (identical client + server) |
| Google Ads | transaction_id / order_id |
Addingwell templates
The Addingwell templates (Meta CAPI, Google Ads Conversions) enrich events automatically with user_data, cookies and URL parameters. No manual variable configuration.
Turnkey container: server-side connectors, first-party routing and destination credentials (Pixel IDs, Access Tokens) are pre-filled through Connectors. Meta runs in Full CAPI (no browser pixel).
5Check the Values
Every value is pre-filled in the imported containers. Open each variable/tag in GTM and confirm the value matches.
G-XXXXXXXhttps://tags.my-store.comxxxxxxxx-xxxx-...123456789EAAG...AW-XXXXXXXXXAbCdEf...Procedure:
GTM → Variables (Web) or Tags (Server) → open the item → check the Connectors value.
DataLayer variables (DLV - ecommerce - *) fill themselves through Addingwell.
6Disable Unused Destinations
When a destination is not in use, pause its tags: do not delete them.
META - Pixel - All EventsMETA - CAPI - All EventsGADS - Remarketing - All PagesGADS - Conv - purchaseProcedure:
GTM → Tags → open the tag → ... menu → Pause → save.
7Publish the Containers
Once the values are checked and the unused destinations paused:
Before you publish
Do not publish if any value looks wrong, or if placeholders are still visible in the variables or tags. Go back to Connectors and fix them first.
8Tag Reference
Enhanced Conversions
Enhanced Conversions improve user matching by sending hashed (SHA-256) data to the platforms.
| Data | Source | Hashing |
|---|---|---|
| DataLayer (purchase) | Automatic SHA-256 | |
| Phone | DataLayer (purchase) | Automatic SHA-256 |
| First Name | DataLayer (purchase) | Automatic SHA-256 |
| Last Name | DataLayer (purchase) | Automatic SHA-256 |
| Address | DataLayer (purchase) | Automatic SHA-256 |
Shopify Checkout (purchase)
↓
DataLayer (user_data in clear text)
↓
GTM Web → GA4 transport → sGTM
↓
sGTM templates hash it automatically
↓
Platforms receive the hashed dataConsent required
User data is never sent without marketing consent. Consent Mode v2 blocks the transmission when ad_user_data = Denied.
DataLayer variables (Web Container)
| Variable | DataLayer path | Usage |
|---|---|---|
| DLV - ecommerce.currency | ecommerce.currency | Currency (EUR, USD, …) |
| DLV - ecommerce.value | ecommerce.value | Transaction amount |
| DLV - ecommerce.transaction_id | ecommerce.transaction_id | Unique order ID |
| DLV - ecommerce.items | ecommerce.items | Products (array) |
Credentials needed (Server Container)
| Destination | Credentials |
|---|---|
| Meta CAPI | Pixel ID + Access Token |
| Google Ads | Conversion ID + Conversion Label |
| GA4 | Measurement ID (inherited from Web) |
Naming convention
DataLayer variables use the DLV - prefix. Configuration constants are named after their role. Triggers use the CE - prefix (Custom Event).
9Verification
GTM Preview Mode (Web Container)
- 1Open GTM → Preview (top-right button)
- 2Enter the Shopify store URL
- 3Browse the store in the preview tab
- 4Check which tags fire in the debug panel
| Check | Expected |
|---|---|
| Consent Initialization | Cookiebot CMP fires first |
| Before consent | Only Cookiebot and GA4 Config fire |
| After marketing consent | Meta and Google Ads fire |
| purchase event | Every ecommerce variable populated |
| server_container_url | GA4 hits leave through the custom domain |
GTM Preview Mode (Server Container)
- 1Open GTM Server → Preview Mode
- 2Browse the store and trigger some events
- 3Check the GA4 Client receives the hits
- 4Check each server tag fires correctly
Verify the destinations
| Destination | Verification tool |
|---|---|
| Meta CAPI | Meta Events Manager → Test Events |
| Google Ads | Google Ads → Conversions → Diagnostics |
| GA4 | GA4 DebugView (Realtime) |
CDN proxy and Preview
When the Addingwell CDN proxy is active, Preview Mode may not work on the custom domain. Test with the proxy temporarily disabled, or use the direct GTM URL.
Phase 2: GTM + consent foundations
10Troubleshooting
Check:
- 1GTM injected by Addingwell (no conflicting manual snippet)
- 2Container ID correct
- 3DataLayer events present (console → dataLayer)
- 4Triggers correctly mapped to the events
Check:
- Cookiebot tag on Consent Initialization (not All Pages)
- Built-in consent configured on every marketing tag
- No tag left on "No additional consent required"
Check:
- 1server_container_url correct in GTM Web (GA4 Config tag)
- 2Custom domain working (curl https://tags.mystore.com/healthz)
- 3Server container published
- 4GA4 Client configured in the sGTM
Check:
- Access Token valid and not expired
- Pixel ID correct
- Token permissions (ads_management, ads_read)
- Event format (event_name, user_data)
Check:
- event_id identical between client-side and server-side
- No duplicate purchase tag in GTM Web
- No conversion imported manually in parallel
- Deduplication enabled on the platform side
Check:
- user_data present in the DataLayer (email, phone)
- Values non-empty at purchase time
- Automatic hashing active in the templates
- ad_user_data consent = Granted
Full checklist
Check the layer you just set up
Scan the store: 41 checks read what it now sends to GA4, Meta and Google Ads.