# Laravel Google Tag Manager This package provides a seamless Google Tag Manager integration for Laravel applications. It simplifies the management of GTM's dataLayer by offering a clean PHP API to set tracking data, handle events, and manage tag triggers without manually editing JavaScript. The package supports both immediate data injection and flash data for post-redirect scenarios. The core functionality revolves around the GoogleTagManager class which manages a DataLayer object that gets rendered as JSON in your page's head section. It includes middleware for handling session-based flash data, a facade for convenient access throughout your application, and Blade view components for easy script inclusion. The package supports dot notation for nested data structures, macros for reusable tracking patterns, and provides utilities for converting arrays to JSON for dynamic client-side pushing. ## Installation and Configuration Install via Composer and configure your GTM container ID ```bash composer require spatie/laravel-googletagmanager php artisan vendor:publish --provider="Spatie\GoogleTagManager\GoogleTagManagerServiceProvider" --tag="config" ``` ```php // config/googletagmanager.php return [ 'id' => env('GOOGLE_TAG_MANAGER_ID', 'GTM-XXXXXX'), 'enabled' => env('GOOGLE_TAG_MANAGER_ENABLED', true), 'sessionKey' => '_googleTagManager', 'domain' => 'www.googletagmanager.com', // or 'gtm.yourdomain.com' for server-side GTM ]; ``` ```php // app/Http/Kernel.php - Register middleware for flash functionality protected $middleware = [ \Illuminate\Session\Middleware\StartSession::class, \Spatie\GoogleTagManager\GoogleTagManagerMiddleware::class, ]; ``` ```blade {{-- resources/views/layouts/app.blade.php --}} @include('googletagmanager::head') @include('googletagmanager::body') {{-- Your content --}} ``` ## Setting Basic DataLayer Values Add data to the dataLayer that renders on page load ```php // app/Http/Controllers/ProductController.php use Spatie\GoogleTagManager\GoogleTagManagerFacade as GoogleTagManager; class ProductController extends Controller { public function show($id) { $product = Product::findOrFail($id); // Simple key-value pairs GoogleTagManager::set('pageType', 'productDetail'); GoogleTagManager::set('productId', $product->id); // Array data GoogleTagManager::set([ 'ecommerce' => [ 'detail' => [ 'products' => [[ 'name' => $product->name, 'id' => $product->id, 'price' => $product->price, 'brand' => $product->brand, 'category' => $product->category, ]] ] ] ]); // Dot notation for nested values GoogleTagManager::set('user.id', auth()->id()); GoogleTagManager::set('user.tier', auth()->user()->membership_tier); return view('products.show', compact('product')); } } ``` ```html ``` ## Flashing Data for Next Request Store dataLayer values that persist through redirects ```php // app/Http/Controllers/ContactController.php use Spatie\GoogleTagManager\GoogleTagManagerFacade as GoogleTagManager; class ContactController extends Controller { public function show() { // This data renders on current page GoogleTagManager::set('pageType', 'contact'); return view('contact.form'); } public function store(Request $request) { $validated = $request->validate([ 'name' => 'required', 'email' => 'required|email', 'message' => 'required', ]); // Send email, store in database, etc. // Flash data for the NEXT request (after redirect) GoogleTagManager::flash('event', 'form_submission'); GoogleTagManager::flash('formType', 'contact'); GoogleTagManager::flash('conversionValue', 100); // Flash also supports arrays and dot notation GoogleTagManager::flash([ 'user' => [ 'action' => 'contacted', 'timestamp' => now()->toIso8601String(), ] ]); return redirect()->route('contact.show') ->with('success', 'Thank you for contacting us!'); } } ``` ```html ``` ## Pushing Events After Page Load Push data to dataLayer after initial page load using the push functionality ```php // app/Http/Controllers/AuthController.php use Spatie\GoogleTagManager\GoogleTagManagerFacade as GoogleTagManager; class AuthController extends Controller { public function login(Request $request) { $credentials = $request->validate([ 'email' => 'required|email', 'password' => 'required', ]); if (Auth::attempt($credentials)) { // Push event that fires on page load via addEventListener GoogleTagManager::push([ 'event' => 'user_login', 'method' => 'email', 'userId' => auth()->id(), ]); return redirect()->intended('dashboard'); } return back()->withErrors(['email' => 'Invalid credentials']); } public function oauthCallback() { // Handle OAuth authentication $user = $this->handleOAuthCallback(); if ($user->wasRecentlyCreated) { // Push multiple events - order matters GoogleTagManager::flashPush(['event' => 'sign_up', 'method' => 'OAuth']); } GoogleTagManager::flashPush(['event' => 'login', 'method' => 'OAuth']); return redirect()->intended(); } } ``` ```html ``` ## Using DataLayer Class Directly Work with DataLayer objects for custom implementations ```php use Spatie\GoogleTagManager\DataLayer; use Spatie\GoogleTagManager\GoogleTagManagerFacade as GoogleTagManager; // Create standalone DataLayer instance $dataLayer = new DataLayer(); $dataLayer->set('product.name', 'Example Product'); $dataLayer->set('product.price', 29.99); // Convert to JSON echo $dataLayer->toJson(); // Output: {"product":{"name":"Example Product","price":29.99}} // Convert to array $array = $dataLayer->toArray(); // Output: ['product' => ['name' => 'Example Product', 'price' => 29.99]] // Access the main GoogleTagManager's DataLayer $mainDataLayer = GoogleTagManager::getDataLayer(); $currentData = $mainDataLayer->toArray(); // Clear all data $dataLayer->clear(); ``` ## Dumping Arrays to JSON for Client-Side Use Embed product data in HTML attributes for JavaScript tracking ```php // app/Http/Controllers/CategoryController.php class CategoryController extends Controller { public function show($slug) { $category = Category::where('slug', $slug)->firstOrFail(); $products = $category->products()->paginate(20); GoogleTagManager::set('pageType', 'category'); GoogleTagManager::set('categoryName', $category->name); return view('category.show', compact('category', 'products')); } } ``` ```blade {{-- resources/views/category/show.blade.php --}}
@foreach($products as $product) {{ $product->name }}

