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 Plausible Laravel Package

vincentbean/laravel-plausible

A lightweight Laravel integration for Plausible Analytics. It provides a simple facade and Blade helpers to track pageviews and custom events, supports self-hosted instances, and enables privacy-friendly, cookie-free analytics with minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and configure (2.4.0)

composer require vincentbean/laravel-plausible
php artisan vendor:publish --tag=plausible-config

Set the minimum in .env:

PLAUSIBLE_DOMAIN=example.com          # bare domain, no scheme, must match the site in Plausible exactly
PLAUSIBLE_API_KEY=                   # only needed for stats endpoints
PLAUSIBLE_SELF_HOSTED=false

The package auto-discovers its service provider and registers the Plausible facade — no manual wiring in config/app.php.

Where to look first

  1. config/plausible.php — this is the whole surface area of the package's configuration.
  2. The facade class behind VincentBean\Plausible\Facades\Plausible — read this before anything else; it is a thin wrapper around the Plausible HTTP APIs and is short enough to read end-to-end in a few minutes.
  3. The README's events section — server-side event ingestion is the primary reason to install this.

First use case: record a server-side conversion

The canonical first integration is a signup or checkout event that the browser can't reliably capture (ad-blockers, API-only flows, webhook-driven conversions):

use VincentBean\Plausible\Facades\Plausible;

Plausible::record('Signup');

Put this behind a queued listener rather than in the request path (see below) — the call is a synchronous outbound HTTP request.

Upgrading from 2.3.x

2.4.0 only widens the framework constraint to include Laravel 13. No breaking changes, no config changes, no method signature changes. composer update vincentbean/laravel-plausible and you're done. If you are not yet on Laravel 13 this release is a no-op for you — it's a maintenance bump, not a feature release.

Implementation Patterns

Never call the facade from a controller action directly. Analytics is a side effect, not a response concern. The durable pattern is a domain event plus a queued listener:

// app/Events/UserSignedUp.php  — plain domain event
// app/Listeners/TrackSignup.php
class TrackSignup implements ShouldQueue
{
    public function handle(UserSignedUp $event): void
    {
        Plausible::record('Signup');
    }
}

Queuing gives you retries and keeps a slow or unreachable Plausible instance from adding latency to a user-facing request. Note the caveat in Gotchas about request context being lost in the queue.

Wrap it in your own service, not the facade. Introduce App\Analytics\Tracker that depends on the package and exposes signup(), purchase($order), trialStarted(). Two payoffs: event names stop being scattered string literals across the codebase, and you have one seam to swap or stub in tests. When you later add a second destination (Segment, PostHog) you change one class.

Toggle per environment. Guard the service with a config flag so local and CI runs don't pollute production stats:

if (! config('services.plausible.enabled')) {
    return;
}

Keep this in your wrapper, not in every call site. Plausible will happily accept events from your test suite otherwise.

Multi-tenant / multi-domain. If each tenant has its own Plausible site, don't try to solve it with one env var. Resolve the domain at call time from the tenant context (config(['plausible.domain' => $tenant->plausible_domain]) before the call, or bind a pre-configured tracker instance per tenant). Do this inside a queued job carefully — the config mutation must happen in the same process that issues the request, so pass the tenant identifier into the job and resolve there rather than relying on the request's tenant binding.

Testing. Because the package goes through Laravel's HTTP client, Http::fake() and Http::assertSent() work normally. Fake in TestCase::setUp() for the whole suite so no test can leak a real event, and assert on the outbound request shape in the handful of tests that cover your Tracker:

Http::fake();
// ... act ...
Http::assertSent(fn ($request) => str_contains($request->url(), '/api/event'));

Pair it with client-side tracking, don't replace it. The bundled script tag handles pageviews and engagement metrics that server-side events can't reproduce (bounce rate, visit duration). Use the server-side facade strictly for things the browser can't see: refunds, subscription cancellations, backend-only conversions.

Gotchas and Tips

Queued events lose the visitor's IP and User-Agent. Plausible attributes server-side events using the User-Agent and X-Forwarded-For headers captured from the current request. Once you dispatch a job, that request context is gone and the event may be attributed to your queue worker or dropped as a bot. Either record synchronously in the request lifecycle, or capture request()->ip() and request()->userAgent() at dispatch time and pass them into the job payload. This is the single most common source of "events sent but nothing in the dashboard".

A 202 means accepted, not recorded. The events endpoint returns a success status even when Plausible silently discards the event (bot filtering, wrong domain, disabled site). Never treat a green response as proof of delivery. When debugging, log the outbound payload and check the Plausible dashboard's realtime view within a minute — that's the only reliable confirmation.

Domain mismatch is silent. PLAUSIBLE_DOMAIN must match the site configured in Plausible exactly, bare hostname, no https://, no trailing slash, no www unless that's how the site is registered. Self-hosted installs additionally need PLAUSIBLE_SELF_HOSTED=true and a correctly formed base URL — a doubled or missing slash here produces a 404 you'll only notice by inspecting the response.

Analytics must never break the happy path. Wrap calls in try/catch or ensure the listener fails independently. A timeout on a checkout confirmation should be logged, not surfaced. Set an explicit HTTP timeout (a few seconds) rather than inheriting the default.

Config cache. After changing any PLAUSIBLE_* env var, run php artisan config:cache (or config:clear in local). Stale cached config is a frequent cause of "I changed the domain and it still isn't working".

Realtime lag. The realtime dashboard updates within ~30 seconds; historical views and goal conversions can take longer to materialise. Don't write integration tests that assert against the Plausible API — assert against your fake.

Extension points are thin by design. There is no event/middleware pipeline to hook into — the package is a facade over HTTP. If you need retry policy, header injection, or request logging, do it in your own wrapper class or via a global Http::macro/Http::beforeSending hook rather than by extending the package. Forking it for anything short of a genuine upstream bug is usually the wrong trade.

Laravel 13 and the constraint. 2.4.0's only change is the widened framework constraint. If your composer.json pins the package to 2.3.*, you'll stay on an older release and risk a dependency conflict when you upgrade the framework — relax the pin to ^2.4 now, even if you're not on Laravel 13 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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings