GTM Performance Audit
Analyze Google Tag Manager implementations for performance impact using Chrome DevTools MCP.
Philosophy
Tag managers are powerful but can silently degrade performance. Every tag has a cost.
Core Beliefs
- Measure Tag Impact Individually: Each tag's cost must be measured, not assumed
- Container Size Is a Leading Indicator: Large containers correlate with poor performance
- Triggers Are the Multiplier: Inefficient triggers amplify tag cost exponentially
- Server-Side Is the Future: Move data collection off the main thread when possible
Why GTM Audits Matter
- Invisible Performance Tax: Tags add up silently; no single tag seems costly
- Core Web Vitals Impact: GTM scripts affect LCP, INP, and CLS directly
- Third-Party Risk: Tags load external resources outside your control
- Consent Compliance: Tags firing before consent degrade trust and may violate regulations
When This Skill Activates
Activate this skill when the user:
- Mentions "GTM", "Google Tag Manager", or "tag manager"
- Says "too many tags" or "tracking is slow"
- Asks "are our marketing tags slowing the site?"
- Mentions "container size" or "tag execution"
- References "dataLayer", "custom HTML tags", or "trigger efficiency"
- Asks about "tag performance" or "third-party script impact"
- Shows GTM-related code and asks about performance
Decision Framework
Before auditing, determine the audit mode:
What Data Is Available?
- Live page with GTM → Full audit via Chrome DevTools MCP (best)
- Container JSON export + live page → Container analysis + live profiling (comprehensive)
- Container ID only → Infer from network requests on live page (limited)
- Code review only → Analyze GTM integration code in codebase (minimal)
What's the Goal?
- Quick check → Container size, tag count, obvious issues
- Standard audit → Full analysis with CWV impact mapping
- Comprehensive → Deep profiling with remediation plan and implementation steps
Decision Tree
User asks about GTM performance
|
v
URL provided? → NO → Ask for target URL (STOP until answered)
|
YES
|
v
Proceed autonomously (no further permission prompts needed)
|
v
Phase 1: Baseline Performance (before GTM analysis)
|
v
Phase 2: GTM Container Analysis
|
v
Phase 3: Issue Detection (14 checks)
|
v
Phase 4: Report Generation
Setup
Before starting the audit, gather from the user:
- Target URL (required) - The page to audit
- GTM Container ID (required) - Format: GTM-XXXXXXX
- Container JSON export (optional) - Exported from GTM admin
- Critical tags list (optional) - Tags that must not be removed
Phase 1: Baseline Performance
Measure page performance using the single-pass audit collector script — one evaluate_script call replaces all individual measurement scripts.
Step 1: Read the Collector Script
Read: agents/gtm-specialist/scripts/gtm-audit-collector.js
Step 2: Navigate and Run the Collector
mcp__chrome-devtools__navigate_page(url="<target-url>")
Wait for the page to fully load, then execute:
mcp__chrome-devtools__evaluate_script(function="<full content of gtm-audit-collector.js>")
This single call returns a structured JSON object containing:
- Navigation timing (TTFB, DCL, load complete)
- Paint metrics (FCP, first paint)
- Core Web Vitals (LCP with element, CLS, INP estimate, with ratings)
- Long Tasks / Total Blocking Time
- All
<head>scripts with blocking/async/defer status - All GTM and third-party tracking resources (40+ vendors)
- DataLayer contents and unique events
- Consent platform detection (Google Consent Mode v2, TrustArc, OneTrust, etc.)
- Window-global vendor fingerprinting (60+ vendors)
- GA4 Measurement IDs, Conversion IDs, legacy UA IDs
Step 3: Supplemental Data (if needed)
Run these only if the collector output is insufficient for a specific check:
Console errors (check for GTM JS errors):
mcp__chrome-devtools__list_console_messages()
Raw network waterfall (for precise HAR timing):
mcp__chrome-devtools__list_network_requests()
Deep CPU profiling (comprehensive depth mode only):
mcp__chrome-devtools__performance_start_trace(reload=true, autoStop=true)
mcp__chrome-devtools__performance_stop_trace()
Phase 2: GTM Container Analysis
If Container JSON Available
Parse the exported JSON to extract:
- Container size (bytes)
- Tag count by type (Custom HTML, Google Analytics, Floodlight, etc.)
- Trigger count and types (Page View, Click, Custom Event, etc.)
- Variable count and types (DataLayer, DOM Element, JavaScript, etc.)
- Tag firing sequences and dependencies
- Custom HTML content (inline scripts)
If Only Container ID Available
Infer container details from network data:
- Count tags from network requests
- Identify third-party domains loaded
- Measure script sizes and timing
- Check for known tag patterns (GA4, Meta Pixel, etc.)
DataLayer Analysis
// Use mcp__chrome-devtools__evaluate_script
() => {
if (typeof dataLayer === 'undefined') return { error: 'No dataLayer found' };
return {
eventCount: dataLayer.length,
events: dataLayer.map(item => ({
event: item.event || 'push',
keys: Object.keys(item)
})),
totalSize: JSON.stringify(dataLayer).length
};
}
Phase 3: Issue Detection
Run all 14 check categories:
1. Synchronous Script Loading
What: GTM container loaded with sync instead of async
Impact: Blocks HTML parsing, delays LCP
Check: Look for <script src="...gtm.js"> without async or defer
Fix: Ensure GTM snippet uses async loading pattern
2. Blocking Tags
What: Tags that block the main thread for >50ms Impact: Increases INP, degrades interactivity Check: Profile main thread during tag execution Fix: Defer non-critical tags, use tag sequencing
3. Large Payloads
What: Tags or container >100KB compressed Impact: Increases load time, wastes bandwidth Check: Measure transfer sizes of GTM resources Fix: Remove unused tags, optimize custom HTML, consider server-side
4. Main Thread Blocking
What: JavaScript execution blocks main thread Impact: Poor INP, delayed interaction response Check: Use performance trace to measure long tasks Fix: Break up long-running tag scripts, use Web Workers where possible
5. Missing Conditional Firing
What: Tags fire on all pages when only needed on specific pages Impact: Unnecessary processing and network requests Check: Analyze trigger conditions vs. page types Fix: Add page path or event conditions to triggers
6. Trigger Optimization
What: Triggers using expensive DOM selectors or all-pages rules Impact: Excessive event listener overhead Check: Review trigger configurations for broad matching Fix: Use specific CSS selectors, limit to relevant pages
7. Duplicate Tags
What: Same tracking pixel or analytics tag firing multiple times Impact: Inflated metrics, wasted resources, double-counting Check: Compare tag endpoints and parameters Fix: Remove duplicates, consolidate similar tags
8. Orphaned Tags
What: Tags with no active triggers (paused or misconfigured) Impact: Container bloat, maintenance burden Check: Cross-reference tags with their trigger assignments Fix: Remove or archive orphaned tags
9. Expensive Variables
What: Variables using DOM lookups or complex JavaScript on every evaluation Impact: Repeated expensive computations Check: Review variable types and computation cost Fix: Cache values in dataLayer, use simpler variable types
10. Missing Async Attribute
What: Third-party scripts injected by tags without async/defer Impact: Render-blocking, delays page load Check: Inspect Custom HTML tags for script injection patterns Fix: Add async attribute to injected scripts
11. Custom HTML Best Practices
What: Custom HTML tags with inline scripts that could use built-in tag types Impact: Security risk, harder to maintain, potentially blocking Check: Analyze Custom HTML content for convertible patterns Fix: Convert to built-in tag templates where possible
12. Server-Side Candidates
What: Tags that could run server-side instead of client-side Impact: Reduces client-side JavaScript, improves performance Check: Identify tags sending data to first-party or server endpoints Fix: Migrate eligible tags to server-side GTM container
13. Consent Mode Gaps
What: Tags firing before consent is granted Impact: Privacy violations, regulatory risk Check: Verify consent mode integration and tag firing sequence Fix: Implement Google Consent Mode, add consent triggers
14. Tag Firing Order
What: Critical tags delayed by non-essential tags in the sequence Impact: Important data collection delayed Check: Review tag priority settings and sequencing Fix: Set proper priority values, use tag sequencing groups
Phase 4: Report Generation
Executive Summary
## GTM Performance Audit Summary
**Container**: GTM-XXXXXXX
**URL Tested**: https://example.com
**Date**: YYYY-MM-DD
### Key Metrics
- Container Size: XXX KB (compressed)
- Total Tags: NN (XX active, YY paused)
- GTM Load Time: XXXms
- Main Thread Blocking: XXXms
- Estimated CWV Impact: [Low/Medium/High]
### Quick Wins
1. [Quick win with estimated impact]
2. [Quick win with estimated impact]
3. [Quick win with estimated impact]
Detailed Findings
Each finding should include:
- Description: What the issue is
- Measurement: Quantified impact (ms, KB, count)
- CWV Impact: Which Core Web Vital is affected and by how much
- GTM Fix Steps: Specific steps to fix in GTM admin
- Risk Assessment: Low/Medium/High risk of the fix
- Priority: Critical/High/Medium/Low
Tag Inventory Table
| Tag Name | Type | Trigger | Size | Exec Time | Status |
|----------|------|---------|------|-----------|--------|
| GA4 | Google Analytics | All Pages | 45KB | 120ms | Active |
| Meta Pixel | Custom HTML | All Pages | 32KB | 85ms | Active |
| Hotjar | Custom HTML | Page View | 28KB | 200ms | Active |
Network Waterfall
Show timing of GTM-related requests:
0ms 100ms 200ms 300ms 400ms 500ms
|--------|--------|--------|--------|--------|
[==GTM Container (45KB)==]
[====GA4 (32KB)====]
[==Meta Pixel==]
[====Hotjar (28KB)====]
[=LinkedIn=]
Implementation Checklist
## Remediation Checklist
### Critical (Do This Week)
- [ ] Remove duplicate GA4 tag (saves ~120ms)
- [ ] Add async to Custom HTML script injections
### High Priority (Do This Sprint)
- [ ] Add page path conditions to 5 all-pages tags
- [ ] Convert 3 Custom HTML tags to built-in templates
- [ ] Remove 4 orphaned tags (saves ~15KB)
### Medium Priority (Plan for Next Sprint)
- [ ] Evaluate server-side GTM for conversion tags
- [ ] Implement consent mode v2
- [ ] Optimize dataLayer push frequency
### Low Priority (Backlog)
- [ ] Consolidate similar event triggers
- [ ] Review variable caching strategy
Required MCP Integration
This skill requires Chrome DevTools MCP. Tools used:
mcp__chrome-devtools__evaluate_script- Execute JavaScript for timing, dataLayer, resource analysismcp__chrome-devtools__list_network_requests- Capture GTM network waterfallmcp__chrome-devtools__list_console_messages- Check for GTM errorsmcp__chrome-devtools__navigate_page- Navigate to target URLmcp__chrome-devtools__take_snapshot- Get page structure for tag detectionmcp__chrome-devtools__performance_start_trace- Start performance profilingmcp__chrome-devtools__performance_stop_trace- Stop profiling and get resultsmcp__chrome-devtools__new_page- Open fresh tab for clean measurement
CMS-Specific GTM Patterns
Drupal
Common GTM Integration:
google_tagmodule (most common)- Custom
html.html.twiginjection - Config at
/admin/config/services/google-tag
Check for:
- Module configuration:
drush config:get google_tag.settings - Container ID in config vs. hardcoded in templates
- Multiple containers (module + theme + custom module)
- DataLayer integration via
hook_google_tag_snippets_alter()
WordPress
Common GTM Integration:
- GTM4WP plugin (most common)
- Google Site Kit plugin
- Manual
header.phpinjection - Theme
functions.phpviawp_headaction
Check for:
- Plugin settings: GTM4WP → Settings → Container ID
- Multiple injection points (plugin + theme + another plugin)
- DataLayer population via WooCommerce integration
- Custom event tracking in theme JavaScript
Guardrails
- Read-only: Never modify GTM containers, tags, triggers, or variables
- No credentials: Never ask for or enter GTM admin credentials
- Conservative estimates: When unsure of impact, estimate conservatively
- Preserve functionality: Recommendations must not break tracking
- Privacy-aware: Flag consent issues but don't disable tags
Integration with /audit-gtm Command
-
This Skill: Focused GTM analysis during conversation
- "Are our marketing tags slow?"
- "How big is our GTM container?"
- Single-tag or quick analysis
-
/audit-gtmCommand: Comprehensive GTM performance audit- Full container analysis
- All 14 check categories
- Detailed report with remediation plan
Quick Tips
- Container under 50KB compressed is healthy; over 100KB needs attention
- More than 30 active tags usually indicates cleanup opportunity
- Custom HTML tags are the biggest performance risk - audit these first
- All Pages triggers are the most common source of waste
- dataLayer pushes before GTM loads are queued and processed in order