{{ $product->name }}

${{ $product->price }}

@endforeach
``` ## Creating Reusable Macros Define custom methods for common tracking patterns ```php // app/Providers/AppServiceProvider.php use Spatie\GoogleTagManager\GoogleTagManagerFacade as GoogleTagManager; class AppServiceProvider extends ServiceProvider { public function boot() { // Macro for ecommerce product impressions GoogleTagManager::macro('productImpression', function ($product, $list = 'Search Results') { GoogleTagManager::set('ecommerce', [ 'currencyCode' => 'USD', 'impressions' => [[ 'name' => $product->name, 'id' => $product->id, 'price' => $product->price, 'brand' => $product->brand, 'category' => $product->category, 'list' => $list, 'position' => $product->position ?? 1, ]] ]); }); // Macro for purchase tracking GoogleTagManager::macro('trackPurchase', function ($order) { GoogleTagManager::set('ecommerce', [ 'purchase' => [ 'actionField' => [ 'id' => $order->id, 'affiliation' => 'Online Store', 'revenue' => $order->total, 'tax' => $order->tax, 'shipping' => $order->shipping, 'coupon' => $order->coupon_code, ], 'products' => $order->items->map(fn($item) => [ 'name' => $item->product->name, 'id' => $item->product->id, 'price' => $item->price, 'quantity' => $item->quantity, 'category' => $item->product->category, ])->toArray() ] ]); }); } } ``` ```php // app/Http/Controllers/CheckoutController.php class CheckoutController extends Controller { public function success(Order $order) { // Use the macro GoogleTagManager::trackPurchase($order); GoogleTagManager::set('event', 'purchase_complete'); return view('checkout.success', compact('order')); } } ``` ## Enabling and Disabling GTM Control script rendering dynamically at runtime ```php use Spatie\GoogleTagManager\GoogleTagManagerFacade as GoogleTagManager; // Check current status if (GoogleTagManager::isEnabled()) { // GTM is active } // Disable GTM (useful for admin users, testing, etc.) GoogleTagManager::disable(); // Re-enable GTM GoogleTagManager::enable(); // Get GTM container ID $containerId = GoogleTagManager::id(); // Returns: GTM-XXXXXX // Change GTM ID at runtime (advanced use case) GoogleTagManager::setId('GTM-DIFFERENT'); ``` ```php // app/Http/Middleware/DisableGtmForAdmin.php class DisableGtmForAdmin { public function handle($request, Closure $next) { if (auth()->check() && auth()->user()->is_admin) { GoogleTagManager::disable(); } return $next($request); } } ``` ## Advanced E-commerce Tracking Example Complete checkout flow with enhanced ecommerce tracking ```php // app/Http/Controllers/CartController.php use Spatie\GoogleTagManager\GoogleTagManagerFacade as GoogleTagManager; class CartController extends Controller { public function add(Request $request, $productId) { $product = Product::findOrFail($productId); $quantity = $request->input('quantity', 1); Cart::add($product, $quantity); // Track add to cart event GoogleTagManager::flashPush([ 'event' => 'addToCart', 'ecommerce' => [ 'add' => [ 'products' => [[ 'name' => $product->name, 'id' => $product->id, 'price' => $product->price, 'brand' => $product->brand, 'category' => $product->category, 'quantity' => $quantity, ]] ] ] ]); return redirect()->back()->with('success', 'Product added to cart'); } public function index() { $cart = Cart::current(); GoogleTagManager::set('pageType', 'cart'); GoogleTagManager::set([ 'ecommerce' => [ 'checkout' => [ 'actionField' => ['step' => 1], 'products' => $cart->items->map(fn($item) => [ 'name' => $item->product->name, 'id' => $item->product->id, 'price' => $item->price, 'quantity' => $item->quantity, ])->toArray() ] ] ]); return view('cart.index', compact('cart')); } } ``` ## Summary This Laravel Google Tag Manager package provides a robust solution for integrating GTM into Laravel applications with minimal code. The primary use cases include e-commerce tracking (product impressions, add-to-cart events, purchases), user behavior analytics (page views, form submissions, user authentication), conversion tracking, and custom event monitoring. The package excels at managing the dataLayer through server-side PHP rather than client-side JavaScript, reducing implementation complexity and improving maintainability. Integration patterns typically involve setting up the middleware for flash functionality, including the Blade views in your layout template, and using the facade throughout controllers to push tracking data. The flash methods are particularly useful for post-redirect scenarios like form submissions and authentication flows. For complex implementations, macros allow you to define reusable tracking patterns in your service provider. The DataLayer class can be used standalone for custom integrations, API responses, or generating JSON data for JavaScript consumption. The package supports both traditional web applications and modern SPA patterns where client-side JavaScript needs access to product data for dynamic event tracking.