liberusoftware/analytics-google-livewire
A Laravel Livewire package for displaying Google Analytics data directly in your components. Fetch and render metrics, charts, and reports without leaving your Livewire views, keeping analytics dashboards simple and reactive.
This is a presentation adapter, not an analytics client. Expect it to depend on a sibling package (something like liberusoftware/analytics-google) that owns the Data API calls, credentials, and caching, while this package supplies Livewire components and Blade views on top. Read the sibling package first if you want to understand anything beyond the component surface.
Minimal path:
composer require liberusoftware/analytics-google-livewire
php artisan vendor:publish --provider="Liberu\Analytics\Google\Livewire\AnalyticsGoogleLivewireServiceProvider"
Then confirm three things before writing a single line of your own code:
src/...ServiceProvider.php or src/Providers/) — this tells you whether components are auto-registered via Livewire::component() / namespace discovery, whether views are publishable, whether routes or a dashboard page are registered, and what config keys exist.config/analytics-google-livewire.php — usually the place for property ID, cache TTL, default date range, and view namespace. If the file isn't there, config is probably inherited from the core analytics package.src/Livewire/ — the component list is the real API surface. Names are self-documenting in packages like this (Dashboard, RealtimeVisitors, TopPages, TrafficSources, DateRangePicker).First use case: drop the dashboard component into an existing authenticated Blade view.
<livewire:analytics-google-livewire.dashboard />
or, if registration is class-based:
<livewire:liberu.analytics.google.livewire.dashboard />
If the tag errors with "component not found," you have your answer on registration style — check the provider. Do not guess past that point; the rest of the package's ergonomics depend on which Livewire major it targets (see Gotchas).
Before you build anything, verify credentials end-to-end with the underlying client (php artisan tinker, call the core service, dump a report). Debugging a credentials problem through a Livewire component is needlessly painful.
Parameterise at the component boundary. Presentation adapters usually accept public properties for property ID, date range, and dimensions. Keep those as Livewire props rather than editing config per environment:
<livewire:analytics-google-livewire.dashboard
:property-id="$tenant->ga_property_id"
from="30daysAgo"
to="today"
/>
Wire them with #[Url] if you want shareable dashboard links — that's usually the highest-value small addition you can make.
Wrap in a layout, don't fight the package's markup. Published views will be Tailwind-shaped and opinionated. Override by publishing views into resources/views/vendor/... and editing, or by wrapping the component in your own container and hiding the package's chrome with CSS. Forking the Blade file is cheaper than trying to restyle via props that may not exist.
Compose a page from several widgets rather than one mega-component. If the adapter ships granular components, a typical page is: date-range picker (top), KPI cards, a chart, a table, and a realtime counter. Give each wire:key and, if the component supports it, lazy-load the expensive tables with #[Lazy].
Realtime needs polling; reports need caching. For a live-visitors counter, wire:poll.30s (or the component's built-in interval prop) is normal. For historical reports, rely on the core package's cache and set TTL via config — hitting the GA4 Data API on every render is the single fastest way to burn your quota. If there's no cache layer, add one at your call site keyed on property_id + metrics + dimensions + date_range.
Extend through the public component API, not by subclassing Blade. Subclassing Livewire components in a presentation package is brittle because render() binds to a view name you don't control. Prefer: publish views, publish config, and if you need new data, call the underlying analytics service directly in your own component and reuse the package's views as partials.
Testing. Livewire::test(Dashboard::class)->assertSee(...) works only if the component doesn't make real API calls in the test. If there's no injection seam, bind a fake analytics client in the container in setUp() — or set a fake/mock cache and pre-warm it, which is often the only lever this kind of adapter gives you. Assume you'll need Http::fake() or a mocked core service.
Multi-tenant. In a Liberu-style modular app, per-tenant GA properties are the norm. Resolve the property ID in a middleware or from auth()->user()->team, pass it down as a prop, and — critically — include it in any cache key you control. Cross-tenant leakage via a shared cache key is the classic failure here.
composer.json, and expect breaking changes. The release date is in the future relative to normal package cadence, so verify what tag you're actually installing (composer show after install).viewId/UA- properties, it's not usable for new work regardless of what the components look like.403 PERMISSION_DENIED that looks like an auth bug. Check this before touching config.GOOGLE_APPLICATION_CREDENTIALS or a JSON path from config frequently resolve relative paths against a surprising base. Use an absolute path, and clear config:cache after changes — a cached config with a stale property ID is the most common "it worked yesterday" bug.config('app.timezone'). Date ranges that look off by a day are almost always this, not a bug in the component.Livewire::component('namespace.alias', Class::class) and namespaced tags; Livewire 2 relies on Livewire\Livewire::component() plus the older <livewire:...> syntax. Check composer.json constraints for livewire/livewire — if it allows both, the package is probably 2-era and will need a fork for Livewire 3 (wire:model → wire:model.live, $listeners removal).@push Chart.js or Alpine will double-register if your layout already loads them, causing odd chart behaviour (empty canvases, double tooltips). Check the component's render() for @assets/@push directives and remove one side.rescue() API errors so the widget renders empty. An empty chart means "check logs," not "no traffic." Wrap the component in a try/catch or check the package's logging channel before assuming your data is correct.dataProvider-style binding or an injectable analytics service in the container. If it exists, use it for testing and for adding metrics — it's the only clean seam this kind of package usually offers. If it doesn't, contribute one before you build anything on top.How can I help you explore Laravel packages today?