awcodes/gtm
A lightweight Laravel and Filament package for adding Google Tag Manager to your app. Set your GTM container ID, inject the required scripts, and push dataLayer events without editing your Blade views—a quick, clean analytics setup.
enabled prop and gtm.enabled config are both true — encodes "on in production, dark in local/CI/staging" in configuration rather than in layout conditionals. That is the PM-relevant property: tracking state shows up in a diff and applies consistently across app, admin, and Filament surfaces without per-template negotiation.x-gtm::no-script, which read config('site.gtm.id') while the package publishes config/gtm.php — no site namespace exists — so the noscript iframe emitted an empty container ID and reported nothing. Any dashboard, funnel, or audience-size figure that assumed "GTM sees all sessions" was quietly overstated in coverage for the no-JS segment. Historical "no-JS share of sessions" is an artefact of a broken tag, not a measurement, and should not inform channel-mix, capacity, or funnel-completion decisions.page_view pushes, consent gating — none of which this package addresses.docs/, including an explicit statement of the two-level enable rule, reduces dependence on whoever originally wired up tag management. That informs staffing ("can a generalist engineer add a tag?" vs. "do we need a dedicated analytics engineer?") and shortens the debugging path for the most common support question: why does this page render no GTM markup?enabled prop × gtm.enabled config. Useful when deciding whether to certify the dependency for anything load-bearing.Explicitly not supported: event schemas, data-layer validation, server-side tagging, SPA route-change pushes, and consent capture or enforcement. If the product question is what we track and how we guarantee it fires, this is the wrong level of abstraction — it renders tags, it does not define them.
Adopt when:
enabled prop × gtm.enabled matrix expresses the whole policy in config, with no layout conditionals.Look elsewhere when:
page_view on client-side transitions needs explicit pushes the package does not provide; you would be adopting it for initial load only.For executives: This is a maintenance-grade dependency that places Google Tag Manager on our Laravel pages through two Blade components and a config file — no application code, no schema, no routes. The release under review, v2.0.1, is a patch: no new features, no breaking changes. It fixes a defect where visitors browsing without JavaScript were never counted, because the fallback tag rendered with an empty container ID. That segment has been understated silently, with no error and no failing test. Correcting it is a routine upgrade plus a staging smoke check. The release also ships documentation, reducing our dependence on any one engineer for tag management. Cost: a version bump, a rendered-HTML check, and a note on the GA4 property so the small step-change in sessions is not misread as growth.
For engineering: Upgrade past v2.0.1 before anyone relies on noscript page views. x-gtm::no-script read config('site.gtm.id') while the package publishes config/gtm.php — no site namespace exists — so the iframe emitted an empty id. x-gtm::script was unaffected, which is exactly why it survived: the old suite asserted the container ID appeared somewhere in combined output, and the healthy script tag satisfied that check. The new suite tests each component separately, covers all four combinations of enabled × gtm.enabled, and repairs a test-environment bug (gtm.active vs gtm.enabled). Three operational notes: tags render only when both keys are true — deliberate, now documented, not a bug when you hit it in staging; clear or rebuild cached config on deploy so a stale gtm.id does not mask the fix; and if we patched around this with a site.gtm.id entry or an overridden no-script view, delete both in the same commit, or we retain a dead config key and a view that drifts from corrected upstream.
For the product team: Anything downstream of GTM that assumed complete traffic coverage is affected — funnel drop-off, audience sizes, and any channel where a meaningful share of sessions are no-JS, privacy-hardened, or preview/render traffic. After the upgrade, expect a step change in reported volume for that segment; brief whoever owns the dashboards before the deploy lands so it is not read as a campaign effect or a tracking regression. Two things to hold: the historical baseline for "no-JS share of sessions" is an artefact of a broken tag, not a measurement, so do not use it for channel-mix or capacity decisions; and this package only renders tags — deciding which events exist, and honouring consent before they fire, remains our responsibility, not the dependency's.
How can I help you explore Laravel packages today?