panphp/pan
Pan is a lightweight, privacy-focused analytics package for Laravel. Track page views and custom events directly in your own database, with no cookies, JavaScript bloat, or third-party services required.
Architecture fit. Pan is an event-capture layer that lives inside the Laravel app rather than beside it: one dependency, one migration, first-party data in your own database, no vendor SDK, no outbound data transfer. For a privacy-constrained product (EU-facing, health, fintech, B2B procurement with a security questionnaire) that removes an entire vendor-risk category — DPA negotiation, cookie consent surface, sub-processor listing. The architectural trade-off is scope: Pan is an instrumentation primitive, not an analytics platform. There is no cohorting, funnel builder, session stitching, identity resolution, or warehouse sync. It occupies the "collect" box; the "model and report" boxes are yours to build.
Integration feasibility. Low for a Laravel monolith: composer require, publish config and migrations, migrate, add the Blade directive to the base layout, and Pan::track() at domain boundaries. A realistic first-data estimate is 1–3 engineering days, and the majority of that is taxonomy design, not wiring. Friction concentrates in non-Blade front ends: Inertia, Livewire navigation, Turbo, or any client-side routing path will under-count page views unless events are emitted explicitly. Verify that path in the spike before you commit publicly.
Technical risk.
enabled flag left off in staging. Nobody gets paged. You will discover the gap in a roadmap review, six weeks late.Key questions.
Stack fit. Strong for Laravel-first teams on Blade with Alpine or vanilla JS, MySQL/Postgres, standard CI/CD. Despite the "PHP package" framing, this is Laravel-coupled — do not assume portability to Symfony, Slim, or a polyglot estate. If you run multiple services, scope Pan to the Laravel surfaces and accept that you will not have a unified event pipeline. That is a constraint to state in the decision record, not a detail to discover later.
Migration path. Assume no backfill: Pan history starts at cutover, so sequence it before you need a trend line. Run dual instrumentation for one quarter, instrument the same 5–10 funnel events in both Pan and the incumbent, and reconcile against an agreed tolerance (expect 5–15% divergence from ad-blocking and bot filtering — write the tolerance into the plan or the first reconciliation meeting becomes an incident review). Retire the heavyweight tool for product events only; retain GA or equivalent strictly for marketing attribution, where Pan is not a substitute.
Compatibility. Composer constraints against your Laravel and PHP versions; CSP headers for the beacon endpoint and injected script; Livewire/Inertia/Turbo routing behavior; ad-blocker exposure in your audience; Octane and queue workers if writes are deferred; database driver coverage in CI.
Sequencing.
Maintenance. Low footprint — one dependency, one migration, one config file, one small asset — so recurring toil is small. The counterweight is ownership: you become the de facto maintainer of the integration path. Designate one engineer as owner and write a one-page runbook covering event naming, table pruning, upgrade procedure, and the fork-and-patch path.
Support. Community only. No SLA, no escalation path, thin documentation. Plan for internal enablement rather than vendor onboarding, and do not place this package on a roadmap that assumes vendor support. If procurement asks "who do we call," the honest answer is "our engineer."
Scaling. Every tracked interaction touches the same database serving users — write amplification on primary infrastructure. Mitigations in order of preference: exclude noisy routes in config, instrument only decision-relevant elements, sample high-volume pages, push writes to a queue or a dedicated connection, and roll up to daily summaries on a schedule. If Pan stores raw rows, add partitioning and a retention job before traffic, not after the first slow query. The read path is entirely yours; pre-aggregate rather than hitting the events table from a dashboard.
Failure modes to design against. Silent loss from ad-blockers, CSP, or swallowed 4xx; event-name drift producing orphaned rows nobody owns; migration collisions on multi-instance deploys; lock contention on counter rows under burst traffic; and unmonitored gaps during incidents when there is no external buffer. Cheapest insurance available: a synthetic canary event emitted on a schedule plus a daily assertion that expected counts are non-zero, alerting on deviation. Treat analytics as a feature with a health check, not a background nicety.
Ramp-up. A Laravel developer is productive in hours — the package is not the hard part. The genuine cost, and the reason a TPM should own this, is taxonomy design, metric definitions, cross-team agreement on what a "signup" or "active user" means, and building the reporting layer Pan deliberately omits. Budget engineering days for integration and product/analytics weeks for the questions. Frame the pilot accordingly: one product question, one funnel, one decision — then decide whether to expand or revert.
How can I help you explore Laravel packages today?