- How do I install Pan in a Laravel application?
- Install it with composer require panphp/pan, then publish the package config and migrations, run php artisan migrate, and add the provided Blade directive to your base layout. Custom events are recorded with the fluent PHP API, for example Pan::track('signup') at the domain boundaries you care about. Because everything is stored in your own database, there is no external account, API key, or data transfer to configure. A realistic first-data estimate is one to three engineering days, most of which is taxonomy design rather than wiring.
- Which Laravel and PHP versions does Pan support, and which databases work?
- Pan is built specifically for modern Laravel and is Laravel-coupled rather than framework-agnostic, so do not assume it ports to Symfony, Slim, or Lumen. Check the composer.json constraints for the exact Laravel and PHP version range before you commit, and confirm the migration runs cleanly on your driver of choice (MySQL, Postgres, or SQLite). If you run Laravel Octane or queue workers, verify behaviour under those runtimes in a spike rather than assuming parity.
- How do I track custom events with Pan?
- Pan exposes a simple fluent PHP API, so you call something like Pan::track('checkout_completed', [...]) at the domain boundary where the event actually happens. Because this is server-side, you can record events that never surface in the browser, such as webhook processing or background jobs. Design a small event taxonomy first: a handful of well-named events beats dozens of ad hoc ones you cannot report on later. For multi-tenant apps, attach your tenant or account identifier as part of the event payload and confirm the schema can be filtered by it.
- Is Pan GDPR compliant, and do I still need a cookie consent banner?
- Pan is cookie-free, collects no personal data by design, and sends nothing to a third party, which removes an entire vendor-risk category: no DPA negotiation, no sub-processor listing, and no third-party cookie consent surface. That said, privacy-first is a design posture, not a legal guarantee. Read the shipped migration yourself to confirm exactly what is persisted per event, including IP address, user agent, authenticated user ID, or tenant ID, and whether anything is hashed or anonymised. Whether the no-banner posture is defensible depends on your jurisdiction, so validate it against your own privacy notice before shipping.
- Does Pan track page views correctly in Inertia, Livewire, or SPA-style apps?
- Page views are captured through middleware and a Blade directive, so full server-rendered page loads are covered out of the box. Client-side routing paths such as Inertia visits, Livewire navigation, or Turbo will under-count unless you emit events explicitly on each transition. Test that specific path in a spike before you publish numbers to stakeholders, because the gap is silent and only shows up as suspiciously flat traffic. Also check whether the injected first-party script can be blocked by ad-blockers or a strict Content Security Policy.
- What data does Pan actually store about visitors?
- The package stores aggregated analytics in your own database rather than shipping data to a vendor, but the exact per-event schema is defined by the migration that ships with it. Open that file and confirm whether IP addresses, user agents, authenticated user IDs, or tenant IDs are recorded, and whether any of it is hashed or anonymised. Do this before the package appears in a privacy notice or a security questionnaire. It is also worth checking whether writes happen synchronously in the request path or can be queued, since that affects both latency and failure modes.
- Can I use Pan for server-side-only tracking without the JavaScript beacon?
- The middleware and the Pan::track() API are server-side, so the core capture path does not depend on the browser. The Blade directive does inject a small first-party script, which is blockable by ad-blockers and CSP and therefore the first thing to test if your numbers look low. Ask whether an explicit event API covers all of your use cases with the beacon disabled, and whether Do Not Track is honoured. Resolving this client-side versus server-side ambiguity in a spike matters more than any other integration detail.
- How does Pan compare to Google Analytics, Plausible, or Fathom?
- Google Analytics, Plausible, and Fathom are analytics products with reporting UIs; Pan is an instrumentation primitive that lives inside your Laravel app and stores first-party data in your database. That means no third-party script, no cookie banner surface, and no outbound data transfer, but also no funnel builder, cohorting, session stitching, or identity resolution. Pan fills the collect box and leaves modelling and reporting to you, whether that is Blade admin views, Metabase, or scheduled rollups. Budget that read layer explicitly; it is unscoped work in every it's just a Composer package estimate.
- Does Pan store raw event rows or pre-aggregated counters?
- This is the single most important detail to confirm before adopting it, because it drives both your scaling plan and the questions you can answer later. Incrementing counters keep tables small but foreclose retroactive analysis, while raw event rows give depth at the cost of partitioning and retention obligations. Check the migration and the write path to see which model Pan uses, and confirm counter increments are concurrency-safe under load. Also check whether retention or purge tooling ships with the package or is left for you to build.
- Is Pan actively maintained, and what happens if it is abandoned?
- Pan has roughly 1.2k GitHub stars, which is real adoption but modest, so treat it as a small-maintainer project rather than a vendor with a support contract. It is MIT licensed, so you can fork it and patch it yourself, but that also means you inherit maintenance if development stalls. Pin the version in composer.json and treat upgrades as deliberate, scheduled changes instead of floating to latest. The larger operational risk is silent failure: a disabled config flag or a blocked request degrades tracking quietly, so add a smoke check that alerts you when events stop arriving.