Caching, collections & pagination
Cache any terminal call — aggregate(), timeseries(), breakdown(), run() or realtime() — by a deterministic signature of the query. Pass seconds or a DateTimeInterface, and optionally a cache store:
$result = Plausible::stats()
->for('my-site.com')
->metrics(Metric::Visitors)
->cache(300) // seconds; or ->cache(now()->addHour(), 'redis')
->aggregate();
Plausible::stats()->for('my-site.com')->last7Days()->cache(now()->addHour(), 'redis')->timeseries();
Plausible::stats()->for('my-site.com')->cache(30)->realtime();The key is plausible:stats: plus a hash of the whole query — type, site, metrics, filters, dimensions, ordering, includes, period, interval, dates, comparison, property and page — so different queries never share an entry. The decoded response is cached and the typed result is rebuilt on each hit.
Collections
Every result exposes collect() for an Illuminate\Support\Collection of typed rows; aggregate() returns a metric-keyed collection of values:
use RoundlyConsulting\Plausible\Enums\Property;
Plausible::stats()->for('my-site.com')->breakdown(Property::VisitSource)->collect(); // Collection<int, BreakdownRow>
Plausible::stats()->for('my-site.com')->timeseries()->collect(); // Collection<int, TimeseriesPoint>
Plausible::stats()->for('my-site.com')->aggregate()->collect(); // ['visitors' => 2001, ...]Auto-paginating breakdowns
cursor() and each() transparently walk every page of a breakdown using PHP generators, so you never write a page loop. Pages are fetched on demand, so large breakdowns never load at once:
use RoundlyConsulting\Plausible\Enums\Property;
use RoundlyConsulting\Plausible\Results\BreakdownRow;
foreach (Plausible::stats()->for('my-site.com')->cursor(Property::VisitSource) as $row) {
// every row across every page
}
Plausible::stats()->for('my-site.com')->each(function (BreakdownRow $row) {
// return false to stop early
}, Property::VisitSource);The walk starts at page 1 and stops at the first page with fewer rows than perPage(). Raise perPage() to walk the same breakdown in fewer, larger requests. When the walk ends or stops early, the builder’s own page() is restored, so a later breakdown() on the same builder fetches its page again. Without a property, cursor() and each() throw MissingConfiguration.
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 cryptoBy 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.