GTM audit and fix · Playbook
GTM audit and fix full-audit evidence contract
Beru merges evidence; it does not invent browser observations or mutate GTM. Each optional input is a JSON object. Missing evidence is named as a limitation, never converted into a pass.
Page surface
Pass Ampharos’ normal ampharos.json unchanged with --surface-json. Beru reads pages[].url and
pages[].tags[] (key, label, ids) to detect direct HTML installations that duplicate destinations
configured in GTM.
Runtime journeys
--runtime-json accepts a shared capture envelope or a direct object:
{
"source": "browser capture",
"tool": "Chromium",
"capturedAt": "2026-09-05T00:00:00Z",
"settleMs": 12000,
"artifacts": ["evidence/runtime-home.json"],
"data": {
"journeys": [
{
"name": "contact submit after consent",
"url": "https://example.com/contact",
"consent": "accepted",
"action": "submit",
"requests": [
{ "url": "https://www.google-analytics.com/g/collect?tid=G-XXXX&en=generate_lead" }
]
}
]
}
}
Keep capture provenance at the envelope root. Beru renders the source/tool, capture timestamp, settle window and raw-artifact paths so a reviewer can reproduce the claim instead of receiving an orphaned summary.
Use explicit consent states: pre-consent, rejected, or accepted. unknown is not treated as a
pre-consent failure. Capture a fresh browser profile for consent tests and define the representative
journey set before interpreting an absence.
Environment contract
--contract-json makes “wrong configuration” deterministic and permits intentional multi-property
tagging without a false positive:
{
"environment": "production",
"tracking": "enabled",
"allowed": {
"gtm": ["GTM-XXXX"],
"ga4": ["G-PRIMARY", "G-ROLLUP"],
"ads": ["AW-123456789"]
},
"requiredEvents": ["page_view", "generate_lead", "phone_click"],
"disallowedVendors": ["hotjar"]
}
An observed or configured identifier outside the relevant allowlist is a FAIL. Multiple identifiers
inside an allowlist are intentional by contract, not “sprawl.” A required event absent from the supplied
journeys is REVIEW because trigger coverage or implementation may be incomplete. A disallowed vendor that
is observed firing is FAIL and, when the capture includes gtmTagId/gtmTagName, the remediation names the
exact GTM object to pause. This is how “no longer used” becomes evidence—not by guessing from one quiet load.
Performance comparison
The same file may carry a recorded before/after baseline. Keep field and lab evidence separate:
{
"before": {
"desktop": {
"lighthouse": 36,
"verdict": "FAIL",
"lab": { "lcpMs": 3800, "cls": 0.44, "tbtMs": 398, "lcpBreakdown": { "dominant": "element-render-delay", "ms": 1250 } },
"field": { "rating": "good", "lcpMs": 2000, "inpMs": 100, "cls": 0.01 }
},
"mobile": {
"lighthouse": 51,
"verdict": "REVIEW",
"lab": { "lcpMs": 19800, "fcpMs": 5300, "ttiMs": 21700 },
"field": { "rating": "good", "lcpMs": 2000, "inpMs": 100, "cls": 0.01 }
}
}
}
Add after with the same shape after remediation. Beru calls out a healthy-field/slow-lab split
instead of implying the synthetic worst case describes every real visitor. When BEFORE exists without
AFTER, the report marks validation pending rather than making the baseline look like a completed fix.
Performance evidence may also carry ranked site-level opportunities that are outside GTM but explain the same trace. These are evidence inputs, not conclusions Beru invents:
{
"source": "PageSpeed Insights",
"toolVersion": "Lighthouse 13.4.1",
"capturedAt": "2026-09-04T00:00:00Z",
"artifacts": ["evidence/psi-desktop.json", "evidence/psi-mobile.json"],
"opportunities": [
{
"priority": "high",
"scope": "site performance",
"title": "Optimize oversized third-party images",
"evidence": "Approximately 40MB transferred from a development CDN in the recorded trace.",
"change": "Move approved assets to the production CDN, compress them, and provide dimensions.",
"verification": "Repeat the same profile and confirm lower transfer plus stable CLS.",
"rollback": "Restore the prior asset URLs if delivery fails."
}
]
}
Do not rephrase a Lighthouse opportunity as GTM causation. Scope it separately and retain the measured evidence that supports the rank.
For attribution, add the controlled comparison:
{
"comparison": {
"runs": 3,
"sameUrl": true,
"sameDevice": true,
"enabled": { "metrics": { "lcpMs": 2500, "tbtMs": 500, "transferBytes": 900000, "requests": 80, "mainThreadMs": 1200 } },
"blocked": { "metrics": { "lcpMs": 2100, "tbtMs": 250, "transferBytes": 600000, "requests": 60, "mainThreadMs": 700 } }
}
}
Beru labels this a controlled comparison only when URL and device match and runs >= 3. Otherwise the
delta is directional. Blocking all GTM measures the combined tag-manager ecosystem cost; isolate a vendor
or tag separately before attributing the delta to that individual component.
Report order
The client-readable report leads with the recorded BEFORE baseline and optional AFTER validation, then field-versus-lab nuance, the browser-observed beacon matrix, measured GTM impact, and ranked remediation. Detailed container inventory remains supporting evidence rather than burying the decision.
Safe remediation
Recommendations contain priority, change, verification and rollback. Apply them with beru fix in a new
workspace. Prefer pause-before-delete, preview every contracted journey, publish separately, and retain the
prior live version for rollback. “Not observed” never authorizes deletion.