Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Google Analytics Bundle Laravel Package

setono/google-analytics-bundle

A Symfony bundle for Google Analytics integration that lets you configure tracking, send page views and events, and manage analytics settings from services and templates with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: this is a Symfony bundle, not a Laravel package. It ships a Bundle class, a DI extension, a config tree, and a Twig extension. You cannot composer require it into a Laravel app and expect anything to boot — there is no service provider, no Blade directive, no facade. If you are on Laravel, treat this assessment as "what the bundle does and how to port/replicate it"; if you are on Symfony, use it directly.

Minimal steps (Symfony):

  1. composer require setono/google-analytics-bundle
  2. Register Setono\GoogleAnalyticsBundle\SetonoGoogleAnalyticsBundle in config/bundles.php
  3. Add the config with your GA4 measurement ID (the G-XXXXXXXXXX one — not a UA- property):
# config/packages/setono_google_analytics.yaml
setono_google_analytics:
    tracking_id: '%env(GOOGLE_ANALYTICS_ID)%'
  1. Render the snippet once, high in <head>, in your base layout via the bundle's Twig extension (check src/Twig/ for the exact function name — the API surface here is small and autocompletes in your IDE):
<head>
    {{ google_analytics() }}
</head>

Where to look first, in this order:

  • src/DependencyInjection/Configuration.php — the only authoritative list of config keys. Docs are thin for a 1-star package; the config tree is the docs.
  • src/Twig/ — the render entry point and whether it emits gtag.js inline or via a template partial.
  • src/Renderer/ (or equivalent) — the service that builds the JS. This is your decoration/override point.

First real use case: page-view tracking falls out of step 4 for free. The moment you get value is the first conversion event — a purchase fired from your success page or, better, a server-rendered dataLayer push immediately after checkout. That's the pattern you'll reuse for every other event.

Laravel reality check: the cheapest port is a Blade component (<x-ga4-snippet :id="config('services.ga4.id')" />) plus a small Ga4Events service that serializes events to a window.dataLayer.push(...) array in a @push('scripts') stack. You do not need this bundle to do that — but reading its renderer is a good reference for what GA4 actually requires (consent defaults, gtag('config', ...), send_page_view).

Implementation Patterns

One snippet, many events. Rendering the snippet is the bundle's whole job; everything else is your event plumbing. Keep a single server-side service that accumulates events and renders them once per request — do not call the renderer per component, or you'll emit nested gtag('config') calls and duplicate page views.

Server-triggered, client-executed. The pattern that survives ad blockers and SPA navigations reasonably well: compute the payload in PHP after the business action (order placed, signup confirmed), stash it in the session/flash or a view variable, render it as a dataLayer.push on the next page. In Symfony you'd do this via an event subscriber on kernel.response or by decorating the renderer to append queued events. In Laravel: a Ga4Queue singleton resolved in a middleware that flushes into the Blade stack.

// the shape you want, regardless of framework
$events = [
    ['name' => 'purchase', 'params' => [
        'transaction_id' => $order->number,
        'value'          => (float) $order->total,
        'currency'       => 'DKK',
        'items'          => $order->lines->map(fn ($l) => [
            'item_id'   => $l->sku,
            'item_name' => $l->name,
            'price'     => (float) $l->price,
            'quantity'  => $l->qty,
        ])->all(),
    ]],
];

Consent gating is a first-class concern, not an afterthought. GA4 in the EU means gtag('consent', 'default', {...}) before the config call, then an update on banner accept. If the bundle renders the config unconditionally you'll either (a) violate consent requirements or (b) need to decorate the renderer to emit the consent block first. Budget for this on day one — retrofitting it after a legal review is painful because it changes snippet ordering.

Multi-domain / subdomain setups. Set the cookie domain explicitly if you track across www. and app subdomains; cross-domain measurement additionally requires linker config. This is the class of thing the bundle can't decide for you.

Don't double up with GTM. If you already load Google Tag Manager, do not also use this bundle to render gtag.js. Pick one loader. Running both produces duplicated page_view hits and confusing DebugView output — and it's the single most common misconfiguration in this space.

Testing. Assert on rendered output rather than on Google: decode the dataLayer JSON from the response body in a feature test and assert event names/params. Never make a real hit to google-analytics.com in CI.

Reporting is a different package. This bundle sends tracking data (client-side beacon). It does not read reports. If what you actually wanted was "show me pageviews in my dashboard", you want the GA4 Data API (google/analytics-data + a thin wrapper, or spatie/laravel-analytics on Laravel). Mixing up these two is a very common evaluation mistake.

Gotchas and Tips

  • Measurement ID format. GA4 only. A UA- ID will silently no-op. Also confirm you're not pasting the property ID (a bare integer) — that's for the Data API, not for gtag.
  • Client-side only. Despite the Symfony service container, this bundle does not implement the Measurement Protocol. There is no reliable server-to-server conversion tracking here; anything you "fire" is really a queued JS push. If you need server-side (ad-blocker-proof) events, that's a separate Measurement Protocol client and an api_secret.
  • CSP will eat the inline script. The snippet is inline JS. With a strict script-src you need a nonce or hash. Check whether the renderer exposes a nonce option; if not, decorate it or move the bootstrap to an external file.
  • Full-page caching. If you cache rendered HTML, you cache the snippet — including any user-specific event payloads. Flush event-bearing responses or render events in a non-cached fragment.
  • Debugging loop: append debug_mode: true (or _dbg), open GA4 → Admin → DebugView, and watch the browser Network tab for POST /g/collect. If the request never appears, it's a JS/CSP/consent problem, not a bundle problem. If it appears but DebugView is empty, it's an ID/property mismatch.
  • Vendor risk is real and material. One star, zero dependents, last release 2023-09-12. There is no community backstop. Pin an exact version in composer.json, read Configuration.php before trusting any blog post, and assume you may need to fork. The code is MIT and the surface is small — a fork is hours, not weeks, which is the main thing that makes this tolerable.
  • Twig coupling. If you're bridging into a non-Symfony app, the Twig extension is the part you throw away. The renderer logic is the part worth porting.
  • Extension point: decorate the renderer service (decorates: setono_google_analytics.renderer) rather than editing vendor code — that's where consent blocks, nonces, and custom gtag config belong.
  • Ordering matters. Consent default → gtag('js') → gtag('config') → events. Any deviation and GA4 drops or misattributes hits, and it will not warn you.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib