NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Plausible for Laravel

Querying stats

The fluent builder is the recommended way to read stats. Start it with for($site) — or query() to use the configured default site — chain options, and finish with a terminal call that returns a typed result, so you stop hand-parsing JSON. Enums give type-safe metrics, periods, intervals and properties; plain strings still work everywhere.

use RoundlyConsulting\Plausible\Facades\Plausible;

Plausible::stats()->for('my-site.com');  // a fluent PendingStatsQuery for one site
Plausible::stats()->query();             // the same, for the configured PLAUSIBLE_SITE

Realtime visitors

$live = Plausible::stats()->for('my-site.com')->realtime(); // int — visitors on the site right now

Aggregate

aggregate() returns an AggregateResult. metric() gives a metric’s value (0 when absent), change() the comparison delta when compare() was on, and has() whether the metric is in the response:

use RoundlyConsulting\Plausible\Enums\Metric;

// Aggregate metrics for a custom range, compared with the previous period
$result = Plausible::stats()
    ->for('my-site.com')
    ->metrics(Metric::Visitors, Metric::Pageviews, Metric::BounceRate)
    ->between(now()->subDays(7), now())           // auto-sets period=custom
    ->compare()
    ->aggregate();                                // -> AggregateResult

$visitors = $result->metric(Metric::Visitors);    // typed int
$change   = $result->change(Metric::Visitors);    // comparison delta (or null)
$result->has(Metric::BounceRate);                 // bool
$result->results;                                 // ['visitors' => ['value' => 2001, 'change' => 30], …]
$raw      = $result->response();                  // escape hatch to the Response

Timeseries

timeseries() returns a TimeseriesResult of TimeseriesPoint objects, each with its date as Carbon and its metrics:

use RoundlyConsulting\Plausible\Enums\Interval;
use RoundlyConsulting\Plausible\Enums\Metric;
use RoundlyConsulting\Plausible\Enums\Period;

// Day-by-day trend you can chart
$points = Plausible::stats()
    ->for('my-site.com')
    ->metrics(Metric::Visitors, Metric::Pageviews)
    ->period(Period::ThirtyDays)
    ->interval(Interval::Date)                    // minute, hour, date, week or month
    ->timeseries()                                // -> TimeseriesResult
    ->points();                                   // list<TimeseriesPoint>

foreach ($points as $point) {
    $point->date;                                 // Carbon
    $point->metric(Metric::Visitors);             // int|float
}

Breakdown

breakdown() needs a property — pass it to the terminal or set it earlier with property(). Rows keep Plausible’s response keys, so read the dimension with get() (page for event:page) and metrics with metric():

use RoundlyConsulting\Plausible\Enums\Metric;
use RoundlyConsulting\Plausible\Enums\Property;

// Top pages, ranked and paginated
$rows = Plausible::stats()
    ->for('my-site.com')
    ->metrics(Metric::Visitors)
    ->last30Days()
    ->perPage(20)                                 // default 100
    ->breakdown(Property::EventPage)              // -> BreakdownResult
    ->rows();                                     // list<BreakdownRow>

foreach ($rows as $row) {
    $row->get('page');                            // "/pricing" — the dimension, by its response key
    $row->metric(Metric::Visitors);               // int|float
}

// Or set the property first
Plausible::stats()->for('my-site.com')->property(Property::VisitSource)->breakdown();

Periods and date ranges

Skip the enum for the common ranges with named shortcuts, or pass any Period or an explicit range:

use RoundlyConsulting\Plausible\Enums\Period;

Plausible::stats()->for('my-site.com')->today()->aggregate();
Plausible::stats()->for('my-site.com')->yesterday()->aggregate();      // custom range
Plausible::stats()->for('my-site.com')->last7Days()->timeseries();
Plausible::stats()->for('my-site.com')->last30Days()->aggregate();
Plausible::stats()->for('my-site.com')->last6Months()->timeseries();
Plausible::stats()->for('my-site.com')->last12Months()->timeseries();
Plausible::stats()->for('my-site.com')->thisMonth()->aggregate();
Plausible::stats()->for('my-site.com')->lastMonth()->aggregate();      // custom range
Plausible::stats()->for('my-site.com')->thisYear()->aggregate();
Plausible::stats()->for('my-site.com')->allTime()->aggregate();

// Any Period, or an explicit range
Plausible::stats()->for('my-site.com')->period(Period::SixMonths)->aggregate();
Plausible::stats()->for('my-site.com')->between(now()->subDays(14), now())->aggregate();
Plausible::stats()->for('my-site.com')->since(now()->startOfYear())->aggregate();   // year to date — through today
ShortcutSends
today()period=day
yesterday()custom range — yesterday, start to end of day
last7Days()period=7d
last30Days()period=30d
last6Months()period=6mo
last12Months()period=12mo
thisMonth()period=month
lastMonth()custom range — the previous calendar month
thisYear()period=year
allTime()period=all

between(Carbon $start, Carbon $end) and since(Carbon $start) both set period=custom with a closed range for you: the v1 terminals send date=start,end and run() sends date_range: [start, end]. since() runs through today, in the app’s timezone, fixed when you call it. Unset options fall back to the builder defaults: the visitors metric, a 30d period, a date interval, page 1 and 100 rows per page.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.