Skip to main content

Stats API v2 reference

Plausible Stats API v2 is a powerful single endpoint HTTP interface to view historical and real-time stats. In a nutshell, the endpoint /api/v2/query accepts both simple and complex stats queries in the POST request body and returns the metrics as JSON.

Try it now for your own site!

Not what you need?

Take a look at our Events API Reference if you want to record pageviews or custom events for your sites, or Sites API Reference if you want to manage your sites over the API.

Authentication

You can obtain an API key for your account by going to your user settings page plausible.io/settings.

After creating a token, you can authenticate your request by sending the token in the Authorization header of your request.

Example curl request

In the following request, replace YOUR-TOKEN with a reference to your token and site_id value with your domain.

curl \
--request POST \
--header 'Authorization: Bearer YOUR-TOKEN' \
--header 'Content-Type: application/json' \
--url 'https://plausible.io/api/v2/query' \
--data '{ "site_id": "dummy.site", "metrics": ["visitors"], "date_range": "7d" }'

API keys have a rate limit of 600 requests per hour by default. If you have special needs for more requests, please contact us to request more capacity.

Request structure

/api/v2/query endpoint accepts a query object. Example:

{
"site_id": "dummy.site",
"metrics": ["visitors", "pageviews", "bounce_rate"],
"date_range": "7d",
"filters": [
["is_not", "visit:country_name", [""]]
],
"dimensions": ["visit:country_name", "visit:city_name"]
}

Query can contain the following keys:

site_id REQUIRED

Domain of your site on Plausible to be queried.

date_range REQUIRED

Date range to be queried.

OptionDescription
["2024-01-01", "2024-07-01"]Custom date range (ISO8601)
["2024-01-01T12:00:00+02:00", "2024-01-01T15:59:59+02:00"]Custom date-time range (ISO8601)
"day"Current day (e.g. 2024-07-01)
"7d"Last 7 days relative to today
"30d"Last 30 days relative to today
"month"Since the start of the current month
"6mo"Last 6 months relative to start of this month
"12mo"Last 12 months relative to start of this month
"year"Since the start of this year
"all"Since the start of stats in Plausible

metrics REQUIRED

Metrics represent values to be calculated with the query.

Valid metrics are:

Metric nameDescription
visitorsThe number of unique visitors
visitsThe number of visits/sessions
pageviewsThe number of pageview events
views_per_visitThe number of pageviews divided by the number of visits. Returns a floating point number.
bounce_rateBounce rate percentage
visit_durationVisit duration in seconds
eventsThe number of events (pageviews + custom events). When filtering by a goal, this metric corresponds to "Total Conversions" in the dashboard.
percentageThe percentage of visitors of total who fall into this category: Requires: dimension list
conversion_rateThe percentage of visitors who completed the goal. Requires: dimension list passed, an event:goal filter or event:goal dimension
group_conversion_rateThe percentage of visitors who completed the goal with the same dimension. Requires: dimension list passed, an event:goal filter or event:goal dimension

dimensions optional

Default: []

List of dimensions to group by. See example

Dimensions are attributes of your dataset. Using them in queries enables analyzing and compare multiple groups against each other. Think of them as GROUP BY in SQL.

Event dimensions

Valid dimensions include:

DimensionExampleDescription
event:goalRegisterA custom action that you want your users to take. To use this property, you first need to configure some goals in the site settings, or via the Sites API. The value is the goal's display_name. Learn more about goals here.
event:page/blog/remove-google-analyticsPathname of the page where the event is triggered. You can also use an asterisk to group multiple pages (/blog*)
event:hostnameexample.comHostname of the event.
warning

Mixing session metrics bounce_rate, views_per_visit and visit_duration with event dimensions is not allowed.

Visit dimensions

Values of these dimensions are determined by the first pageview in a session.

DimensionExampleDescription
visit:entry_page/homePage on which the visit session started (landing page).
visit:exit_page/homePage on which the visit session ended (last page viewed).
visit:sourceTwitterVisit source, populated from an url query parameter tag (utm_sourcesource or ref) or the Referer HTTP header.
visit:referrert.co/fzWTE9OTPtRaw Referer header without http://http:// or www..
visit:utm_mediumsocialRaw value of the utm_medium query param on the entry page.
visit:utm_sourcetwitterRaw value of the utm_source query param on the entry page.
visit:utm_campaignprofileRaw value of the utm_campaign query param on the entry page.
visit:utm_contentbannerRaw value of the utm_content query param on the entry page.
visit:utm_termkeywordRaw value of the utm_term query param on the entry page.
visit:deviceDesktopDevice type. Possible values are Desktop, Laptop, Tablet and Mobile.
visit:browserChromeName of the browser vendor. Most popular ones are Chrome, Safari and Firefox.
visit:browser_version88.0.4324.146Version number of the browser used by the visitor.
visit:osMacName of the operating system. Most popular ones are Mac, Windows, iOS and Android. Linux distributions are reported separately.
visit:os_version10.6Version number of the operating system used by the visitor.
visit:countryUSISO 3166-1 alpha-2 code of the visitor country.
visit:regionUS-MDISO 3166-2 code of the visitor region.
visit:city4347778GeoName ID of the visitor
visit:country_nameUnited StatesName of the visitor country.
visit:region_nameCaliforniaName of the visitor region.
visit:city_nameSan FranciscoName of the visitor city.

Time dimensions

It's useful to be able to group data by time, which can be done via the following dimensions.

