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

Filament Plausible Laravel Package

jeffersongoncalves/filament-plausible

A Filament widget for Plausible Analytics that brings your site's visitor stats directly into the admin panel. Display real-time and historical metrics like pageviews, visitors, bounce rate, and top sources without leaving your dashboard. Simple to install and configure for any Plausible-tracked dom...

View on GitHub
Deep Wiki
Context7

Getting Started

The fastest path is: install, register the plugin on a panel, then set the site ID and API token. Everything else (widgets, caching, date ranges) works from that baseline.

1. Install

composer require jeffersongoncalves/filament-plausible

Version 3.4.0 adds navigationGroup(), which is gated on filament-analytics-core 3.1+. If you want that feature, bump the core package in the same PR so you don't ship a window where the plugin is present but core is not.

2. Register on a panel

use JeffersonGoncalves\FilamentPlausible\PlausiblePlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugin(PlausiblePlugin::make());
}

This is the whole integration. No migrations, no routes, no front-end assets.

3. Publish config if you need to override defaults

php artisan vendor:publish --provider="JeffersonGoncalves\FilamentPlausible\FilamentPlausibleServiceProvider"

Use this for the self-hosted host URL (https://plausible.yourdomain.com) or to point at a different analytics instance.

4. Configure credentials

Plausible → Settings → API Keys → create a key with stats:read. The site ID is the domain exactly as configured in Plausible (example.com — no protocol, no path, no trailing slash). Both are editable from the plugin's settings page, so operators can rotate tokens or point a panel at a new site without a deploy.

First use case: put the widgets on your Dashboard (or a dedicated "Analytics" page) and confirm you see non-zero visitors for a date range you know has traffic. If the API returns zeros, the site ID or token is almost always the cause — not the widget.

Where to look first: the settings page in the panel nav (translated group by default), then the config file for host URL, then the widget classes themselves if you want to customize display.

Implementation Patterns

Dashboard widgets vs. dedicated page. The default pattern is dropping the widgets onto Dashboard or a custom page. For SaaS admin panels and client portals, a dedicated page grouped under "Insights" is usually cleaner than polluting the home dashboard with traffic numbers the operator doesn't act on every day.

Settings page as runtime config. The plugin's settings page is the primary control surface: site ID, token, host URL, and (per the development skill) the option to disable the settings page entirely for script-only injection. Use it — it means rotating a token or repointing a panel at a different Plausible site is an operator task, not an engineering one.

Per-panel isolation. Each PanelProvider registers its own plugin instance, so multi-panel apps (admin + client portal, or a multi-tenant setup) can point at different Plausible sites or use different tokens. This is the natural fit for white-labeled portals where each tenant has its own domain.

Navigation grouping (3.4.0+). Put the settings page in your own taxonomy instead of the translated default:

->plugin(
    PlausiblePlugin::make()
        ->navigationGroup('Insights')
)

Register the group on the panel so ordering is deterministic:

$panel->navigationGroups([
    NavigationGroup::make('Insights')->collapsible(),
]);

For multi-tenant or permission-driven placement, pass a Closure — resolved during panel boot:

->navigationGroup(fn () => auth()->user()?->isAdmin()
    ? 'Settings'
    : 'Insights')

Self-hosted Plausible. Set the host in config to the base URL of your instance (https://plausible.example.com). The Stats API path is appended by the plugin; do not include /api in the configured value.

Script-only mode. If you only want the frontend tracking snippet and not the API-backed widgets/settings page, disable the settings page. This keeps the nav clean and avoids confusing operators with a page you don't intend them to use. Note this is separate from whether the tracking script is injected — check both.

Date ranges and comparisons. The widgets accept a period and support previous-period comparison. Standardize on a small set (7d / 30d / 90d) rather than exposing the full Plausible range syntax — operators rarely need more and every range change is a fresh cached query.

Extending. The plugin is a thin wrapper over the Plausible Stats API. Custom widgets should reuse the same client (and therefore the same cache) rather than making their own HTTP calls. Subclass the shipped widgets and override the query or the view.

Gotchas and Tips

Site ID is not a URL. It must match the domain in Plausible exactly — example.com, not https://example.com or example.com/. Wrong format returns empty arrays, not an error, so it looks like "no traffic."

Token scope. The API key needs stats:read. A key with broader scopes works but violates least privilege; a key without stats:read fails with an HTTP error the widgets usually swallow into a blank state. Test the token with curl before debugging widgets.

Settings are stored in the database. The API token lands in your settings table, not .env. That means: back up your DB before rotating, restrict DB access accordingly, and consider column-level encryption if your threat model requires it. Also means a migrate:fresh wipes the token and every widget silently goes blank until reconfigured.

Cache and site changes. Responses are cached to reduce API load — which is good, because the Stats API is rate-limited. But after changing the site ID or token in settings, you may see data from the previous site until the cache expires. Clear the cache after repointing a panel, or scope the cache key to the site ID (the package may not do this for you — verify).

navigationGroup() closure cost. The closure is evaluated during panel boot, on every request that renders the panel, not just on the settings page. Keep it cheap and total:

// Fine: reads already-loaded user state
->navigationGroup(fn () => auth()->user()?->isAdmin() ? 'Settings' : 'Insights')

// Avoid: per-request DB lookup for tenant metadata
->navigationGroup(fn () => Team::find(auth()->id())->nav_group)

An exception in the resolver breaks navigation rendering for the entire panel, not just the settings page.

Unregistered group names. Passing a string that isn't in Panel::navigationGroups() produces an implicit group — visible, but often in an unexpected position. Register the group on the panel first.

Core version floor. Below filament-analytics-core 3.1, navigationGroup() fails hard at panel boot (taking the whole panel down) rather than degrading gracefully. Pin core ^3.1 in composer.json rather than relying on runtime behavior.

Timezone offset on "today." Plausible returns dates in the site's configured timezone. Comparing "today" against a now() in a different app timezone produces off-by-one numbers that look like a bug. Align the site timezone with the app, or drop the "today" range from operator-facing widgets.

Empty data ≠ broken. A brand new Plausible site legitimately returns zeros for weeks. Don't chase phantom integration bugs on a site with no traffic — verify with a date range you know has data.

Multi-panel verification. Each panel configures the plugin independently. After upgrading, smoke-test navigation and widgets per panel; a change that looks correct in admin can misplace the settings page in a tenant-scoped portal.

Debugging. Log the raw Stats API response when a widget renders empty. The failure modes (invalid token, wrong site ID, wrong host URL, rate limit) all produce blank widgets in the UI but distinct HTTP codes on the wire — a Http::dd() in the client is faster than guessing.

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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox