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

fluffydiscord/google-analytics-bundle

A Symfony bundle for integrating Google Analytics into your application, providing configuration and helpers to add tracking code and monitor page views and user activity from within your Symfony project.

View on GitHub
Deep Wiki
Context7

Getting Started

Start by confirming how the package is wired into your layout, since v2.2.0 changes the data layer path from a fetch wrapper to a Stimulus controller.

  1. Install/update the package and republish any published assets if the package ships its JS separately. The new files are:
    • assets/src/data_layer_controller.js
    • assets/src/analytics_events.js
  2. Include the head helper in your main layout:
    <head>
        {{ google_analytics_head() }}
    </head>
    
    This now renders the dataLayer bootstrap with a data-controller attribute.
  3. Check the Stimulus identifier in config/*.php:
    'stimulus_controller_name' => 'data-layer',
    
    Only change this if you already use that identifier for another controller. The rendered data-controller value must match the registered Stimulus controller name.
  4. Ensure the controller is registered in your Stimulus application. If you use Laravel’s default Stimulus setup, confirm the package’s controller is imported and registered, or add it explicitly:
    import DataLayerController from './../../vendor/.../data_layer_controller'
    application.register('data-layer', DataLayerController)
    
    Use the identifier configured in stimulus_controller_name.
  5. First use case: open a page containing a Live Component and perform an interaction that causes a re-render. The controller listens for render:started, reads the events collected by that response, and pushes them into the data layer. Inspect window.dataLayer in the browser console to confirm the payloads.

If you previously called the documented fetch wrapper for your own AJAX requests, that path is replaced. For custom requests, call pushAnalyticsEvents(response) from analytics_events.js after the response resolves.

Implementation Patterns

Automatic Live Component tracking

The primary day-to-day path is now automatic. data_layer_controller.js hooks every Live Component’s render:started event and pushes the events returned in that response. In practice:

  • You no longer need to manually push data layer events after a Live Component action if the component response already collects analytics events.
  • The controller acts as the bridge between Live Component responses and the dataLayer.
  • This keeps analytics concerns out of individual component templates and Alpine handlers.

A typical Live Component action remains unchanged:

public function addToCart()
{
    Cart::add($this->product);

    $this->dispatchBrowserEvent('cart-updated');

    // Analytics events are collected by the package's Live Component integration.
}

Then verify in the browser:

window.dataLayer

Tracking your own AJAX calls

For shop-side AJAX calls that do not go through a Live Component, use the exposed helper:

import { pushAnalyticsEvents } from './../../vendor/.../analytics_events'

const response = await fetch('/cart/add', {
    method: 'POST',
    headers: { 'X-Requested-With': 'XMLHttpRequest' },
})

await pushAnalyticsEvents(response)

The helper expects the same response shape used by the Live Component bridge. Confirm the exact contract in assets/src/analytics_events.js; typically this means a JSON response containing whatever event payloads the server collected.

Reacting to pushed events

Every pushed payload is also dispatched as an analytics:event CustomEvent. This is useful when you need to forward events to another system or add client-side enrichment:

window.addEventListener('analytics:event', (event) => {
    // event.detail contains the pushed payload
    console.log('Analytics event:', event.detail)

    // Example: forward to a non-GA endpoint
    navigator.sendBeacon('/analytics/collect', JSON.stringify(event.detail))
})

This is also a good place to add consent checks, debug logging, or transformation for downstream tools.

Integrating with GTM or a custom data layer

The package bootstraps dataLayer through google_analytics_head(). If you use Google Tag Manager, ensure your GTM snippet runs after the package bootstrap but still reads from the same dataLayer array. Avoid declaring a second independent dataLayer unless you intentionally isolate it.

A practical order in Blade:

<head>
    {{ google_analytics_head() }}

    {{-- GTM or analytics.js snippet --}}
    @include('partials.gtm')
</head>

Configuring the Stimulus identifier

If your application already registers a controller named data-layer, change the package config rather than renaming your own controller:

// config/analytics.php (or the package config file)
'stimulus_controller_name' => 'shop-data-layer',

Then make sure the same identifier is registered:

application.register('shop-data-layer', DataLayerController)

Clear config cache after changing it:

php artisan config:clear

Gotchas and Tips

  • Breaking change from the fetch wrapper. Any code, Blade partial, or documentation snippet still calling the old fetch wrapper must move to pushAnalyticsEvents(response) for custom AJAX calls. Live Component tracking is now handled by the Stimulus controller instead.
  • The controller must actually be registered. google_analytics_head() renders the data-controller attribute, but if the controller is missing from your Stimulus app, nothing will push. Check the browser console for “controller not found” style errors.
  • Identifier mismatch is silent. If stimulus_controller_name does not match the registered Stimulus identifier, the data layer bootstrap may render but no bridge will run. Keep the config and application.register(...) value in sync.
  • Live Component events are only pushed if the response collected them. The controller forwards what the response provides; it does not synthesize events. If an interaction is missing from dataLayer, inspect the Live Component response and the server-side event collection first.
  • Avoid double-pushing. If you manually call pushAnalyticsEvents(response) for a request that is already handled by the Live Component bridge, you will push the same payload twice. Use the manual helper only for non-Live-Component AJAX calls.
  • Inspect analytics:event for debugging. The CustomEvent is the easiest place to confirm the payload shape before it reaches GTM or GA. Add a temporary listener and log event.detail.
  • Check script order. The data layer must exist before analytics or GTM processes events. Keep google_analytics_head() before your analytics/GTM snippet, and avoid moving it into a deferred bundle unless you also defer all consumers.
  • Config caching can hide changes. After editing stimulus_controller_name, run php artisan config:clear (and config:cache in production if that is your deployment practice).
  • CSP and asset publishing. The new controller lives under assets/src. If you publish or compile package assets, confirm the compiled controller is included in your build and allowed by your Content Security Policy.
  • Consent mode. If your shop requires consent before analytics storage, gate the analytics:event forwarding or your GTM triggers. The package pushes to dataLayer; whether those events become hits depends on your tag configuration and consent settings.
  • Nested Live Components. render:started can fire for multiple components. If you see more events than expected, verify whether nested component renders are also collecting and pushing payloads.
  • Testing strategy. Add a browser-level test that performs a Live Component interaction, waits for the response, and asserts that window.dataLayer contains the expected event. For custom AJAX, assert that pushAnalyticsEvents was called and that the corresponding analytics:event was dispatched.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource