Skip to main content

Plausible Events API reference

The Plausible Events API can be used to record pageviews and custom events. This is useful when tracking Android or iOS mobile apps, or for server side tracking.

In most cases we recommend installing Plausible through our provided script or one of the many integration packages listed here. However, if there's no easy way for you to integrate with Plausible, you can still do so by sending events directly to our API.

Unique visitor tracking​

Important! Special care should be taken with two key headers which are used for unique visitor counting:

  1. The User-Agent header
  2. The X-Forwarded-For header

If these headers are not sent exactly as required, unique visitor counting will not work as intended. Please refer to the Request headers section below for more in-depth documentation on each header separately.

Endpoints​

POST /api/event​

Records a pageview or custom event. When using this endpoint, it's crucial to send the HTTP headers correctly, since these are used for unique user counting.

Try it yourself
curl -i -X POST https://plausible.io/api/event \
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36 OPR/71.0.3770.284' \
-H 'X-Forwarded-For: 127.0.0.1' \
-H 'Content-Type: application/json' \
--data '{"name":"pageview","url":"http://dummy.site","domain":"dummy.site"}'
Response 202 Accepted
{}

Request headers​


User-Agent REQUIRED

The raw value of User-Agent is used to calculate the user_id which identifies a unique visitor in Plausible.

User-Agent is also used to populate the Browsers, Operating Systems and Devices tabs in your Plausible dashboard. The device data is derived from the open source database device-detector. If your User-Agent is not showing up in your dashboard, it's probably because it is not recognized as one in the device-detector database.

The header is required but bear in mind that browsers and some HTTP libraries automatically add a default User-Agent header to HTTP requests. In case of browsers, we would not recommend overriding the header manually unless you have a specific reason to.


X-Forwarded-For optional

Used to explicitly set the IP address of the client. If not set, the remote IP of the sender will automatically be used. Depending on your use-case:

  1. If sending the event from your visitors' device, this header does not need to be set
  2. If sending the event from a backend server or proxy, make sure to override this header with the correct IP address of the client.
warning

If you forward a server, hosting provider, or CDN IP address instead of the actual visitor IP, Plausible's bot filtering will drop the event. The API still returns HTTP 202 with no obvious error, but the event is not recorded. You can confirm this by checking for x-plausible-dropped: 1 in the response headers.

The raw value of the IP address is not stored in our database. The IP address is used to calculate the user_id which identifies a unique visitor in Plausible. It is also used to fill the Location report with country, region and city data of the visitor.

If the header contains a comma-separated list (as it should if the request is sent through a chain of proxies), then the first valid IP address from the list is used. Both IPv4 and IPv6 addresses are supported. More information about the header format can be found on MDN docs.

If the request also carries a CF-Connecting-IP header, Plausible uses that address instead of X-Forwarded-For. When your proxy runs on Cloudflare (a Worker, for example), Cloudflare can fill this header with the proxy's own outgoing address, so set CF-Connecting-IP to the visitor's IP address as well.


Content-Type REQUIRED

Must be either application/json or text/plain. In case of text/plain, the request body is still interpreted as JSON.

How server-side events are attributed​

Plausible doesn't use cookies or persistent IDs. An event sent from your server joins a visitor's existing visit only when all of these are true:

  • It carries that visitor's own User-Agent and IP address (X-Forwarded-For)
  • Its url is on the same site (domain) the visitor is browsing
  • It arrives within 30 minutes of that visitor's last event

If there's no matching visit, the event starts a new visit. If its User-Agent and IP don't match any visitor's, it also counts as a new visitor. Its source then comes from the referrer and any UTM tags in the url you send. If you send neither, it's counted as Direct / None.

This decides where to send a revenue event from:

  • Good: from the request handler that renders your thank-you or success page. The visitor's browser is making that request, so you can forward its User-Agent and IP. Don't pass the request's Referer header as referrer for purchase events: if no visit is matched, the payment provider would become the source.
  • Not suitable: payment provider webhooks, scheduled jobs and retries. They run on the provider's or your servers, often minutes or days later, with no visitor headers. Their events can't be linked to the visit that led to the payment. They add visitors credited to Direct / None, or are dropped as data-center traffic.

Example (Node.js, run while handling the visitor's request to /thank-you):

await fetch('https://plausible.io/api/event', {
method: 'POST',
headers: {
'User-Agent': req.get('User-Agent'),
'X-Forwarded-For': req.ip, // make sure this is the visitor's IP, not your proxy's
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Purchase',
url: 'https://example.com/thank-you',
domain: 'example.com',
revenue: {amount: '49.00', currency: 'EUR'}
})
})

Visitors who block analytics scripts have no visit to join. A purchase sent from your server for them is still counted, with its revenue, but credited to Direct / None.

Request body JSON parameters​


