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

Laravel First Party Analytics Laravel Package

amjadiqbal/laravel-first-party-analytics

First-party analytics for Laravel: collect and store visitor and event data on your own infrastructure without third-party scripts, giving you privacy-friendly, self-hosted reporting and insights.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require amjadiqbal/laravel-first-party-analytics
php artisan migrate
php artisan about   # confirms the package registered

There is nothing else to configure for a first data point: the tracking middleware is auto-added to the web group, so loading any successful HTML page on a web route writes a pageview and a visit. Open the dashboard (local-only by default — see the gate below) and confirm the hit appears before you touch config.

Order of operations for a first real setup:

  1. Decide cookie mode now. Default is no-cookie (daily salted hash of IP + user agent + host). Set ANALYTICS_COOKIES=true only if you need cross-day visitor continuity and anonymous-visit linking on login. This choice changes what your funnel numbers mean, so make it before you accumulate history.
  2. Find the package config and edit the keys the release notes name: exclude_paths, retention_days, ignore_referrers, conversions, and funnel definitions.
  3. Open the dashboard outside local. Gate is viewFirstPartyAnalytics, local-only by default — define it in a service provider (Gate::define('viewFirstPartyAnalytics', fn ($user) => $user->isAdmin())) or your staging team will report "it's broken".
  4. Add analytics:prune to the scheduler the same day. Retention is opt-in via that command; without it the tables grow forever.

First meaningful use case: drop exclude_paths entries for /admin, /health, /sitemap.xml, and any webhook-ish GET routes, then let it run for a day before wiring custom events.

Implementation Patterns

Tracking scope. For most apps, leave the auto-web-group registration alone and control scope with exclude_paths. Reach for the analytics.track middleware alias only when you want tracking on routes outside web or want per-group opt-in instead of per-route opt-out.

Custom events from PHP. Analytics::track('signup_completed', ['plan' => 'pro']) inside a controller joins the visit already created for that request, so the event lands attached to the right visit with no extra correlation work. From a queued job or artisan command there is no request context — call Analytics::identify($user) first, or the event is stored against the user but not a visit. This is the pattern for "trial expired", "invoice paid", anything asynchronous.

Browser events. Include @firstPartyAnalytics once (layout, before </body>). Then either analytics.track('cta_click', { position: 'hero' }) or, for zero-JS cases, data-analytics-event="cta_click" on the element. Clicks are sent with sendBeacon to a same-origin-checked, rate-limited endpoint — best-effort by design.

Identity. User linking is automatic on Login and Registered. If you use a custom auth flow (SSO, passwordless, impersonation), call Analytics::identify() yourself. With cookies enabled, identify() also back-links the visitor's earlier anonymous visits — that is the main reason to accept cookies.

Funnels and conversions. Define them in config as ordered event sequences rather than computing them in SQL later. Because a visit ends on a new source, keep funnel steps inside a single-session journey (e.g. view_pricing → start_checkout → purchase), not "signed up last month, upgraded today".

Write mode. Default batched-after-response is right for almost everyone. Choose the queued mode when per-request write latency or DB contention matters, and make sure a worker is running. Use sync only in tests or while debugging a missing event.

Suppression. Analytics::ignoreUsing(fn () => ...) for admin users, internal IPs, or a ?preview=1 flag — cheaper and more reliable than trying to express every case in exclude_paths.

Tests. Feature tests hitting web routes will write analytics rows. Disable tracking in your test suite config (or via ignoreUsing) so you don't assert against polluted tables.

Gotchas and Tips

  • Inertia/SPA navigations will not count. The middleware explicitly skips JSON, AJAX, Livewire updates, redirects, errors and prefetches. Inertia page changes are XHR+JSON, so a JS-driven app may record almost nothing despite looking busy. Fire browser events manually on navigation, or accept pageview-only-on-full-load.
  • No-cookie mode rotates daily. The hash is salted per day, so a returning visitor is a new visitor each day. That is fine for traffic trends, wrong for retention/cross-session attribution. Also note the salt changing on config edits or multi-server deployments if the salt isn't shared — check where it is stored before scaling horizontally.
  • Referrer query strings are stripped. utm_* are captured as their own columns, and ?ref= is supported, but arbitrary params on the referrer URL are gone. Keep campaign tags on your own landing URLs, where they are read.
  • ignore_referrers defaults cover Stripe Checkout, PayPal, Google and Apple sign-in. Any other OAuth/checkout provider (Auth0, GitHub, Clerk, a custom payment page) will look like a new source and split the visit, breaking funnel completion. Add yours.
  • Country needs a CDN header. Self-hosted with no CDN in front means the country column stays empty — not a bug.
  • The user agent is never stored. You get browser/OS/device buckets only; you cannot debug an individual session or re-parse history later. Plan for that if you expect forensic-level data.
  • DNT and GPC are respected, invisibly. A non-trivial share of privacy-conscious traffic vanishes. Compare against server logs before concluding tracking is broken.
  • Write failures are reported, never thrown. That is the right call for analytics, but it means silent data loss if nobody watches the reported exceptions. Route them to your alerting channel, and sanity-check the daily total against requests.
  • Batched writes rely on terminable middleware. Verify the batch actually flushes under Octane / long-running workers before trusting totals in production.
  • Queue mode is the least-proven path in this release — the suite asserts the job is dispatched and applied, but not against a real worker. Smoke-test it on staging, and watch for events lost when a job dispatches inside an uncommitted transaction.
  • The browser endpoint is rate-limited. Rapid-fire clicks can 429 and drop events; never attach business meaning to a client-side event. Server-side Analytics::track() is the durable path.
  • Dashboard ranges are preset or custom — check whether "today" follows app timezone or UTC before reconciling with another tool.
  • Pruning is chunked but destructive. Run analytics:prune --pretend first, schedule it off-peak, and confirm retention_days matches whatever your privacy policy claims.
  • Extension points to remember: the DetectsBots contract (swap for your own bot logic without touching the middleware), Analytics::ignoreUsing(), the viewFirstPartyAnalytics gate, and the write-mode config. Everything else is driven by config.
  • It's 0.1.0. Pin the exact version and read changelogs; the public surface (event property names, config keys, dashboard routes) has no stability guarantee yet.
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