spatie/laravel-analytics
Retrieve data from Google Analytics in your Laravel app with spatie/laravel-analytics. Simple methods like fetchMostVisitedPages and fetchVisitorsAndPageViews return Laravel collections, with easy Composer installation and publishable config.
Architecture fit
spatie/laravel-analytics is a thin, read-through adapter over the Google Analytics 4 Data API, exposed as a Laravel facade (Spatie\Analytics\Facades\Analytics) returning Illuminate\Support\Collection instances. It is deliberately not an ETL tool, a warehouse loader, or a metrics store — it holds no state beyond an optional cache.
That makes the fit decision binary and easy to reason about:
A TPM should frame this as a buy-vs-build on ~500 lines of glue code: the package replaces a google/analytics-data client wrapper plus credential/config plumbing. The value is not capability, it's compression of undifferentiated work.
Integration feasibility
The path is well-trodden and fully documented: Composer install → publish config/analytics.php → create a GCP project → enable the Analytics Data API → generate a service-account JSON key → grant that service-account email Viewer/Analyst on the GA4 property → set ANALYTICS_PROPERTY_ID.
Realistic estimates: half a day for a spike, plus 1–2 days of coordination with whoever administers the GA4 property (this is usually a marketing or agency third party, and is the most common schedule slip). The Analytics::fake() helper is a genuine accelerant — it means CI has no dependency on live Google credentials, which is where comparable packages often fail.
Technical risk
get() method requires callers to construct Google\Analytics\Data\V1beta\FilterExpression, OrderBy, StringFilter objects directly. That couples application code to a beta Google protobuf namespace. This is the single largest long-term risk and must be contained behind an app-level wrapper.storage_path('app/analytics/service-account-credentials.json'). In a containerised or multi-environment deployment this needs to move to an env-supplied array sourced from a secret manager, with defined rotation. A long-lived JSON key with property read access is a standing credential.property_id is read from config. Multi-brand, multi-tenant, or agency-per-client products need a per-call override or a service wrapper that manages property context — this is not solved out of the box.cache_lifetime_in_minutes). Too long and dashboards mislead; too short and you burn GA4 quota and request latency. This is a product decision, not a config detail.Key questions
Stack fit
Composer-native, Laravel-first, facade-based, Collections out. This drops cleanly into Blade views, Inertia props, API resources, and Livewire components without transformation. Credentials and caching reuse Laravel's existing config and cache infrastructure, so there is no new operational surface — the cache store is whichever store the app already runs.
The important constraint: treat the facade as an infrastructure boundary, not a domain API. The correct integration is a single AnalyticsService (or repository) in the app that owns property resolution, period construction, cache policy, retry, and mapping to app-owned DTOs. Every controller and view talks to that service. Nothing outside it imports Spatie\Analytics or Google\Analytics\Data\V1beta.
Migration path
spatie/laravel-analytics v4 / Universal Analytics: this is the GA4 rewrite; the migration is not drop-in. Return keys changed (visitors → activeUsers, pageViews → screenPageViews, url → fullPageUrl), and method names shifted (fetchVisitorsAndPageViewsByDate, etc.). Budget 1–3 days for call-site and view changes even in a modest app, and grep aggressively for key names in Blade templates where breakage is silent rather than fatal.google/analytics-data client code: straightforward and a net reduction in code; port the query-building into the get() call or the DTO wrapper.analytics-php / Reporting API v4: UA-era, effectively a rewrite.Compatibility
Pin the package and google/analytics-data explicitly. The V1beta namespace is the churn vector — expect a V1 promotion and watch the changelog for it. Confirm Laravel and PHP version support against the package's composer.json before committing; Spatie drops older Laravel majors on a predictable cadence.
Sequencing
AnalyticsService with property context, DTO mapping, cache policy, retry/backoff, and graceful degradation. Tests use Analytics::fake().Maintenance
Small code footprint, MIT licence, active Spatie ownership with a maintained changelog and release train. Ongoing effort is low but non-zero: the real maintenance driver is the transitive google/analytics-data dependency, not this package. Plan a quarterly dependency review and expect one meaningful upgrade event when the beta namespace stabilises. Total cost of ownership is dominated by secrets management and dashboard correctness, not by code upkeep.
Support
Community-only, no SLA, no vendor escalation. The support path is GitHub issues plus internal Laravel expertise. Name a backend owner for the integration and a product/marketing owner for the GA4 property relationship — most incidents are caused by changes on the GA4 side, and without a named counterpart you will debug blind.
Scaling
The system is quota-bound, not compute-bound. Google enforces per-property token quotas; the package's response cache is the primary lever, and the cache TTL is effectively your capacity plan.
maxResults, restrict dimension sets, and prefer Period::days(7/28) presets over arbitrary ranges.Failure modes
| Failure | Symptom | Mitigation |
|---|---|---|
| Service-account key expired/revoked | 401/403, hard failure | Rotation runbook; alert on auth errors; keep key in secret manager |
| Property access removed or role downgraded | 403 on all calls | Contractual/process check with property owner |
| Analytics Data API disabled in GCP project | 403 with opaque message | Pin in infra-as-code and monitor |
| Quota exceeded | 429 | Serve last-known-good cached payload; exponential backoff; alert at 80% |
| GA4 thresholding/sampling | Numbers silently wrong, no error | Surface a data-quality disclaimer; spot-check against GA4 UI; consider BigQuery export |
| Cached config after property change | Wrong property's data displayed | Config-cache clear in deploy pipeline; assert property ID at boot |
| Network timeout in request path | Page error | Move to queue/prefetch; timeout + empty state |
| Silent key-name change on upgrade | Blank values in views, no exception | Typed DTO mapping with explicit key assertions; smoke test in CI |
Design for graceful degradation from day one: every analytics surface should have a cached-last-known-good path and an empty-state UI. An analytics widget that errors the page is worse than one that says "data temporarily unavailable."
Ramp-up
Low for any Laravel developer — hours to first successful call. The genuine learning curve is GA4 Data API semantics (dimension/metric compatibility rules, ordering, keepEmptyRows, filter expressions), which is Google's complexity, not the package's. Budget roughly a week for one developer to go from zero to confidently shipping production dashboards, including the credential and quota work.
How can I help you explore Laravel packages today?