# Common GTM Issues & Fixes ## Container Issues ### GTM Not Firing **Symptoms**: No GTM requests in network tab **Causes**: 1. Script blocked by ad blocker 2. Script placed after closing body tag 3. JavaScript error before GTM loads 4. Consent management blocking GTM **Fix**: ```html ``` ### Multiple Containers Conflict **Symptoms**: Duplicate events, inconsistent data **Causes**: 1. Legacy container not removed 2. Different teams installed separate containers 3. Theme/plugin auto-installed GTM **Fix**: 1. Audit all containers in source 2. Consolidate to single container 3. Use GTM environments for staging/prod ### Container ID Mismatch **Symptoms**: Tags not firing, wrong property receiving data **Causes**: 1. Dev/staging container on production 2. Copy-paste error during installation **Fix**: Verify container ID matches GTM account --- ## DataLayer Issues ### DataLayer Not Initialized **Symptoms**: First push events lost **Code Error**: ```javascript // Wrong - GTM loads before dataLayer exists dataLayer.push({...}); ``` **Fix**: ```javascript // Correct - Initialize dataLayer first ``` ### Case Sensitivity Issues **Symptoms**: Triggers not matching **Example**: ```javascript // DataLayer pushes "AddToCart" dataLayer.push({ event: "AddToCart" }); // But GTM trigger looks for "addToCart" - won't match! ``` **Fix**: Standardize event naming (recommend lowercase with underscores) ### Wrong Data Types **Symptoms**: Calculations wrong in GA4, missing data **Example**: ```javascript // Wrong - price as string dataLayer.push({ ecommerce: { value: "29.99" }}); // Correct - price as number dataLayer.push({ ecommerce: { value: 29.99 }}); ``` ### Timing Issues **Symptoms**: Events fire before data available **Cause**: DataLayer push happens after tag fires **Fix**: Use "Custom Event" trigger instead of "Page View" --- ## Tag Issues ### Tag Not Firing **Checklist**: 1. ✓ Trigger conditions met? 2. ✓ Trigger enabled? 3. ✓ Tag not paused? 4. ✓ No blocking triggers active? 5. ✓ Consent mode not blocking? **Debug Steps**: 1. GTM Preview > Check Tags Fired 2. Verify trigger shows green check 3. Check Variables tab for expected values ### Duplicate Tag Firing **Symptoms**: Events counted 2x in GA4 **Causes**: 1. Multiple triggers on same action 2. Page re-renders triggering again 3. SPA virtual pageviews firing multiple times **Fix**: 1. Add "Once per event" tag firing option 2. Use trigger groups to control firing 3. Add conditions to prevent re-firing ### Wrong Parameters Sent **Symptoms**: Data appears in wrong fields in GA4 **Debug**: 1. GTM Preview > Tags > Show fired tag 2. Check "Values" sent with tag 3. Compare with expected parameters --- ## E-commerce Issues ### Missing Transaction ID **Symptoms**: Duplicate purchases counted **Fix**: Ensure unique `transaction_id` generated server-side ### Items Array Empty **Symptoms**: Revenue tracked but no products **Check**: `ecommerce.items` array populated ### Value Mismatch **Symptoms**: Revenue doesn't match actual **Causes**: 1. Tax/shipping included inconsistently 2. Currency conversion issues 3. Discount applied incorrectly ### Purchase Event Fires Multiple Times **Symptoms**: Same order tracked 2-3x **Causes**: 1. Page refresh on confirmation 2. Browser back button 3. Email link revisit **Fix**: ```javascript // Check if already tracked if (!sessionStorage.getItem('purchase_' + transaction_id)) { dataLayer.push({ event: 'purchase', ... }); sessionStorage.setItem('purchase_' + transaction_id, 'true'); } ``` --- ## Consent Mode Issues ### Tags Blocked by Consent **Symptoms**: Tags show "Blocked by consent" in Preview **Fix**: 1. Verify consent mode implementation 2. Check default consent state 3. Test with consent granted ### Consent Not Updating **Symptoms**: Tags stay blocked after user accepts **Fix**: Verify `gtag('consent', 'update', {...})` fires on accept --- ## SPA (Single Page App) Issues ### Pageviews Not Tracking Navigation **Symptoms**: Only initial pageview tracked **Cause**: No page reload on route change **Fix**: Implement History Change trigger or custom event: ```javascript // On route change dataLayer.push({ event: 'virtual_pageview', page_path: newPath, page_title: newTitle }); ``` ### Events Fire on Old Page Data **Symptoms**: Wrong page_path in events **Fix**: Update page variables before event push --- ## Content Grouping Issues (RegEx Table Variables) ### How Content Grouping Works in GTM Content grouping uses **RegEx Table** variables to categorize pages by URL/path patterns. The variable takes an input (typically `{{Page Path}}` or `{{Page URL}}`), tests it against an ordered list of regex patterns, and returns the first matching output value. If no pattern matches, it falls to the **Default Value** (usually "Other"). **Key settings:** - **Full Matches Only**: OFF — partial regex match is sufficient - **Capture Groups and Replace**: OFF — output is the literal value, not a regex replacement - **Ignore Case**: ON — case-insensitive matching ### New Page Paths Fall Through to "Other" **Symptoms**: New sections (campaigns, special events, landing pages) show as "Other" in GA4 content group reports. **Root cause**: The RegEx Table was built for the site's original URL structure. New paths like `/specialEvent/`, `/campaign/`, `/timesale/` don't match any existing pattern. **Example**: JHR site has `/specialEvent/landersshoppingfesta2026/teaser.do` but only `/package/` and `/event/` are in the regex table, not `/specialEvent/`. **Fix**: Add regex rule for the new path pattern. Place it BEFORE the default. **Gotcha — two variables to update**: Sites often have parallel content group variables: 1. **Page Path based** (e.g., `(\/m)?\/specialEvent\/(.*)`) — for internal reports 2. **Page URL based** (e.g., full URL with domain regex) — for cross-domain or subdomain tracking Both must be updated or they'll produce inconsistent groupings. ### RegEx Pattern Conventions (JHR Example) Page Path patterns follow this structure: ``` (\/m)?\/section\/(.*) → Korean Category Label ``` - `(\/m)?` — optional mobile path prefix - `\/section\/` — the URL path segment to match - `(.*)` — match anything after Page URL patterns include domain matching: ``` ^https\:\/\/(www|app|jpg|gjb|gjj|grp|\.)?josunhotel\.com(\/m)?\/section\/(.*) ``` - Multi-subdomain support via alternation group - Same `(\/m)?` mobile prefix handling ### Content Group Categories (Hospitality Reference) | Pattern | Category (KR) | Category (EN) | |---------|---------------|---------------| | `/intro.do`, `/main.do` | 메인페이지 | Main Page | | `/about/`, `/press/` | 기업 소개 | Corporate Info | | `/hotel/` | 호텔 소개 | Hotel Info | | `/rooms/` | 객실 소개 | Room Info | | `/dining/` | 다이닝 이용 | Dining | | `/facilities/`, `/meeting/`, `/fitness/` | 부대시설 소개 | Facilities | | `/package/`, `/event/` | 이벤트 \| 패키지 조회 | Events & Packages | | `/specialEvent/` | 캠페인 \| 프로모션 | Campaign & Promotion | | `/timesale/`, `/campaign/` *(placeholder — not actual paths yet, replace when specific paths are registered)* | 캠페인 \| 프로모션 | Campaign & Promotion | | `/activity/` | 액티비티 소개 | Activities | | `/step[0-4]` | 룸, 패키지 예약 프로세스 | Booking Process | | `/resve/dining/` | 다이닝 예약 프로세스 | Dining Booking | | `/membership/` | 멤버쉽 | Membership | | `/mypage/`, `/login/`, `/join/` | 웹회원 관련 | Member Portal | | `/retail/`, `/product/`, `/office/` | 리테일 관련 | Retail | | `/voc/`, `/customer/` | 고객지원 | Customer Support | | `/policy/` | 웹사이트 정책 | Website Policy | | `/upload_file/event/html/` | 캠페인 \| 프로모션 | Campaign & Promotion | | Default | Other | Other | ### Two Content Group Variables — Old vs New (JHR) The JHR container has two content group variables for menu categories: | | **Contents Group 2** (ID:1234) | **Contents Group new** (ID:1826) | |---|---|---| | Input | `{{Page Path}}` | `{{Page URL}}` | | Rules | 20 | 24 (replacement) | | Domain matching | No — path only | Yes — full URL with subdomain alternation | | Subdomain coverage | N/A | `www\|app\|jpg\|gjb\|gjj\|grp\|les\|\.` | | Cross-domain | No | Yes — booking, josuntns, lounge subdomains | | Mobile path | `(\/m)?` prefix | `(\/m)?` prefix within URL pattern | **"Contents Group new" (ID:1826) is the replacement** — it handles subdomains (booking, T&S, lounge, les) that the old path-based variable cannot distinguish. When auditing, check which variable is referenced in the GA4 config tag — the newer one should be used. **Gotcha — adding new subdomains**: When a new hotel brand subdomain launches (e.g., `les.josunhotel.com`), the subdomain alternation group `(www|app|...|les|\.)` in ALL main-domain rules must be updated. This affects 14+ rules in the URL-based variable. ### Audit Checklist for Content Grouping - [ ] Run `dtm var info ` to dump the full regex table - [ ] Check if new site sections have matching patterns - [ ] Verify both Path and URL variables are in sync - [ ] Check GA4 config tag references the correct variable - [ ] Test in GTM Preview: navigate to new page, check variable value - [ ] After update, verify in GA4 Realtime > Content Group report --- ## Performance Issues ### Tags Slowing Page Load **Symptoms**: High LCP, slow TTI **Causes**: 1. Too many synchronous tags 2. Large third-party scripts 3. Tags in wrong firing sequence **Fix**: 1. Use tag sequencing 2. Load non-critical tags on Window Loaded 3. Defer marketing tags