---
title: "Querying stats — Plausible for Laravel | Roundly"
description: "Read realtime visitors, aggregates, timeseries and breakdowns through the fluent builder, with typed results and period shortcuts."
url: https://roundly-consulting.com/open-source/docs/plausible-for-laravel/stats
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Plausible for Laravel](https://roundly-consulting.com/open-source/docs/plausible-for-laravel.md)

# 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.

```php
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

```php
$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:

```php
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. Plausible’s v1 timeseries endpoint takes only the date (alias day) and month intervals; minute, hour or week throw UnsupportedRequest before anything is sent — for hourly or weekly buckets use run() with Dimension::TimeHour or Dimension::TimeWeek (Stats v2 queries):

```php
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)                    // date or month — hourly or weekly buckets go through run()
    ->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(); without one it throws MissingConfiguration naming the missing property. Rows keep Plausible’s response keys, so read the dimension with get() (page for event:page) and metrics with metric():

```php
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:

```php
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();     // v1: custom range, 1 January to today
Plausible::stats()->for('my-site.com')->allTime()->run();            // run() only — v1 terminals throw UnsupportedRequest

// 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
```

| Shortcut | Sends |
| --- | --- |
| `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. A later period() or shortcut such as last7Days() replaces an earlier between(), since(), yesterday() or lastMonth() range. The v1 terminals have no year or all-time period: thisYear() goes to them as a custom range from 1 January to today, while allTime() throws UnsupportedRequest pointing to run(), which sends both unchanged. 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](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## 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.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/plausible-for-laravel.md)