domain REQUIRED

Domain name of the site in Plausible

This is the domain name you used when you added your site to your Plausible account

It doesn't need to be an actual domain name, so when adding your mobile app to Plausible, you could insert the mobile app name in the domain name field


name REQUIRED

Name of the event. Can specify pageview which is a special type of event in Plausible. All other names will be treated as custom events.


url REQUIRED

URL of the page where the event was triggered. If the URL contains UTM parameters, they will be extracted and stored. When using the script, this is set to window.location.href.

The hostname derived from url takes part in unique visitor recognition.

Sending two events from the same client, for two different hostnames, will result with two sessions recorded. If you don't include hostname in the url field (e.g. the value is /blog instead of https://example.com/blog), we'll store missing hostname as (none).

The maximum size of the URL, excluding the domain and the query string, is 2,000 characters. Additionally, URLs using the data URI scheme are not supported by the API.

The URL parameter will feel strange in a mobile app but you can manufacture something that looks like a web URL

If you name your mobile app screens like page URLs, Plausible will know how to handle it. So for example, on your login screen you could send something like:

event: pageview url: app://localhost/login

The pathname (/login) is what will be shown as the page value in the Plausible dashboard


referrer optional

Referrer for this event. When using the standard tracker script, this is set to document.referrer

Referrer values are processed heavily for better usability. Consider referrer URLS like m.facebook.com/some-path and facebook.com/some-other-path. It's intuitive to think of both of these as coming from a single source: Facebook. In the first example the referrer value would be split into visit:source == Facebook and visit:referrer == m.facebook.com/some-path.

Plausible uses the open source referer-parser database to parse referrers and assign these source categories.

When no match has been found, the value of the referrer field will be parsed as an URL. The hostname will be used as the visit:source and the full URL as the visit:referrer. So if you send https://some.domain.com/example-path, it will be parsed as follows: visit:source == some.domain.com visit:referrer == some.domain.com/example-path


props optional

Custom properties for the event. These can be attached to both pageviews and custom events. Learn more about using custom properties here.

The value corresponding to the props key in the request body is expected to be a JSON object with a maximum of 30 key-value pairs. If you include more than 30 items in the props object, the exceeding items will be discarded. For example, if you're using the text/plain content type, your request body might look like this:

'{"name":"pageview","url":"http://dummy.site","domain":"dummy.site","props":{"author":"John Doe","logged_in":"false"}}'

revenue optional

Revenue data for this event. This can be attached to goals and custom events to track revenue attribution. To learn more about revenue tracking and how you can set up your dashboard before sending revenue data, please read this document.

The value corresponding to the revenue key in the request body is expected to be a JSON object with currency and amount. currency is a ISO 4217 string representing the currency code, e.g. "USD" or "EUR". amount can be either a float or a string, e.g. 1322.22 or "1322.22". In the case of an invalid currency or amount, the event is still recorded and the API returns HTTP 202, but revenue data associated with it is discarded.

For example, to track a purchase of US$ 1.322,22, your request body might look like this:

{"name":"Purchase","url":"http://dummy.site","domain":"dummy.site","revenue":{"currency":"USD","amount":"1322.22"}}

interactive optional

Whether the event is interactive. By default, Plausible will assume all events are interactive and will be counted for bounce detection.

By marking a custom event as non-interactive, it will not be counted towards bounce rate calculations.

Debugging​

The API always returns HTTP 202 Accepted, even when an event is dropped. To debug your setup, there are two tools:

Check if events are being dropped: Inspect the response headers for x-plausible-dropped: 1. When present, the event was rejected by bot filtering. The most common cause is X-Forwarded-For containing a server or CDN IP instead of the actual visitor IP.

Check which IP address Plausible sees: Add the X-Debug-Request: true header to your request. The API will return HTTP 200 with the IP address it will use for unique visitor counting. Use this to confirm that X-Forwarded-For is being forwarded correctly from your proxy. Requests sent with this header are not recorded in your stats, so use it on separate test requests rather than on your real events.

E.g: Add this header to your request and log the response.

Test the path your real events take. Send an X-Debug-Request test request from the same place your production events are sent (your server, worker, edge function or retry job), not only from your own computer. X-Forwarded-For can be set correctly in your code and still reach us with a different IP: a proxy, CDN, load balancer or hosting provider along the way may replace the header or add its own address to it. If the header contains a comma-separated list, Plausible uses the first valid IP address in it, so make sure the visitor's IP comes first. Also check that the visitor's original User-Agent is forwarded, not your server's or HTTP library's default.

Dropped events can't be added to your stats afterwards, so it's worth running these checks whenever you set up or change your integration.

Want to monitor the status of our API?

You can can use GET https://plausible.io/api/health endpoint to do so

Ready to ditch Google Analytics?

Start your free trial today