diff --git a/docs/stats-api-v1.md b/docs/stats-api-v1.md new file mode 100644 index 00000000..3adf0f9a --- /dev/null +++ b/docs/stats-api-v1.md @@ -0,0 +1,563 @@ +--- +title: Stats API reference +--- + +import {Required, Optional} from '../src/js/api-helpers.tsx'; + +:::warning[Legacy feature] +There is a new version of this API which can be found [here](stats-api.md). +::: + +The Plausible Stats API offers a way to retrieve your stats programmatically. It's a read-only interface to present historical and real-time stats only. Take a look at our [events API](events-api.md) if you want to send pageviews or custom events to our backend and our [sites API](sites-api.md) if you want to manage your sites through the API. + +The API accepts GET requests with query parameters and returns standard HTTP responses along with a JSON-encoded body. All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail. + +Each request must be authenticated with an API key using the Bearer Token method. You can obtain an API key for your account by going to your user +settings page [plausible.io/settings](https://plausible.io/settings). + +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. + +The easiest way to explore the API is by using our Postman collection. Just define your `TOKEN` and `SITE_ID` variables, and you'll have an executable API reference ready to go. + +[![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/32c111c4f6d2cccef9dd) + +:::tip New to Postman? +We have a [step-by-step guide to set up the authorization and run your first queries with Postman](get-started-with-postman.md) +::: + +## Concepts + +Querying the Plausible API will feel familiar if you have used time-series databases before. You can't query individual records from +our stats database. You can only request aggregated metrics over a certain time period. + +Each request requires a `site_id` parameter which is the domain of your site as configured in Plausible. If you're unsure, navigate to your site +settings in Plausible and grab the value of the `domain` field. + +### Metrics + +You can specify a `metrics` option in the query, to choose the metrics for each instance returned. See here for a full overview of [metrics and their definitions](/metrics-definitions). The metrics currently supported in Stats API are: + +| Metric | Description | +|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| +| `visitors` | The number of unique visitors. | +| `visits` | The number of visits/sessions | +| `pageviews` | The number of pageview events | +| `views_per_visit` | The number of pageviews divided by the number of visits. Returns a floating point number. Currently only supported in Aggregate and Timeseries endpoints. | +| `bounce_rate` | Bounce rate percentage | +| `visit_duration` | Visit duration in seconds | +| `events` | The number of events (pageviews + custom events). When filtering by a goal, this metric corresponds to "Total Conversions" in the dashboard. | +| `conversion_rate` | The percentage of visitors who completed the goal. Requires an `event:goal` filter or `event:goal` property in the breakdown endpoint | +| `time_on_page` | The average time users spend on viewing a single page. Requires an `event:page` filter or `event:page` property in the breakdown endpoint. | + +### Time periods + +The options are identical for each endpoint that supports configurable time periods. Each period is relative to a `date` parameter. The date should follow the standard ISO-8601 format. When not specified, the `date` field defaults to `today(site.timezone)`. +All time calculations on our backend are done in the time zone that the site is configured in. + +* `12mo,6mo` - Last n calendar months relative to `date`. +* `month` - The calendar month that `date` falls into. +* `30d,7d` - Last n days relative to `date`. +* `day` - Stats for the full day specified in `date`. +* `custom` - Provide a custom range in the `date` parameter. + +When using a custom range, the `date` parameter expects two ISO-8601 formatted dates joined with a comma as follows `?period=custom&date=2021-01-01,2021-01-31`. +Stats will be returned for the whole date range inclusive of the start and end dates. + +### Properties + +Each pageview and custom event in our database has some predefined _properties_ associated with it. In other analytics tools, these +are often referred to as _dimensions_ as well. Properties can be used for filtering and breaking down your stats to drill into +more depth. Here's the full list of properties we collect automatically: + +| Property | Example | Description | +| ----------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| `event:goal` | Register | A custom action that you want your users to take. To use this property, you first need to configure some goals in the [site settings](/website-settings), or via the [Sites API](/sites-api). The value is the goal's `display_name`. Learn more about goals [here](/goal-conversions). | +| `event:page` | /blog/remove-google-analytics | Pathname of the page where the event is triggered. You can also use an asterisk to group multiple pages (`/blog*`) | +| `event:hostname` | example.com | Hostname of the event. At this stage, breaking down on hostname is not supported and you can only use this property for filtering. Use an asterisk to filter by multiple hostnames at once, e.g. `*.example.com`. +| `visit:entry_page` | /home | Page on which the visit session started (landing page). | +| `visit:exit_page` | /home | Page on which the visit session ended (last page viewed). | +| `visit:source` | Twitter | Visit source, populated from an url query parameter tag (`utm_source`, `source` or `ref`) or the `Referer` HTTP header. | +| `visit:referrer` | t.co/fzWTE9OTPt | Raw `Referer` header without `http://`, `http://` or `www.`. | +| `visit:utm_medium` | social | Raw value of the `utm_medium` query param on the entry page. | +| `visit:utm_source` | twitter | Raw value of the `utm_source` query param on the entry page. | +| `visit:utm_campaign` | profile | Raw value of the `utm_campaign` query param on the entry page. | +| `visit:utm_content` | banner | Raw value of the `utm_content` query param on the entry page. | +| `visit:utm_term` | keyword | Raw value of the `utm_term` query param on the entry page. | +| `visit:device` | Desktop | Device type. Possible values are `Desktop`, `Laptop`, `Tablet` and `Mobile`. | +| `visit:browser` | Chrome | Name of the browser vendor. Most popular ones are `Chrome`, `Safari` and `Firefox`. | +| `visit:browser_version` | 88.0.4324.146 | Version number of the browser used by the visitor. | +| `visit:os` | Mac | Name of the operating system. Most popular ones are `Mac`, `Windows`, `iOS` and `Android`. Linux distributions are reported separately. | +| `visit:os_version` | 10.6 | Version number of the operating system used by the visitor. | +| `visit:country` | US | ISO 3166-1 alpha-2 code of the visitor country. | +| `visit:region` | US-MD | ISO 3166-2 code of the visitor region. | +| `visit:city` | 4347778 | [GeoName ID](https://www.geonames.org/) of the visitor city. | + +#### Custom properties + +In addition to properties that are collected automatically, you can also query for [custom properties](/custom-props/introduction). +To filter or break down by a custom property, use the key `event:props:`. [See example](#breakdown-custom-event-by-custom-properties) for how to use it. + +### Filtering + +Most endpoints support a `filters` query parameter to drill down into your data. You can filter by all properties described in the [Properties table](#properties), using the following operators: + +| Operator | Usage example | Explanation | +|-----------------|--------------------------------------------|---------------------------------------------------------------------------| +| `==` | `event:goal==Signup` | Simple equality - completed goal "Signup" | +| `!=` | `visit:country!=FR` | Simple inequality - country is not France | +| \| | visit:source==Github\|Twitter | IN expression - visit source is Github or Twitter. | +| `;` | `event:goal==Signup;visit:country==DE` | AND expression - completed goal "Signup" and country is Germany | +| `*` | `event:page==/blog/*` | Wildcard - matches any character | + +:::tip Want to use the `|` character in a filter value? +You can escape it with a backslash. For example, `visit:utm_campaign==campaign\|one` will let you filter by the literal `campaign|one` value +::: + +#### Limitations + +* It is currently possible to exclude only one value at a time (e.g. `visit:browser!=Chrome|Safari` is not yet supported) +* Wildcard characters cannot be used in combination with an IN expression (except for pageview goals - e.g. `event:goal==Signup|Visit+/register` is supported) +* Inequality `!=` operator is currently not supported for goals + +#### Filtering by goals + +Unlike other properties you need to set up the goals in your [site settings](/website-settings), or via the [Sites API](/sites-api) first, before you can filter by them. + +For custom event goals, the filter value is simply the name of your goal, e.g. `event:goal==Signup`. + +For pageview goals, the value should contain the string `"Visit"` followed by a space character, and the pathname of your pageview goal. For example: `Visit /register`. + +To include a space character in the query part of the URL, you can use `%20` (a URL encoded space character) or a `+` sign. For example: + +* `event:goal==Visit%20/register` +* `event:goal==Outbound+Link:+Click` + +### Imported stats + +Aggregates, timeseries and breakdowns support including imported stats in the results using `with_imported` option, with limitations. Breakdowns for custom properties (`event:props:*`) are only supported for 2 properties: `url` and `path`. Additionally, these breakdowns will only work in combination with a [certain subset](/csv-import#goals-and-custom-properties) of `event:goal` filters. + +#### Timeseries intervals + +Since imported data is aggregated for each date, it cannot be included in timeseries queries with an hourly interval (i.e. when querying for a `day` period in Timeseries). + +#### 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, `filters=event:page==/;visit:source==Twitter` is not able to return any imported results. The same happens when you try to filter by one property and break down by another. + +There are some exceptions though. The following properties 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 break down by `country` and filter by both `city` and `region`. When the applied combination of filters and property is not supported for imported stats, the results are still returned based only on native stats, with a warning. + +## Endpoints + +### GET /api/v1/stats/realtime/visitors + +This endpoint returns the number of current visitors on your site. A current visitor is defined as a visitor who triggered a pageview on your site +in the last 5 minutes. + +```bash title="Try it yourself" +curl "https://plausible.io/api/v1/stats/realtime/visitors?site_id=$SITE_ID" \ + -H "Authorization: Bearer ${TOKEN}" +``` + +```json title="Response" +21 +``` + +#### Parameters +
+ +**site_id** + +Domain of your site on Plausible. +
+ +### GET /api/v1/stats/aggregate + +This endpoint aggregates metrics over a certain time period. If you are familiar with the Plausible dashboard, this endpoint corresponds to the top row of stats that include `Unique Visitors` Pageviews, `Bounce rate` and `Visit duration`. You can retrieve any number and combination of these metrics in one request. + + +```bash title="Try it yourself" +curl "https://plausible.io/api/v1/stats/aggregate?site_id=$SITE_ID&period=6mo&metrics=visitors,pageviews,bounce_rate,visit_duration" \ + -H "Authorization: Bearer ${TOKEN}" +``` + +```json title="Response" +{ + "results": { + "bounce_rate": { + "value": 53.0 + }, + "pageviews": { + "value": 673814 + }, + "visit_duration": { + "value": 86.0 + }, + "visitors": { + "value": 201524 + } + } +} +``` + +#### Parameters +
+ +**site_id** + +Domain of your site on Plausible. + +
+ +**period** + +See [time periods](#time-periods). If not specified, it will default to `30d`. + +
+ +**metrics** + +Comma-separated list of metrics to aggregate, e.g. `visitors,pageviews,bounce_rate`. See the [list of available metrics](#metrics) above. + +If not specified, will default to `visitors`. + +:::note +Some metrics can only be queried with a certain filter. For example, the `conversion_rate` metric can only be queried with a filter on `event:goal`. Similarly, `time_on_page` can only be queried with an `event:page` filter. +::: + +
+ +**with_imported** + +A boolean determining whether to include imported stats in the returned results or not. If not specified, it will default to `false`. See [imported stats](#imported-stats) for more details. + +
+ +**compare** + +Off by default. You can specify `compare=previous_period` to calculate the percent difference with the previous period for each metric. The previous period will be of the exact same length as specified in the `period` parameter. + +
+ +**filters** + +See [filtering](#filtering) + +### GET /api/v1/stats/timeseries + +This endpoint provides timeseries data over a certain time period. If you are familiar with the Plausible dashboard, this endpoint corresponds to +the main visitor graph. + + +```bash title="Try it yourself" +curl "https://plausible.io/api/v1/stats/timeseries?site_id=$SITE_ID&period=6mo" \ + -H "Authorization: Bearer ${TOKEN}" +``` + +```json title="Response" +{ + "results": [ + { + "date": "2020-08-01", + "visitors": 36085 + }, + { + "date": "2020-09-01", + "visitors": 27688 + }, + { + "date": "2020-10-01", + "visitors": 71615 + }, + { + "date": "2020-11-01", + "visitors": 31440 + }, + { + "date": "2020-12-01", + "visitors": 35804 + }, + { + "date": "2021-01-01", + "visitors": 0 + } + ] +} +``` + +#### Parameters +
+ +**site_id** + +Domain of your site on Plausible. + +
+ +**period** + +See [time periods](#time-periods). If not specified, it will default to `30d`. + +
+ +**filters** + +See [filtering](#filtering) + +
+ +**metrics** + +Comma-separated list of metrics to show for each time bucket. Valid options are `visitors`, `visits`, `pageviews`, `views_per_visit`, `bounce_rate`, `visit_duration`, `events` and `conversion_rate`. If not specified, it will default to `visitors`. + +
+ +**with_imported** + +A boolean determining whether to include imported stats in the returned results or not. If not specified, it will default to `false`. See [imported stats](#imported-stats) for more details. + +
+ +**interval** + +Choose your reporting interval. Valid options are `day` (always) and `month` (when specified period is longer than one calendar month). Defaults to +`month` for `6mo` and `12mo`, otherwise falls back to `day`. + +### GET /api/v1/stats/breakdown + +This endpoint allows you to break down your stats by some property. If you are familiar with SQL family databases, this endpoint corresponds to +running `GROUP BY` on a certain property in your stats, then ordering by the count. + +Check out the [properties](#properties) section for a reference of all the properties you can use in this query. + +This endpoint can be used to fetch data for `Top sources`, `Top pages`, `Top countries` and similar reports. + + +```bash title="Try it yourself" +curl "https://plausible.io/api/v1/stats/breakdown?site_id=$SITE_ID&period=6mo&property=visit:source&metrics=visitors,bounce_rate&limit=5" \ + -H "Authorization: Bearer ${TOKEN}" +``` + +```json title="Response" +{ + "results": [ + { + "bounce_rate": 49.0, + "source": "(Direct / None)", + "visitors": 94932 + }, + { + "bounce_rate": 75.0, + "source": "Hacker News", + "visitors": 22540 + }, + { + "bounce_rate": 58.0, + "source": "Google", + "visitors": 16909 + }, + { + "bounce_rate": 62.0, + "source": "Twitter", + "visitors": 7477 + }, + { + "bounce_rate": 56.0, + "source": "indiehackers.com", + "visitors": 4518 + } + ] +} +``` + +#### Parameters +
+ +**site_id** + +Domain of your site on Plausible. + +
+ +**property** + +Which property to break down the stats by. Valid options are listed in the [properties](#properties) section above. Note that the `event:hostname` property is unsupported as a breakdown property at this stage. + +
+ +**period** + +See [time periods](#time-periods). If not specified, it will default to `30d`. + +
+ +**metrics** + +Comma-separated list of metrics to show for each item in breakdown. See the [list of available metrics](#metrics) above. If not specified, it will default to `visitors`. + +:::note +Some metrics require a certain filter or breakdown property. For example `conversion_rate` can be queried with a filter on `event:goal` or in a breakdown by`event:goal`. +::: + +
+ +**with_imported** + +A boolean determining whether to include imported stats in the returned results or not. If not specified, it will default to `false`. See [imported stats](#imported-stats) for more details. + +
+ +**limit** + +Limit the number of results. Maximum value is 1000. Defaults to 100. If you want to get more than 1000 results, you can make multiple requests and paginate the results by specifying the `page` parameter (e.g. make the same request with `page=1`, then `page=2`, etc) + +**page** + +Number of the page, used to paginate results. Importantly, the page numbers start from 1 not 0. + +**filters** + +See [filtering](#filtering) + +#### Breaking down by multiple properties at the same time + +Currently, it is only possible to break down on one property at a time. Using a list of properties with one query is not supported. So if you want a breakdown by both `event:page` and `visit:source` for example, you would have to make multiple queries (break down on one property and filter on another) and then manually/programmatically group the results together in one report. This also applies for breaking down by time periods. To get a daily breakdown for every page, you would have to break down on `event:page` and make multiple queries for each date. For a simple time period breakdown, have a look at the Timeseries endpoint. + +## Examples of common queries + +### Top pages + +Let's say you want to show a similar report to the `Top pages` report in the Plausible UI. You can do this by calling the +`/api/v1/stats/breakdown` endpoint and specify `event:page` as the property to group by. + +```bash title="Top pages" +curl "https://plausible.io/api/v1/stats/breakdown?site_id=$SITE_ID&period=6mo&property=event:page&limit=5" \ + -H "Authorization: Bearer ${TOKEN}" +``` + +```json title="Response" +{ + "results": [ + { + "page": "/", + "visitors": 94298 + }, + { + "page": "/blog/open-source-licenses", + "visitors": 18803 + }, + { + "page": "/plausible.io", + "visitors": 20485 + }, + { + "page": "/self-hosted-web-analytics", + "visitors": 22236 + }, + { + "page": "/sites", + "visitors": 32386 + } + ] +} +``` + +### Number of visitors to a specific page + +Let's say you want to get the number of visitors to a specific page on your website like `/order/confirmation`. This can be achieved by +filtering your stats on the `event:page` property: + +```bash title="Visitors to /order/confirmation" +curl "https://plausible.io/api/v1/stats/aggregate?site_id=$SITE_ID&period=6mo&filters=event:page%3D%3D%2Forder%2Fconfirmation" \ + -H "Authorization: Bearer ${TOKEN}" +``` + +```json title="Response" +{ + "results": { + "visitors": { + "value": 1480 + } + } +} +``` + +### Monthly traffic from Google + +As a second example, let's imagine we want to analyze our SEO efforts for the last half year. +To graph your traffic from Google over time, you can use the `timeseries` endpoint with a time period `6mo` and +filter expression `visit:source==Google`. + +```bash title="Monthly traffic from Google" +curl "https://plausible.io/api/v1/stats/timeseries?site_id=$SITE_ID&period=6mo&filters=visit:source%3D%3DGoogle" \ + -H "Authorization: Bearer ${TOKEN}" +``` + +```json title="Response" +{ + "results": [ + { + "date": "2020-09-01", + "visitors": 2962 + }, + { + "date": "2020-10-01", + "visitors": 4974 + }, + { + "date": "2020-11-01", + "visitors": 5119 + }, + { + "date": "2020-12-01", + "visitors": 5397 + }, + { + "date": "2021-01-01", + "visitors": 7167 + }, + { + "date": "2021-02-01", + "visitors": 5802 + } +] +} +``` + +### Breakdown custom event by custom properties + +A more advanced use-case where custom events are used along with custom properties. Let's say you have a `Download` custom event goal along with +a custom property called `method`. You can get a breakdown of download methods with the following query: + +```bash title="Breakdown of download methods" +curl "https://plausible.io/api/v1/stats/breakdown?site_id=$SITE_ID&period=6mo&property=event:props:method&filters=event:goal%3D%3DDownload" \ + -H "Authorization: Bearer ${TOKEN}" +``` + +```json title="Response" +{ + "results": [ + { + "method": "HTTP", + "visitors": 1477 + }, + { + "method": "Magnet", + "visitors": 370 + } + ] +} +``` + +:::tip Want to monitor the status of our API? +You can use GET https://plausible.io/api/health endpoint to do so +::: diff --git a/docs/stats-api-v2.md b/docs/stats-api-v2.md deleted file mode 100644 index 1a2e3d14..00000000 --- a/docs/stats-api-v2.md +++ /dev/null @@ -1,374 +0,0 @@ ---- -title: Stats API v2 reference -toc_max_heading_level: 4 -sidebar_label: Stats API v2 reference (Beta) ---- - -import { ApiV2Example, ExamplesTip } from '../src/js/apiv2-example.tsx'; -import { Required, Optional } from '../src/js/api-helpers.tsx'; -import { getExampleCode } from '../src/js/examples.tsx'; -import CodeBlock from '@theme/CodeBlock'; -import { SiteContextProvider } from '../src/js/sites.tsx'; - -:::warning[Beta feature] -Please be advised that this feature is currently in beta phase. It might change or break in the coming months as it is refined. -::: - -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!](#examples) - -:::tip[Not what you need?] -Take a look at our [Events API Reference](events-api.md) if you want to record pageviews or custom events for your sites, or [Sites API Reference](sites-api.md) 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](https://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. - -```bash -curl \ ---request POST \ -# highlight-next-line ---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: - -{getExampleCode("query", "example-country-and-city", null)} - - -Query can contain the following keys: - -### site_id - -Domain of your site on Plausible to be queried. - -### date_range {#date_range} - -Date range to be queried. - -| Option | Description | -| --- | --- | -| `["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 {#metrics} - -Metrics represent values to be calculated with the query. - -Valid metrics are: - -| Metric name | Description | -| --- | --- | -| `visitors` | The number of unique visitors | -| `visits` | The number of visits/sessions | -| `pageviews` | The number of pageview events | -| `views_per_visit` | The number of pageviews divided by the number of visits. Returns a floating point number. | -| `bounce_rate` | Bounce rate percentage | -| `visit_duration` | Visit duration in seconds | -| `events` | The number of events (pageviews + custom events). When filtering by a goal, this metric corresponds to "Total Conversions" in the dashboard. | -| `percentage` | The percentage of visitors of total who fall into this category: Requires: dimension list | -| `conversion_rate` | The percentage of visitors who completed the goal. Requires: dimension list passed, an event:goal filter or event:goal dimension | -| `group_conversion_rate` | The percentage of visitors who completed the goal with the same dimension. Requires: dimension list passed, an event:goal filter or event:goal dimension | - -### dimensions {#dimensions} - -Default: `[]` - -List of dimensions to group by. [See example](#example-utm) - -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: - -| Dimension | Example | Description | -| --- | --- | --- | -| `event:goal` | Register | A custom action that you want your users to take. To use this property, you first need to configure some goals in the [site settings](/website-settings), or via the [Sites API](/sites-api). The value is the goal's `display_name`. Learn more about goals [here](/goal-conversions). | -| `event:page` | /blog/remove-google-analytics | Pathname of the page where the event is triggered. You can also use an asterisk to group multiple pages (`/blog*`) | -| `event:hostname` | example.com | Hostname 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. - - -| Dimension | Example | Description | -| --- | --- | --- | -| `visit:entry_page` | /home | Page on which the visit session started (landing page). | -| `visit:exit_page` | /home | Page on which the visit session ended (last page viewed). | -| `visit:source` | Twitter | Visit source, populated from an url query parameter tag (`utm_source`, `source` or `ref`) or the Referer HTTP header. | -| `visit:referrer` | t.co/fzWTE9OTPt | Raw `Referer` header without `http://`, `http://` or `www.`. | -| `visit:utm_medium` | social | Raw value of the `utm_medium` query param on the entry page. | -| `visit:utm_source` | twitter | Raw value of the `utm_source` query param on the entry page. | -| `visit:utm_campaign` | profile | Raw value of the `utm_campaign` query param on the entry page. | -| `visit:utm_content` | banner | Raw value of the `utm_content` query param on the entry page. | -| `visit:utm_term` | keyword | Raw value of the `utm_term` query param on the entry page. | -| `visit:device` | Desktop | Device type. Possible values are `Desktop`, `Laptop`, `Tablet` and `Mobile`. | -| `visit:browser` | Chrome | Name of the browser vendor. Most popular ones are `Chrome`, `Safari` and `Firefox`. | -| `visit:browser_version` | 88.0.4324.146 | Version number of the browser used by the visitor. | -| `visit:os` | Mac | Name of the operating system. Most popular ones are `Mac`, `Windows`, `iOS` and `Android`. Linux distributions are reported separately. | -| `visit:os_version` | 10.6 | Version number of the operating system used by the visitor. | -| `visit:country` | US | ISO 3166-1 alpha-2 code of the visitor country. | -| `visit:region` | US-MD | ISO 3166-2 code of the visitor region. | -| `visit:city` | 4347778 | [GeoName ID](https://www.geonames.org/) of the visitor | -| `visit:country_name` | United States | Name of the visitor country. | -| `visit:region_name` | California | Name of the visitor region. | -| `visit:city_name` | San Francisco | Name of the visitor city. | - -#### Time dimensions {#time-dimensions} - -It's useful to be able to group data by time, which can be done via the following dimensions. - -| Dimension | Example | Description | -| -- | -- | -- | -| `time` | 2024-01-01 | Time 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:hour` | 2021-01-27T23:43:10Z | Time grouped by hour. ISO8601 timestamp | -| `time:day` | 2021-01-27 | Time grouped by date. ISO8601 date | -| `time:week` | 2021-01-04 | Time grouped by start of the week. ISO8601 date | -| `time:month` | 2021-01-01 | Time grouped by start of month. ISO8601 date | - -Note that: -- `time` dimensions are not usable in filters. Set [`date_range`](#date_range) instead. -- If no data falls into a given time bucket, no values are returned. [See `include.time_labels` option](#time-labels) for a workaround. - -[See example](#example-timeseries) - -#### Custom properties - -[Custom properties](/custom-props/introduction) can also be used as dimensions with the form `event:props:`. [See example](#example-custom-properties) - -### filters - -Default: `[]` - -Filters allow limiting the data analyzed in a query. [See example](#example-filtering). - -#### Simple filters - -Each simple filter takes the form of `[operator, dimension, clauses]`. - -##### operators - -The following operators are currently supported: - -| Operator | Example | Explanation | -| -- | -- | -- | -| `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](https://github.com/google/re2/wiki/Syntax) | -| `matches_not` | `["matches", "event:page", ["^/user/\d+$"]]` | Events where page does not match regular expression `^/user/\d+$`. [Uses re2 syntax](https://github.com/google/re2/wiki/Syntax) | - -##### dimension - -[Event and visit dimensions](#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. - -| Operator | Example | Explanation | -| -- | -- | -- | -| `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 - -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`](#metrics) or [`dimensions`](#dimensions) respectively. -- `direction` can be one of `"asc"` or `"desc"` - -For example: - -```json -[["visitors", "desc"], ["visit:country_name", "asc"]] -``` - -When not specified, the default ordering is: - -1. If a [time dimensions](#time-dimensions) is present, `[time_dimension, "asc"]` -2. By the first metric specified, descending. - -[See full query example](#example-custom-properties) - -### include - -Default: `{}` - -Additional options for the query as to what data to include. - -#### include.imports {#include.imports} - -Default: `false` - -If true, tries to include imported data in the result. See [imported stats](#imported-stats) for more details, [query example](#example-imports). - -
- 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](/csv-import#goals-and-custom-properties) 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](#example-imports-warning) - -#### include.time_labels {#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](#example-time-labels) - -#### include.total_rows {#include.total_rows} - -Default: `false` - -Should be used for [pagination](#pagination). If true, sets `meta.total_rows` in response containing the total number of -rows for this query. - -[See example](#example-pagination) - -### pagination - -Default: `{ "limit": 10000, "offset: 0 }` - -[See example](#example-pagination) - -## Response structure - -Example response: - -{getExampleCode("exampleResponse", "example-country-and-city", null)} - -### 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](#include.imports) and [include.time_labels](#include.time_labels). - -### query - -The query that was executed, after manipulations performed on the backend. - -## Examples - - - - - -### Simple aggregate query {#example-aggregate} - - - -### Custom date range {#example-custom-date-range} - - - -### Country and city analysis {#example-country-and-city} - - - -### UTM medium, source analysis {#example-utm} - - - -### Filtering by page and country {#example-filtering} - - - -### Timeseries query {#example-timeseries} - - - -### Timeseries query hourly, with labels {#example-time-labels} - - - -### Using custom properties {#example-custom-properties} - - - -### Pagination {#example-pagination} - - - -### Including imported data {#example-imports} - - - -### Including imported data failed {#example-imports-warning} - -In this example, imported data could not be included due to dimension and filter combination not supporting imports. [More information](#include.imports) - - - - diff --git a/docs/stats-api.md b/docs/stats-api.md index 7bff90af..2a9d6dac 100644 --- a/docs/stats-api.md +++ b/docs/stats-api.md @@ -1,559 +1,369 @@ --- -title: Stats API reference +title: Stats API v2 reference +toc_max_heading_level: 4 --- -import {Required, Optional} from '../src/js/api-helpers.tsx'; +import { ApiV2Example, ExamplesTip } from '../src/js/apiv2-example.tsx'; +import { Required, Optional } from '../src/js/api-helpers.tsx'; +import { getExampleCode } from '../src/js/examples.tsx'; +import CodeBlock from '@theme/CodeBlock'; +import { SiteContextProvider } from '../src/js/sites.tsx'; -The Plausible Stats API offers a way to retrieve your stats programmatically. It's a read-only interface to present historical and real-time stats only. Take a look at our [events API](events-api.md) if you want to send pageviews or custom events to our backend and our [sites API](sites-api.md) if you want to manage your sites through the API. +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. -The API accepts GET requests with query parameters and returns standard HTTP responses along with a JSON-encoded body. All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail. +[Try it now for your own site!](#examples) -Each request must be authenticated with an API key using the Bearer Token method. You can obtain an API key for your account by going to your user -settings page [plausible.io/settings](https://plausible.io/settings). - -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. - -The easiest way to explore the API is by using our Postman collection. Just define your `TOKEN` and `SITE_ID` variables, and you'll have an executable API reference ready to go. - -[![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/32c111c4f6d2cccef9dd) - -:::tip New to Postman? -We have a [step-by-step guide to set up the authorization and run your first queries with Postman](get-started-with-postman.md) +:::tip[Not what you need?] +Take a look at our [Events API Reference](events-api.md) if you want to record pageviews or custom events for your sites, or [Sites API Reference](sites-api.md) if you want to manage your sites over the API. ::: -## Concepts - -Querying the Plausible API will feel familiar if you have used time-series databases before. You can't query individual records from -our stats database. You can only request aggregated metrics over a certain time period. - -Each request requires a `site_id` parameter which is the domain of your site as configured in Plausible. If you're unsure, navigate to your site -settings in Plausible and grab the value of the `domain` field. - -### Metrics - -You can specify a `metrics` option in the query, to choose the metrics for each instance returned. See here for a full overview of [metrics and their definitions](/metrics-definitions). The metrics currently supported in Stats API are: - -| Metric | Description | -|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------| -| `visitors` | The number of unique visitors. | -| `visits` | The number of visits/sessions | -| `pageviews` | The number of pageview events | -| `views_per_visit` | The number of pageviews divided by the number of visits. Returns a floating point number. Currently only supported in Aggregate and Timeseries endpoints. | -| `bounce_rate` | Bounce rate percentage | -| `visit_duration` | Visit duration in seconds | -| `events` | The number of events (pageviews + custom events). When filtering by a goal, this metric corresponds to "Total Conversions" in the dashboard. | -| `conversion_rate` | The percentage of visitors who completed the goal. Requires an `event:goal` filter or `event:goal` property in the breakdown endpoint | -| `time_on_page` | The average time users spend on viewing a single page. Requires an `event:page` filter or `event:page` property in the breakdown endpoint. | - -### Time periods - -The options are identical for each endpoint that supports configurable time periods. Each period is relative to a `date` parameter. The date should follow the standard ISO-8601 format. When not specified, the `date` field defaults to `today(site.timezone)`. -All time calculations on our backend are done in the time zone that the site is configured in. - -* `12mo,6mo` - Last n calendar months relative to `date`. -* `month` - The calendar month that `date` falls into. -* `30d,7d` - Last n days relative to `date`. -* `day` - Stats for the full day specified in `date`. -* `custom` - Provide a custom range in the `date` parameter. - -When using a custom range, the `date` parameter expects two ISO-8601 formatted dates joined with a comma as follows `?period=custom&date=2021-01-01,2021-01-31`. -Stats will be returned for the whole date range inclusive of the start and end dates. - -### Properties - -Each pageview and custom event in our database has some predefined _properties_ associated with it. In other analytics tools, these -are often referred to as _dimensions_ as well. Properties can be used for filtering and breaking down your stats to drill into -more depth. Here's the full list of properties we collect automatically: - -| Property | Example | Description | -| ----------------------- | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -| `event:goal` | Register | A custom action that you want your users to take. To use this property, you first need to configure some goals in the [site settings](/website-settings), or via the [Sites API](/sites-api). The value is the goal's `display_name`. Learn more about goals [here](/goal-conversions). | -| `event:page` | /blog/remove-google-analytics | Pathname of the page where the event is triggered. You can also use an asterisk to group multiple pages (`/blog*`) | -| `event:hostname` | example.com | Hostname of the event. At this stage, breaking down on hostname is not supported and you can only use this property for filtering. Use an asterisk to filter by multiple hostnames at once, e.g. `*.example.com`. -| `visit:entry_page` | /home | Page on which the visit session started (landing page). | -| `visit:exit_page` | /home | Page on which the visit session ended (last page viewed). | -| `visit:source` | Twitter | Visit source, populated from an url query parameter tag (`utm_source`, `source` or `ref`) or the `Referer` HTTP header. | -| `visit:referrer` | t.co/fzWTE9OTPt | Raw `Referer` header without `http://`, `http://` or `www.`. | -| `visit:utm_medium` | social | Raw value of the `utm_medium` query param on the entry page. | -| `visit:utm_source` | twitter | Raw value of the `utm_source` query param on the entry page. | -| `visit:utm_campaign` | profile | Raw value of the `utm_campaign` query param on the entry page. | -| `visit:utm_content` | banner | Raw value of the `utm_content` query param on the entry page. | -| `visit:utm_term` | keyword | Raw value of the `utm_term` query param on the entry page. | -| `visit:device` | Desktop | Device type. Possible values are `Desktop`, `Laptop`, `Tablet` and `Mobile`. | -| `visit:browser` | Chrome | Name of the browser vendor. Most popular ones are `Chrome`, `Safari` and `Firefox`. | -| `visit:browser_version` | 88.0.4324.146 | Version number of the browser used by the visitor. | -| `visit:os` | Mac | Name of the operating system. Most popular ones are `Mac`, `Windows`, `iOS` and `Android`. Linux distributions are reported separately. | -| `visit:os_version` | 10.6 | Version number of the operating system used by the visitor. | -| `visit:country` | US | ISO 3166-1 alpha-2 code of the visitor country. | -| `visit:region` | US-MD | ISO 3166-2 code of the visitor region. | -| `visit:city` | 4347778 | [GeoName ID](https://www.geonames.org/) of the visitor city. | - -#### Custom properties - -In addition to properties that are collected automatically, you can also query for [custom properties](/custom-props/introduction). -To filter or break down by a custom property, use the key `event:props:`. [See example](#breakdown-custom-event-by-custom-properties) for how to use it. - -### Filtering +## Authentication -Most endpoints support a `filters` query parameter to drill down into your data. You can filter by all properties described in the [Properties table](#properties), using the following operators: +You can obtain an API key for your account by going to your user settings page [plausible.io/settings](https://plausible.io/settings). -| Operator | Usage example | Explanation | -|-----------------|--------------------------------------------|---------------------------------------------------------------------------| -| `==` | `event:goal==Signup` | Simple equality - completed goal "Signup" | -| `!=` | `visit:country!=FR` | Simple inequality - country is not France | -| \| | visit:source==Github\|Twitter | IN expression - visit source is Github or Twitter. | -| `;` | `event:goal==Signup;visit:country==DE` | AND expression - completed goal "Signup" and country is Germany | -| `*` | `event:page==/blog/*` | Wildcard - matches any character | +After creating a token, you can authenticate your request by sending the token in the Authorization header of your request. -:::tip Want to use the `|` character in a filter value? -You can escape it with a backslash. For example, `visit:utm_campaign==campaign\|one` will let you filter by the literal `campaign|one` value -::: - -#### Limitations - -* It is currently possible to exclude only one value at a time (e.g. `visit:browser!=Chrome|Safari` is not yet supported) -* Wildcard characters cannot be used in combination with an IN expression (except for pageview goals - e.g. `event:goal==Signup|Visit+/register` is supported) -* Inequality `!=` operator is currently not supported for goals +### Example curl request -#### Filtering by goals +In the following request, replace YOUR-TOKEN with a reference to your token and site_id value with your domain. -Unlike other properties you need to set up the goals in your [site settings](/website-settings), or via the [Sites API](/sites-api) first, before you can filter by them. - -For custom event goals, the filter value is simply the name of your goal, e.g. `event:goal==Signup`. +```bash +curl \ +--request POST \ +# highlight-next-line +--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" }' +``` -For pageview goals, the value should contain the string `"Visit"` followed by a space character, and the pathname of your pageview goal. For example: `Visit /register`. +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. -To include a space character in the query part of the URL, you can use `%20` (a URL encoded space character) or a `+` sign. For example: +## Request structure -* `event:goal==Visit%20/register` -* `event:goal==Outbound+Link:+Click` +`/api/v2/query` endpoint accepts a `query` object. Example: -### Imported stats +{getExampleCode("query", "example-country-and-city", null)} -Aggregates, timeseries and breakdowns support including imported stats in the results using `with_imported` option, with limitations. Breakdowns for custom properties (`event:props:*`) are only supported for 2 properties: `url` and `path`. Additionally, these breakdowns will only work in combination with a [certain subset](/csv-import#goals-and-custom-properties) of `event:goal` filters. -#### Timeseries intervals +Query can contain the following keys: -Since imported data is aggregated for each date, it cannot be included in timeseries queries with an hourly interval (i.e. when querying for a `day` period in Timeseries). +### site_id -#### Filtering imported stats +Domain of your site on Plausible to be queried. -Filtering by imported data is limited. The general rule is that you cannot filter by two different properties at the same time. -For example, `filters=event:page==/;visit:source==Twitter` is not able to return any imported results. The same happens when you try to filter by one property and break down by another. +### date_range {#date_range} -There are some exceptions though. The following properties are aggregated and grouped together and can be combined in a query: +Date range to be queried. -* 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 +| Option | Description | +| --- | --- | +| `["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 | -For example, you can break down by `country` and filter by both `city` and `region`. When the applied combination of filters and property is not supported for imported stats, the results are still returned based only on native stats, with a warning. +### metrics {#metrics} -## Endpoints +Metrics represent values to be calculated with the query. -### GET /api/v1/stats/realtime/visitors +Valid metrics are: -This endpoint returns the number of current visitors on your site. A current visitor is defined as a visitor who triggered a pageview on your site -in the last 5 minutes. +| Metric name | Description | +| --- | --- | +| `visitors` | The number of unique visitors | +| `visits` | The number of visits/sessions | +| `pageviews` | The number of pageview events | +| `views_per_visit` | The number of pageviews divided by the number of visits. Returns a floating point number. | +| `bounce_rate` | Bounce rate percentage | +| `visit_duration` | Visit duration in seconds | +| `events` | The number of events (pageviews + custom events). When filtering by a goal, this metric corresponds to "Total Conversions" in the dashboard. | +| `percentage` | The percentage of visitors of total who fall into this category: Requires: dimension list | +| `conversion_rate` | The percentage of visitors who completed the goal. Requires: dimension list passed, an event:goal filter or event:goal dimension | +| `group_conversion_rate` | The percentage of visitors who completed the goal with the same dimension. Requires: dimension list passed, an event:goal filter or event:goal dimension | -```bash title="Try it yourself" -curl "https://plausible.io/api/v1/stats/realtime/visitors?site_id=$SITE_ID" \ - -H "Authorization: Bearer ${TOKEN}" -``` +### dimensions {#dimensions} -```json title="Response" -21 -``` +Default: `[]` -#### Parameters -
+List of dimensions to group by. [See example](#example-utm) -**site_id** +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. -Domain of your site on Plausible. -
+#### Event dimensions -### GET /api/v1/stats/aggregate +Valid dimensions include: -This endpoint aggregates metrics over a certain time period. If you are familiar with the Plausible dashboard, this endpoint corresponds to the top row of stats that include `Unique Visitors` Pageviews, `Bounce rate` and `Visit duration`. You can retrieve any number and combination of these metrics in one request. +| Dimension | Example | Description | +| --- | --- | --- | +| `event:goal` | Register | A custom action that you want your users to take. To use this property, you first need to configure some goals in the [site settings](/website-settings), or via the [Sites API](/sites-api). The value is the goal's `display_name`. Learn more about goals [here](/goal-conversions). | +| `event:page` | /blog/remove-google-analytics | Pathname of the page where the event is triggered. You can also use an asterisk to group multiple pages (`/blog*`) | +| `event:hostname` | example.com | Hostname of the event. | +:::warning -```bash title="Try it yourself" -curl "https://plausible.io/api/v1/stats/aggregate?site_id=$SITE_ID&period=6mo&metrics=visitors,pageviews,bounce_rate,visit_duration" \ - -H "Authorization: Bearer ${TOKEN}" -``` +Mixing session metrics `bounce_rate`, `views_per_visit` and `visit_duration` with event dimensions is not allowed. +::: -```json title="Response" -{ - "results": { - "bounce_rate": { - "value": 53.0 - }, - "pageviews": { - "value": 673814 - }, - "visit_duration": { - "value": 86.0 - }, - "visitors": { - "value": 201524 - } - } -} -``` -#### Parameters -
+#### Visit dimensions + +Values of these dimensions are determined by the first pageview in a session. + + +| Dimension | Example | Description | +| --- | --- | --- | +| `visit:entry_page` | /home | Page on which the visit session started (landing page). | +| `visit:exit_page` | /home | Page on which the visit session ended (last page viewed). | +| `visit:source` | Twitter | Visit source, populated from an url query parameter tag (`utm_source`, `source` or `ref`) or the Referer HTTP header. | +| `visit:referrer` | t.co/fzWTE9OTPt | Raw `Referer` header without `http://`, `http://` or `www.`. | +| `visit:utm_medium` | social | Raw value of the `utm_medium` query param on the entry page. | +| `visit:utm_source` | twitter | Raw value of the `utm_source` query param on the entry page. | +| `visit:utm_campaign` | profile | Raw value of the `utm_campaign` query param on the entry page. | +| `visit:utm_content` | banner | Raw value of the `utm_content` query param on the entry page. | +| `visit:utm_term` | keyword | Raw value of the `utm_term` query param on the entry page. | +| `visit:device` | Desktop | Device type. Possible values are `Desktop`, `Laptop`, `Tablet` and `Mobile`. | +| `visit:browser` | Chrome | Name of the browser vendor. Most popular ones are `Chrome`, `Safari` and `Firefox`. | +| `visit:browser_version` | 88.0.4324.146 | Version number of the browser used by the visitor. | +| `visit:os` | Mac | Name of the operating system. Most popular ones are `Mac`, `Windows`, `iOS` and `Android`. Linux distributions are reported separately. | +| `visit:os_version` | 10.6 | Version number of the operating system used by the visitor. | +| `visit:country` | US | ISO 3166-1 alpha-2 code of the visitor country. | +| `visit:region` | US-MD | ISO 3166-2 code of the visitor region. | +| `visit:city` | 4347778 | [GeoName ID](https://www.geonames.org/) of the visitor | +| `visit:country_name` | United States | Name of the visitor country. | +| `visit:region_name` | California | Name of the visitor region. | +| `visit:city_name` | San Francisco | Name of the visitor city. | + +#### Time dimensions {#time-dimensions} + +It's useful to be able to group data by time, which can be done via the following dimensions. + +| Dimension | Example | Description | +| -- | -- | -- | +| `time` | 2024-01-01 | Time 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:hour` | 2021-01-27T23:43:10Z | Time grouped by hour. ISO8601 timestamp | +| `time:day` | 2021-01-27 | Time grouped by date. ISO8601 date | +| `time:week` | 2021-01-04 | Time grouped by start of the week. ISO8601 date | +| `time:month` | 2021-01-01 | Time grouped by start of month. ISO8601 date | + +Note that: +- `time` dimensions are not usable in filters. Set [`date_range`](#date_range) instead. +- If no data falls into a given time bucket, no values are returned. [See `include.time_labels` option](#time-labels) for a workaround. + +[See example](#example-timeseries) -**site_id** +#### Custom properties -Domain of your site on Plausible. +[Custom properties](/custom-props/introduction) can also be used as dimensions with the form `event:props:`. [See example](#example-custom-properties) -
+### filters -**period** +Default: `[]` -See [time periods](#time-periods). If not specified, it will default to `30d`. +Filters allow limiting the data analyzed in a query. [See example](#example-filtering). -
+#### Simple filters -**metrics** +Each simple filter takes the form of `[operator, dimension, clauses]`. -Comma-separated list of metrics to aggregate, e.g. `visitors,pageviews,bounce_rate`. See the [list of available metrics](#metrics) above. +##### operators -If not specified, will default to `visitors`. +The following operators are currently supported: -:::note -Some metrics can only be queried with a certain filter. For example, the `conversion_rate` metric can only be queried with a filter on `event:goal`. Similarly, `time_on_page` can only be queried with an `event:page` filter. -::: +| Operator | Example | Explanation | +| -- | -- | -- | +| `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](https://github.com/google/re2/wiki/Syntax) | +| `matches_not` | `["matches", "event:page", ["^/user/\d+$"]]` | Events where page does not match regular expression `^/user/\d+$`. [Uses re2 syntax](https://github.com/google/re2/wiki/Syntax) | -
+##### dimension -**with_imported** +[Event and visit dimensions](#dimensions) are valid for filters. -A boolean determining whether to include imported stats in the returned results or not. If not specified, it will default to `false`. See [imported stats](#imported-stats) for more details. +Note that only `is` operator is valid for `event:goal` dimension. -
+##### clauses -**compare** +List of values to match against. A data point matches filter if _any_ of the clauses matches. -Off by default. You can specify `compare=previous_period` to calculate the percent difference with the previous period for each metric. The previous period will be of the exact same length as specified in the `period` parameter. +#### Logical operations -
+Filters can be combined using `and`, `or` and `not` operators. -**filters** +| Operator | Example | Explanation | +| -- | -- | -- | +| `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 | -See [filtering](#filtering) +Note that top level filters is wrapped in an implicit `and`. -### GET /api/v1/stats/timeseries +### order_by -This endpoint provides timeseries data over a certain time period. If you are familiar with the Plausible dashboard, this endpoint corresponds to -the main visitor graph. +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`](#metrics) or [`dimensions`](#dimensions) respectively. +- `direction` can be one of `"asc"` or `"desc"` -```bash title="Try it yourself" -curl "https://plausible.io/api/v1/stats/timeseries?site_id=$SITE_ID&period=6mo" \ - -H "Authorization: Bearer ${TOKEN}" -``` +For example: -```json title="Response" -{ - "results": [ - { - "date": "2020-08-01", - "visitors": 36085 - }, - { - "date": "2020-09-01", - "visitors": 27688 - }, - { - "date": "2020-10-01", - "visitors": 71615 - }, - { - "date": "2020-11-01", - "visitors": 31440 - }, - { - "date": "2020-12-01", - "visitors": 35804 - }, - { - "date": "2021-01-01", - "visitors": 0 - } - ] -} +```json +[["visitors", "desc"], ["visit:country_name", "asc"]] ``` -#### Parameters -
+When not specified, the default ordering is: -**site_id** +1. If a [time dimensions](#time-dimensions) is present, `[time_dimension, "asc"]` +2. By the first metric specified, descending. -Domain of your site on Plausible. +[See full query example](#example-custom-properties) -
+### include -**period** +Default: `{}` -See [time periods](#time-periods). If not specified, it will default to `30d`. +Additional options for the query as to what data to include. -
+#### include.imports {#include.imports} -**filters** +Default: `false` -See [filtering](#filtering) +If true, tries to include imported data in the result. See [imported stats](#imported-stats) for more details, [query example](#example-imports). -
+
+ Read more on limitations of including imported data -**metrics** + 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](/csv-import#goals-and-custom-properties) of `event:goal` filters. -Comma-separated list of metrics to show for each time bucket. Valid options are `visitors`, `visits`, `pageviews`, `views_per_visit`, `bounce_rate`, `visit_duration`, `events` and `conversion_rate`. If not specified, it will default to `visitors`. + ##### 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. -**with_imported** + There are some exceptions though. The following dimensions are aggregated and grouped together and can be combined in a query: -A boolean determining whether to include imported stats in the returned results or not. If not specified, it will default to `false`. See [imported stats](#imported-stats) for more details. + * 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`. +
-**interval** +If set, `meta.imports_included` field will be set as a boolean. -Choose your reporting interval. Valid options are `day` (always) and `month` (when specified period is longer than one calendar month). Defaults to -`month` for `6mo` and `12mo`, otherwise falls back to `day`. +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](#example-imports-warning) -### GET /api/v1/stats/breakdown +#### include.time_labels {#include.time_labels} -This endpoint allows you to break down your stats by some property. If you are familiar with SQL family databases, this endpoint corresponds to -running `GROUP BY` on a certain property in your stats, then ordering by the count. +Default: `false` -Check out the [properties](#properties) section for a reference of all the properties you can use in this query. +Requires a `time` dimension being set. If true, sets `meta.time_labels` in response containing all +time labels valid for `date_range`. -This endpoint can be used to fetch data for `Top sources`, `Top pages`, `Top countries` and similar reports. +[See example](#example-time-labels) +#### include.total_rows {#include.total_rows} -```bash title="Try it yourself" -curl "https://plausible.io/api/v1/stats/breakdown?site_id=$SITE_ID&period=6mo&property=visit:source&metrics=visitors,bounce_rate&limit=5" \ - -H "Authorization: Bearer ${TOKEN}" -``` - -```json title="Response" -{ - "results": [ - { - "bounce_rate": 49.0, - "source": "(Direct / None)", - "visitors": 94932 - }, - { - "bounce_rate": 75.0, - "source": "Hacker News", - "visitors": 22540 - }, - { - "bounce_rate": 58.0, - "source": "Google", - "visitors": 16909 - }, - { - "bounce_rate": 62.0, - "source": "Twitter", - "visitors": 7477 - }, - { - "bounce_rate": 56.0, - "source": "indiehackers.com", - "visitors": 4518 - } - ] -} -``` +Default: `false` -#### Parameters -
+Should be used for [pagination](#pagination). If true, sets `meta.total_rows` in response containing the total number of +rows for this query. -**site_id** +[See example](#example-pagination) -Domain of your site on Plausible. +### pagination -
+Default: `{ "limit": 10000, "offset: 0 }` -**property** +[See example](#example-pagination) -Which property to break down the stats by. Valid options are listed in the [properties](#properties) section above. Note that the `event:hostname` property is unsupported as a breakdown property at this stage. +## Response structure -
+Example response: -**period** +{getExampleCode("exampleResponse", "example-country-and-city", null)} -See [time periods](#time-periods). If not specified, it will default to `30d`. +### results -
+Results is an ordered list query results. -**metrics** +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` -Comma-separated list of metrics to show for each item in breakdown. See the [list of available metrics](#metrics) above. If not specified, it will default to `visitors`. -:::note -Some metrics require a certain filter or breakdown property. For example `conversion_rate` can be queried with a filter on `event:goal` or in a breakdown by`event:goal`. -::: +### meta -
+Meta information about this query. Related: [include.imports](#include.imports) and [include.time_labels](#include.time_labels). -**with_imported** +### query -A boolean determining whether to include imported stats in the returned results or not. If not specified, it will default to `false`. See [imported stats](#imported-stats) for more details. +The query that was executed, after manipulations performed on the backend. -
+## Examples -**limit** + -Limit the number of results. Maximum value is 1000. Defaults to 100. If you want to get more than 1000 results, you can make multiple requests and paginate the results by specifying the `page` parameter (e.g. make the same request with `page=1`, then `page=2`, etc) + -**page** +### Simple aggregate query {#example-aggregate} -Number of the page, used to paginate results. Importantly, the page numbers start from 1 not 0. + -**filters** +### Custom date range {#example-custom-date-range} -See [filtering](#filtering) + -#### Breaking down by multiple properties at the same time +### Country and city analysis {#example-country-and-city} -Currently, it is only possible to break down on one property at a time. Using a list of properties with one query is not supported. So if you want a breakdown by both `event:page` and `visit:source` for example, you would have to make multiple queries (break down on one property and filter on another) and then manually/programmatically group the results together in one report. This also applies for breaking down by time periods. To get a daily breakdown for every page, you would have to break down on `event:page` and make multiple queries for each date. For a simple time period breakdown, have a look at the Timeseries endpoint. + -## Examples of common queries +### UTM medium, source analysis {#example-utm} -### Top pages + -Let's say you want to show a similar report to the `Top pages` report in the Plausible UI. You can do this by calling the -`/api/v1/stats/breakdown` endpoint and specify `event:page` as the property to group by. +### Filtering by page and country {#example-filtering} -```bash title="Top pages" -curl "https://plausible.io/api/v1/stats/breakdown?site_id=$SITE_ID&period=6mo&property=event:page&limit=5" \ - -H "Authorization: Bearer ${TOKEN}" -``` + -```json title="Response" -{ - "results": [ - { - "page": "/", - "visitors": 94298 - }, - { - "page": "/blog/open-source-licenses", - "visitors": 18803 - }, - { - "page": "/plausible.io", - "visitors": 20485 - }, - { - "page": "/self-hosted-web-analytics", - "visitors": 22236 - }, - { - "page": "/sites", - "visitors": 32386 - } - ] -} -``` +### Timeseries query {#example-timeseries} -### Number of visitors to a specific page + -Let's say you want to get the number of visitors to a specific page on your website like `/order/confirmation`. This can be achieved by -filtering your stats on the `event:page` property: +### Timeseries query hourly, with labels {#example-time-labels} -```bash title="Visitors to /order/confirmation" -curl "https://plausible.io/api/v1/stats/aggregate?site_id=$SITE_ID&period=6mo&filters=event:page%3D%3D%2Forder%2Fconfirmation" \ - -H "Authorization: Bearer ${TOKEN}" -``` + -```json title="Response" -{ - "results": { - "visitors": { - "value": 1480 - } - } -} -``` +### Using custom properties {#example-custom-properties} -### Monthly traffic from Google + -As a second example, let's imagine we want to analyze our SEO efforts for the last half year. -To graph your traffic from Google over time, you can use the `timeseries` endpoint with a time period `6mo` and -filter expression `visit:source==Google`. +### Pagination {#example-pagination} -```bash title="Monthly traffic from Google" -curl "https://plausible.io/api/v1/stats/timeseries?site_id=$SITE_ID&period=6mo&filters=visit:source%3D%3DGoogle" \ - -H "Authorization: Bearer ${TOKEN}" -``` + -```json title="Response" -{ - "results": [ - { - "date": "2020-09-01", - "visitors": 2962 - }, - { - "date": "2020-10-01", - "visitors": 4974 - }, - { - "date": "2020-11-01", - "visitors": 5119 - }, - { - "date": "2020-12-01", - "visitors": 5397 - }, - { - "date": "2021-01-01", - "visitors": 7167 - }, - { - "date": "2021-02-01", - "visitors": 5802 - } -] -} -``` +### Including imported data {#example-imports} -### Breakdown custom event by custom properties + -A more advanced use-case where custom events are used along with custom properties. Let's say you have a `Download` custom event goal along with -a custom property called `method`. You can get a breakdown of download methods with the following query: +### Including imported data failed {#example-imports-warning} -```bash title="Breakdown of download methods" -curl "https://plausible.io/api/v1/stats/breakdown?site_id=$SITE_ID&period=6mo&property=event:props:method&filters=event:goal%3D%3DDownload" \ - -H "Authorization: Bearer ${TOKEN}" -``` +In this example, imported data could not be included due to dimension and filter combination not supporting imports. [More information](#include.imports) -```json title="Response" -{ - "results": [ - { - "method": "HTTP", - "visitors": 1477 - }, - { - "method": "Magnet", - "visitors": 370 - } - ] -} -``` + -:::tip Want to monitor the status of our API? -You can use GET https://plausible.io/api/health endpoint to do so -::: + diff --git a/sidebars.js b/sidebars.js index 3767b810..1c49c166 100644 --- a/sidebars.js +++ b/sidebars.js @@ -81,7 +81,31 @@ module.exports = { ], }, ], - API: ['stats-api', 'events-api', 'sites-api', 'stats-api-v2', 'stats-api-playground'], + API: [ + { + type: 'category', + label: 'Stats API', + items: [ + { + type: 'doc', + id: 'stats-api', + label: 'Reference', + }, + { + type: 'doc', + id: 'stats-api-playground', + label: 'Playground', + }, + { + type: 'doc', + id: 'stats-api-v1', + label: 'v1 API Reference', + } + ] + }, + 'events-api', + 'sites-api', + ], Adblockers: [ { type: 'doc', id: 'proxy/introduction', label: 'Overview' }, { diff --git a/static/_redirects b/static/_redirects index f92bb310..a52add53 100644 --- a/static/_redirects +++ b/static/_redirects @@ -1 +1,4 @@ https://docs.plausible.io/* https://plausible.io/docs/:splat 301! + +# Legacy redirect +/docs/stats-api-v2 /docs/stats-api