DimensionExampleDescription
time2024-01-01Time or date to group by. Automatically figures out the appropriate time:bucket value from date range. Response is a valid ISO8601 date or timestamp
time:hour2021-01-27T23:43:10ZTime grouped by hour. ISO8601 timestamp
time:day2021-01-27Time grouped by date. ISO8601 date
time:week2021-01-04Time grouped by start of the week. ISO8601 date
time:month2021-01-01Time grouped by start of month. ISO8601 date

Note that:

See example

Custom properties

Custom properties can also be used as dimensions with the form event:props:<custom_prop_name>. See example

filters optional

Default: []

Filters allow limiting the data analyzed in a query. See example.

Simple filters

Each simple filter takes the form of [operator, dimension, clauses].

operators

The following operators are currently supported:

OperatorExampleExplanation
is["is", "visit:country_name", ["Germany", "Poland"]]Sessions originating from Germany or Poland.
is_not["is_not", "event:page", ["/pricing"]]Events that did not visit /pricing page
contains["contains", "event:page", ["/login"]]Events visited any page containing /login
contains_not["contains_not", "event:page", ["docs", "pricing"]]Events that did not visit any page containing docs or pricing
matches["matches", "event:page", ["^/user/\d+$"]]Events where page matches regular expression ^/user/\d+$. Uses re2 syntax
matches_not["matches", "event:page", ["^/user/\d+$"]]Events where page does not match regular expression ^/user/\d+$. Uses re2 syntax
dimension

Event and visit dimensions are valid for filters.

Note that only is operator is valid for event:goal dimension.

clauses

List of values to match against. A data point matches filter if any of the clauses matches.

Logical operations

Filters can be combined using and, or and not operators.

OperatorExampleExplanation
and["and", [["is", "visit:country_name", ["Germany"]]], ["is", "visit:city_name", ["Berlin"]]]]Sessions originating from Berlin, Germany
or["and", [["is", "visit:country_name", ["Germany"]]], ["is", "visit:city_name", ["Tallinn"]]]]Sessions originating from Germany or city of Tallinn
not["not", ["is", "visit:country_name", ["Germany"]]]Sessions not originating from Germany

Note that top level filters is wrapped in an implicit and.

order_by optional

Allows for custom ordering of query results.

List of tuples [dimension_or_metric, direction], where:

  • dimension_or_metric needs to be listed in query metrics or dimensions respectively.
  • direction can be one of "asc" or "desc"

For example:

[["visitors", "desc"], ["visit:country_name", "asc"]]

When not specified, the default ordering is:

  1. If a time dimensions is present, [time_dimension, "asc"]
  2. By the first metric specified, descending.

See full query example

include optional

Default: {}

Additional options for the query as to what data to include.

include.imports

Default: false

If true, tries to include imported data in the result. See imported stats for more details, query example.

Read more on limitations of including imported data

Using custom property dimensions (event:props:*) are only supported for 2 properties: url and path. Additionally, these breakdowns will only work in combination with a certain subset of event:goal filters.

Filtering imported stats

Filtering by imported data is limited. The general rule is that you cannot filter by two different properties at the same time. For example, event:page==/;visit:source==Twitter is not able to return any imported results. The same happens when you try to filter by one dimension and set another as a dimension.

There are some exceptions though. The following dimensions are aggregated and grouped together and can be combined in a query:

  • Countries, regions, cities
  • Operating systems and their versions
  • Hostnames and pages
  • Specific custom events and their properties
    • Outbound Link: Click and File Download goals with the url property
    • 404 goals with the path property

For example, you can set a country dimension and filter by both city and region.

If set, meta.imports_included field will be set as a boolean.

If the applied combination of filters and dimensions is not supported for imported stats, the results are still returned based only on native stats. Additionally, meta.imports_skip_reason and meta.imports_warning response fields will contain more information on why including imported data failed. See example

include.time_labels

Default: false

Requires a time dimension being set. If true, sets meta.time_labels in response containing all time labels valid for date_range.

See example

include.total_rows

Default: false

Should be used for pagination. If true, sets meta.total_rows in response containing the total number of rows for this query.

See example

pagination optional

Default: { "limit": 10000, "offset: 0 }

See example

Response structure

Example response:

{
"results": [
{"metrics": [99, 98, 94], "dimensions": ["Estonia", "Tallinn"]},
{"metrics": [98, 82, 97], "dimensions": ["Brazil", "São Paulo"]},
{"metrics": [97, 77, 98], "dimensions": ["Germany", "Berlin"]},
{"metrics": [94, 86, 93], "dimensions": ["Italy", "Rome"]},
{"metrics": [89, 77, 96], "dimensions": ["United States", "San Francisco"]},
{"metrics": [82, 78, 92], "dimensions": ["Poland", "Warsaw"]}
],
"meta": {},
"query": {
"site_id": "dummy.site",
"metrics": ["visitors", "pageviews", "bounce_rate"],
"date_range": ["2024-09-04T00:00:00+00:00", "2024-09-10T23:59:59+00:00"],
"filters": [["is_not", "visit:country_name", [""]]],
"dimensions": ["visit:country_name", "visit:city_name"],
"order_by": [["visitors", "desc"]],
"include": {}
}
}

results

Results is an ordered list query results.

Each result row contains:

  • dimensions - values for each dimension listed in query. In the same order as query dimensions, empty if no dimensions requested.
  • metrics - List of metric values, in the same order as query metrics

meta

Meta information about this query. Related: include.imports and include.time_labels.

query

The query that was executed, after manipulations performed on the backend.

Examples