jeffersongoncalves/laravel-ga4
Laravel GA4 offers a simple integration for Google Analytics 4, letting you send events and page views to GA4 directly from your Laravel application. Configure your measurement ID and start tracking server-side events quickly.
Architecture fit. The package targets three distinct GA4 surfaces with materially different characteristics, and a TPM should treat them as three integration decisions rather than one:
runReport, runRealtimeReport) — read-only, service-account authenticated, quota-bound. Low blast radius. This is the natural first integration and the one most likely to succeed quickly.listConversionEvents, createConversionEvent) — read/write against live property configuration. createConversionEvent mutates production analytics config and is not obviously reversible from the exposed surface (no deleteConversionEvent or updateConversionEvent in this release). Highest governance burden.sendEvent) — unauthenticated-by-design (API secret), fire-and-forget, returns no meaningful body. Server-side event ingestion, typically used to backfill or join offline conversions.Architecturally this is a thin API client, so fit depends almost entirely on whether it uses Laravel's HTTP client, config, and queue primitives or ships its own. A package that respects Http:: macros, config/, and container binding slots into a Laravel app cleanly; one that hard-wires Guzzle and reads $_ENV directly will fight the framework.
Integration feasibility. Feasible for all three surfaces, but the effort is asymmetric. Data API is a same-sprint task. Measurement Protocol is trivial to call and hard to verify. Admin API needs a service account with Editor-or-above on the property plus a deliberate decision about who is allowed to create conversion events via application code. Because this is a v1.0.0 initial release, there is no adoption history, no issue backlog, and no evidence of how the maintainer handles GA4 API version churn — treat the first integration as a spike, not a commitment.
Technical risk.
204 No Content whether the hit was accepted or silently discarded. A wrapper that surfaces success on 2xx will let bad events disappear for weeks. Validation (validationBehavior / debug endpoint) is not exposed in these release notes.createConversionEvent is a privileged, side-effecting operation with no compensating delete in this release. No idempotency or dry-run affordance is documented.Key questions.
google/apiclient, or call the REST endpoints directly? The former is ~20MB of transitive weight and a separate upgrade treadmill.Http RequestException, or a result object? Can a caller distinguish 403 PERMISSION_DENIED (config problem) from 429 (retry) from 400 (bad payload)?listConversionEvents, or does it silently truncate the first page?createConversionEvent support dry-run, and is there any delete/update path planned?sendEvent expose MP validation mode or batch sending?Stack fit. The package needs to occupy one narrow slot: a credentials-and-transport adapter behind an application-owned interface. Do not let controllers or jobs call the package facade directly. Define AnalyticsReporter (reports), ConversionConfig (admin), and EventIngestor (measurement) as first-party interfaces, with the package as the initial implementation. This costs an hour and converts an unproven v1.0.0 dependency into a swappable one — the correct posture for any package with no release history.
Configuration should read from environment, with the service-account JSON resolved through the platform secret store rather than a file path in the repo. Namespace credentials per property so a multi-market rollout doesn't require a shared secret.
Migration path. Greenfield — no incumbent to displace. Two plausible entry points: (a) teams currently hand-rolling Http::post() calls against GA4 endpoints, who gain error handling and pagination; (b) teams with no GA4 server-side integration at all, who gain capability. For (a), the migration is a like-for-like replacement of ad-hoc calls, and worth doing. For (b), the package is incidental — the real work is credential provisioning and property access grants, which the package does not do for you.
Compatibility. The binding constraint is not Laravel version, it is GA4 property permissions. Data API needs at least Viewer on the property; Admin API needs Editor or higher; MP needs only the measurement ID and API secret, which is a separate trust boundary from the service account. Confirm the service account has been added as a user on the GA4 property — the most common first-integration failure is a perfectly valid token rejected with 403 because the service account was never granted property access.
Sequencing.
runReport call, verify token caching, confirm exception types on a deliberately bad property ID. Gate: documented error taxonomy.runReport behind the AnalyticsReporter interface, wrapped in a cache with a TTL matched to reporting cadence (GA4 data is not realtime-accurate; caching aggressively is correct). No writes.runRealtimeReport has tighter quotas and 30-minute-ish data windows. Adopt only if a dashboard actually needs it — otherwise it is quota spent on nothing.listConversionEvents first, to prove read access and pagination. createConversionEvent only after deciding whether application code should ever create conversion config unattended. Default answer: no — run it as a one-off operator task, not a runtime path.sendEvent inline in a request cycle. Dispatch to a queue with retry, log every outbound payload with its client_id/session_id, and reconcile against GA4 debug output or BigQuery export before trusting the pipeline.Maintenance. Pin to an exact version (1.0.0), not a caret constraint. A v1.0.0 package with no history will ship breaking changes in 1.x; a caret range hands the maintainer unilateral authority over your analytics pipeline. Budget recurring effort for GA4 API version churn — Google deprecates beta surfaces on its own schedule, and this package's response time to that is unknown. The abstraction layer from the previous section is what makes that churn a dependency bump rather than a refactor.
Support. Two support surfaces, and the second is the one that bites. The package itself is a small open-source dependency with an unknown maintainer responsiveness profile — treat it as community-supported, not vendor-supported, regardless of license. Google's GA4 APIs sit underneath and are well-documented but have their own quota dispute process, which the package cannot help with.
Scaling. Quota is the ceiling, not CPU. Data API quota is per-property, per-project, and per-hour; a naive per-request runReport on a user-facing dashboard will exhaust it. Cache read results, batch dimension combinations into fewer reports, and keep an eye on concurrent-request limits. Measurement Protocol tolerates far higher volume but is subject to payload size limits per request, so high-cardinality event backfills need chunking. Realtime API is the tightest and should be reserved for genuinely live surfaces.
Failure modes.
| Mode | Signal | Blast radius | Mitigation |
|---|---|---|---|
| Service account lacks property access | 403 PERMISSION_DENIED on every call |
Total outage of analytics features | Verify at deploy time with a health-check call |
| Token not cached / refresh storm | Latency creep, intermittent 429 |
Degraded, then failing reads | Confirm caching; add circuit breaker |
| Quota exhaustion | 429 RESOURCE_EXHAUSTED |
Reads fail during peak traffic | Cache aggressively, backoff, alert on 429 rate |
| MP silently drops hits | None — 204 either way |
Silent data loss, discovered weeks later | Validate payloads pre-send; reconcile against BigQuery/GA4 debug |
createConversionEvent misconfigured |
Duplicate or spurious conversion events in reporting | Corrupted conversion metrics, hard to unwind | Restrict to operator-run, sandbox-first, no delete API available |
| Upstream API version retirement | 404 on all endpoints |
Total outage | Abstraction layer + pinned version + changelog watch |
| Credential leakage via config | Secret in repo history | Unauthorized property access | Secret store, no inline keys, rotate on any suspicion |
The Measurement Protocol row is the one to escalate. Silent data loss with no error signal is the worst failure shape available: it is invisible, it compounds, and by the time it surfaces the raw events may be unrecoverable. Do not ship MP ingestion without an independent reconciliation path.
Ramp-up. A Laravel developer with no GA4 exposure is productive on the read path in under a day. The Admin API requires understanding GA4's property/permission model and conversion-event semantics — call it one to two days including a sandbox exercise, plus review from whoever owns analytics governance. Measurement Protocol looks trivial and is not: the ramp-up cost is not in the API call, it is in building the reconciliation harness that tells you whether the calls worked. Budget for that explicitly, or the integration will be "done" and quietly wrong.
How can I help you explore Laravel packages today?