Plausible API 使用详解
逐条 curl 实测 Plausible CE v3.2.1 三组 API:Stats API v1(realtime/aggregate/timeseries/breakdown 的 date_range/metrics/filters 组合与 7 类错误分支)、Query API v2(dimensions+filter_tree+schema)、Events API 采集上报(pageview/自定义事件 props 与 6 类边界分支),全部响应 JSON 实测照抄。
Plausible API 使用详解
> 目标:面向开发者讲清 Plausible 的三组 API——Stats API(v1,GET 查询)、Query API(v2,POST 查询)、Events API(采集上报)——并用逐条 curl 实测覆盖参数组合与错误分支。本文全部请求与响应 JSON 均在实测环境(Plausible CE v3.2.1)执行并照抄;部署与环境准备见《Plausible Docker Compose 部署指南》,参数调优见《Plausible 配置参数详解》。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 22.04.4 LTS |
| 组件版本 | Plausible CE v3.2.1 |
| 服务地址 | http://192.168.146.128:13910(下文示例统一用 http://127.0.0.1:13910) |
| 演示站点 | mysite.dev(已通过《Plausible Docker Compose 部署指南》4.7 节埋点实测积累数据) |
| 测试账号 | admin@example.com(API Key:qzuo-demo-key-2026,实测创建) |
| 实测日期 | 2026-10-18 |
| 事件数据 | 事件库 events_v2 实测累计 5 条事件(4 条 pageview + 1 条自定义事件 signup) |
二、API 概览与认证
| API | 方法与路径 | 用途 | 认证 |
|---|---|---|---|
| Stats API(v1) | GET /api/v1/stats/* | 实时/聚合/时序/分组查询 | Authorization: Bearer <key> |
| Query API(v2) | POST /api/v2/query | 复杂查询(多维度/过滤树/分页) | 同上 |
| Events API | POST /api/event | 埋点上报(页面浏览/自定义事件) | 无需认证(等同浏览器脚本) |
| Sites API | POST /api/v1/sites/* | 站点与目标管理 | 同 Stats API(本文不展开) |
API Key 创建:
- UI 路径(官方文档口径):登录 → 右上角账号名 → Settings → API Keys → New API Key(Key 只显示一次);
- 本文为可复现实测,通过应用内置 CLI 创建(在应用服务内执行,等价于 UI 操作):
/app/bin/plausible rpc \
'user = Plausible.Repo.get!(Plausible.Auth.User, 1); {:ok, team} = Plausible.Teams.get_or_create(user); res = Plausible.Auth.create_stats_api_key(user, team, "docs-demo", "qzuo-demo-key-2026"); IO.inspect(res, label: "APIKEY")'
实测回显(节选):
{:ok,
%Plausible.Auth.ApiKey{
...
user_id: 1,
name: "docs-demo",
key: "qzuo-demo-key-2026",
inserted_at: ~N[2026-10-17 22:58:44],
updated_at: ~N[2026-10-17 22:58:44]
}}
📌 Key 按**团队(Team)**隔离:只能查询创建时所属团队的站点(官方文档明示)。限流:官方文档注明默认 600 请求/小时(2026-10-18 抓取 https://plausible.io/docs/stats-api )。
三、快速开始
# 1. 配置认证头(示例值,请替换为你的 Key)
K='Authorization: Bearer qzuo-demo-key-2026'
# 2. 查一次聚合
curl -s -H "$K" \
'http://127.0.0.1:13910/api/v1/stats/aggregate?site_id=mysite.dev&period=day&metrics=visitors,pageviews'
# 3. 上报一条页面浏览
curl -s -X POST http://127.0.0.1:13910/api/event \
-H 'Content-Type: application/json' \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) Chrome/126 Safari/537.36' \
-d '{"name":"pageview","domain":"mysite.dev","url":"http://mysite.dev/"}'
# 响应:ok(HTTP 202),约 5 秒后落库可查
四、Stats API 详解(/api/v1/stats)
4.1 realtime visitors(实时访客)
请求:
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' \
'http://127.0.0.1:13910/api/v1/stats/realtime/visitors?site_id=mysite.dev'
实测序列(响应为纯文本数字,非 JSON):
| 时点 | 实测返回 | 说明 |
|---|---|---|
| 发送 1 条 pageview 后立即查询 | 0 | 事件还在内存缓冲(默认 5 秒刷盘) |
| 补发 1 条并等待约 30 秒 | 2 | 近 5 分钟窗口内 2 名访客 |
完整 down → up 循环 + 1 条新 pageview 后 | 1 | 历史会话已滑出 5 分钟窗口 |
参数:仅 site_id(站点域名)。
4.2 aggregate(聚合指标)
① 常用指标组合(period=day):
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' \
'http://127.0.0.1:13910/api/v1/stats/aggregate?site_id=mysite.dev&period=day&metrics=visitors,pageviews,bounce_rate,visit_duration,views_per_visit,visits'
实测响应(当天累计 4 次访问):
{
"results": {
"pageviews": {
"value": 4
},
"visit_duration": {
"value": 117
},
"visitors": {
"value": 4
},
"visits": {
"value": 4
},
"bounce_rate": {
"value": 50
},
"views_per_visit": {
"value": 1.0
}
}
}
② 自定义日期范围(period=custom):
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' \
'http://127.0.0.1:13910/api/v1/stats/aggregate?site_id=mysite.dev&period=custom&date=2026-10-17,2026-10-18&metrics=visitors,pageviews'
实测响应:
{"results":{"pageviews":{"value":4},"visitors":{"value":4}}}
③ 带过滤条件(filters):只看 /pricing 页:
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' \
'http://127.0.0.1:13910/api/v1/stats/aggregate?site_id=mysite.dev&period=custom&date=2026-10-17,2026-10-18&metrics=visitors,pageviews&filters=event:page==/pricing'
实测响应:
{"results":{"pageviews":{"value":2},"visitors":{"value":2}}}
参数小结:
| 参数 | 取值(实测验证) | 说明 |
|---|---|---|
site_id | 站点域名,如 mysite.dev | 必填 |
period | day / 7d / 30d / custom 等 | 自定义需配合 date |
date | YYYY-MM-DD 或 起,止(逗号分隔) | custom 时用;实测 2026-10-17,2026-10-18 有效 |
metrics | 逗号分隔,实测有效:visitors、pageviews、bounce_rate、visit_duration、views_per_visit、visits、events_per_session、time_on_page | 无效指标返回 400(见 4.5) |
filters | 维度==值,如 event:page==/pricing | 过滤维度详见 4.4 |
4.3 timeseries(时序数据)
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' \
'http://127.0.0.1:13910/api/v1/stats/timeseries?site_id=mysite.dev&period=custom&date=2026-10-17,2026-10-18&metrics=visitors,pageviews&interval=date'
实测响应(事件集中在 10-17,10-18 为 0):
{
"results": [
{
"date": "2026-10-17",
"pageviews": 4,
"visitors": 4
},
{
"date": "2026-10-18",
"pageviews": 0,
"visitors": 0
}
]
}
参数:在 aggregate 基础上增加 interval(date/hour/month,实测 date 按天聚合)。
4.4 breakdown(维度分组)
① 按页面分组:
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' \
'http://127.0.0.1:13910/api/v1/stats/breakdown?site_id=mysite.dev&property=event:page&period=custom&date=2026-10-17,2026-10-18&metrics=visitors,pageviews,bounce_rate,time_on_page'
实测响应:
{
"results": [
{
"page": "/pricing",
"pageviews": 2,
"visitors": 2,
"time_on_page": null,
"bounce_rate": 100
},
{
"page": "/",
"pageviews": 1,
"visitors": 1,
"time_on_page": null,
"bounce_rate": 0
},
{
"page": "/blog/hello-world",
"pageviews": 1,
"visitors": 1,
"time_on_page": null,
"bounce_rate": 100
},
{
"page": "/register",
"pageviews": 0,
"visitors": 1,
"time_on_page": null,
"bounce_rate": 0
}
]
}
⚠️ 实测发现:
time_on_page在 breakdown 中返回null(该指标在分组场景无数据),但 aggregate 中可正常返回数值——分组查询建议改用visit_duration。
② 按来源分组:
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' \
'http://127.0.0.1:13910/api/v1/stats/breakdown?site_id=mysite.dev&property=visit:source&period=custom&date=2026-10-17,2026-10-18&metrics=visitors'
实测响应:
{"results":[{"source":"Direct / None","visitors":4}]}
③ 按浏览器分组:
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' \
'http://127.0.0.1:13910/api/v1/stats/breakdown?site_id=mysite.dev&property=visit:browser&period=custom&date=2026-10-17,2026-10-18&metrics=visitors'
实测响应:
{"results":[{"browser":"Chrome","visitors":3},{"browser":"Safari","visitors":1}]}
④ 分组 + 过滤组合:各浏览器在 /pricing 页的访客:
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' \
'http://127.0.0.1:13910/api/v1/stats/breakdown?site_id=mysite.dev&property=visit:browser&period=custom&date=2026-10-17,2026-10-18&metrics=visitors&filters=event:page==/pricing'
实测响应:
{"results":[{"browser":"Chrome","visitors":2}]}
常用维度前缀(实测验证 event:page、visit:source、visit:browser):event:* 为事件属性(如 event:page、event:url、自定义 event:props:xxx);visit:* 为会话属性(如 visit:source、visit:browser、visit:os、visit:device、visit:country、visit:entry_page、visit:exit_page)。
4.5 错误分支实测
| 场景 | 请求 | 实测响应 |
|---|---|---|
| 无认证 | curl -s '.../aggregate?site_id=mysite.dev&period=30d&metrics=visitors' | {"error":"missing or invalid API key"} |
| 错误 Key | -H 'Authorization: Bearer wrong-key' | {"error":"invalid api key"} |
| 未知站点 | site_id=noexist.dev | {"error":"could not find site with domain \"noexist.dev\""} |
| 未知指标 | metrics=foo | {"error":"Invalid metrics"} |
| 缺 site_id | .../aggregate?period=day&metrics=visitors | {"error":"site_id is required"} |
| 非法 filter | filters=page==/x | {"error":"invalid filter: page==/x"} |
| 指标不适用 | metrics=visitors,time_on_page(day 聚合) | 正常返回,time_on_page 值为 null(分组/特定窗口才有值) |
五、Query API(v2,POST /api/v2/query)
v2 是官方当前主推的查询接口:单端点、JSON 请求体,支持维度、过滤树与分页;模式由 /api/docs/query/schema.json 公开(实测可获取)。
5.1 基本聚合
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' -H 'Content-Type: application/json' \
-X POST http://127.0.0.1:13910/api/v2/query \
-d '{"site_id":"mysite.dev","metrics":["visitors","pageviews","bounce_rate"],"date_range":["2026-10-17","2026-10-18"]}'
实测响应:
{
"results": [
{
"metrics": [
4,
4,
50
],
"dimensions": []
}
],
"meta": {},
"query": {
"site_id": "mysite.dev",
"metrics": [
"visitors",
"pageviews",
"bounce_rate"
],
"date_range": [
"2026-10-17T00:00:00Z",
"2026-10-18T23:59:59Z"
],
"filters": [],
"dimensions": [],
"order_by": [
[
"visitors",
"desc"
]
],
"include": {},
"pagination": {
"offset": 0,
"limit": 10000
}
}
}
📌 响应的
query字段回显了服务端解析结果(date_range被规范化为 UTC 起止时刻,默认排序visitors desc,分页默认limit: 10000)。
5.2 维度 + 过滤
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' -H 'Content-Type: application/json' \
-X POST http://127.0.0.1:13910/api/v2/query \
-d '{"site_id":"mysite.dev","metrics":["visitors","pageviews"],"date_range":["2026-10-17","2026-10-18"],"filters":[["is","event:page",["/pricing"]]],"dimensions":["event:page"]}'
实测响应(metrics 与 dimensions 数组按位对应):
{
"results": [
{
"metrics": [
2,
2
],
"dimensions": [
"/pricing"
]
}
],
"meta": {},
"query": {
"site_id": "mysite.dev",
"metrics": [
"visitors",
"pageviews"
],
"date_range": [
"2026-10-17T00:00:00Z",
"2026-10-18T23:59:59Z"
],
"filters": [
[
"is",
"event:page",
[
"/pricing"
]
]
],
"dimensions": [
"event:page"
],
"order_by": [
[
"visitors",
"desc"
]
],
"include": {},
"pagination": {
"offset": 0,
"limit": 10000
}
}
}
5.3 请求体 Schema(实测自 schema.json)
curl -s http://127.0.0.1:13910/api/docs/query/schema.json | python3 -m json.tool
实测关键定义(照抄):
- 必填字段:
site_id、metrics、date_range; date_range:两个 ISO8601 日期的数组({"minItems": 2, "maxItems": 2, "items": {"format": "date", "type": "string"}}),示例["2024-09-01", "2024-09-30"];filter_tree:filter_entry/filter_and_or/filter_not/filter_has_done的 oneOf 组合,支持is/contains/matches(正则)/wildcard等操作;dimensions:simple_filter_dimensions/custom_property_filter_dimensions/goal_dimension/time_dimensions之一。
校验错误实测(非法 date_range):
curl -s -H 'Authorization: Bearer qzuo-demo-key-2026' -H 'Content-Type: application/json' \
-X POST http://127.0.0.1:13910/api/v2/query \
-d '{"site_id":"mysite.dev","metrics":["visitors","pageviews"],"date_range":"bad"}'
实测响应:
{"error":"#/date_range: Invalid date range \"bad\""}
六、Events API(POST /api/event)
采集上报接口,无需认证(与浏览器埋点脚本同源),仅接受 POST。
6.1 页面浏览
curl -s -w '\nHTTP %{http_code}\n' -X POST http://127.0.0.1:13910/api/event \
-H 'Content-Type: application/json' \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' \
-d '{"name":"pageview","domain":"mysite.dev","url":"http://mysite.dev/"}'
实测响应:
ok
HTTP 202
字段说明:name(事件名,页面浏览固定 pageview)、domain(站点域名)、url(完整页面地址,用于解析路径/来源);UA 决定浏览器/操作系统/设备维度,缺 UA 会影响这些维度取值。
6.2 自定义事件与属性(props)
curl -s -w ' [HTTP %{http_code}]\n' -X POST http://127.0.0.1:13910/api/event \
-H 'Content-Type: application/json' \
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' \
-d '{"name":"signup","domain":"mysite.dev","url":"http://mysite.dev/register","props":{"plan":"pro","amount":99}}'
实测响应:
ok [HTTP 202]
事件落库验证(事件库 clickhouse-client 直查实测):
SELECT name, count() AS c FROM plausible_events_db.events_v2 GROUP BY name ORDER BY c DESC;
pageview 4
signup 1
📌 自定义事件要在仪表盘显示为转化目标,需在站点设置中添加同名 Goal(本文实测仅验证上报与落库)。
6.3 错误与边界分支实测
| 场景 | 请求体/方式 | 实测响应 |
|---|---|---|
缺 url | {"name":"pageview","domain":"mysite.dev"} | {"errors":{"url":["is required"]}} 400 |
| 空 body | {} | {"errors":{"domain":["can't be blank"],"url":["is required"],"event_name":["can't be blank"]}} 400 |
缺 domain(有 url) | {"name":"pageview","url":"http://x.dev/"} | ok 202(宽松接受,但事件无法归属站点,勿依赖) |
| 未知站点 | {"name":"pageview","domain":"no-such.dev","url":"http://no-such.dev/"} | ok 202(也返回 202,事件实际未入库——防探测设计,见下) |
| GET 请求 | GET /api/event | 404 HTML 错误页(<h1>404</h1>) |
| 非 JSON Content-Type | -H 'Content-Type: text/plain' + 合法 JSON | ok 202(服务端宽松解析,规范仍要求 application/json) |
💡 关键发现:对未知站点上报也返回
202 ok(响应内容与成功一致,事件不会入库)。因此不能用 Events API 的响应判断站点是否存在;上报成功与否的可靠验证方式是查事件库或稍后查 Stats API。
时效注意:事件先入内存缓冲,默认每 5 秒(CLICKHOUSE_FLUSH_INTERVAL_MS=5000)批量刷入事件库(实测见《Plausible 配置参数详解》5.3),发送后立即查询可能看不到。
七、错误处理与限流
- 认证错误统一返回
{"error": "..."}(HTTP 401/403),文案见 4.5; - 参数校验错误:v1 返回
400+error文案;v2 返回400+ JSON Schema 路径(如#/date_range: ...);Events API 返回400+errors字段级错误; - 限流:官方文档注明默认 600 请求/小时,超限返回
429(本文未触发实测该阈值); - 调试建议:先打
/api/health确认服务正常,再打/api/v1/stats/aggregate?period=day&metrics=visitors最小化验证认证与站点归属,最后逐步加参数。
八、常见问题(FAQ)
Q1:realtime visitors 返回的是数字不是 JSON?
是。该端点返回纯文本整数(实测 2),脚本解析时注意别按 JSON 处理。
Q2:发完事件马上查不到数据?
5 秒缓冲 + 查询缓存所致(实测发送后立即查 0,约 30 秒内出现)。相关参数见《Plausible 配置参数详解》5.3。
Q3:breakdown 里 time_on_page 是 null?
该指标在分组场景无数据(实测返回 null),分组统计改用 visit_duration。
Q4:自定义事件上报 202 了,仪表盘为什么没有转化数据?
202 只代表事件被接受且入库;要在仪表盘展示为转化,还需在站点设置里添加同名目标(Goal)。实测确认事件已落库(6.2)。
Q5:Events API 能否用来探测站点是否存在?
不能。未知站点同样返回 202(实测 6.3),需用 Stats API 或界面确认。
Q6:v1 与 v2 该用哪个?
新集成建议 v2(单端点、过滤树、分页、schema 自描述);v1 适合简单 GET 集成与脚本调试。两者指标名一致。
九、参考链接
- 官方 Stats API 文档(含限流/Key 团队隔离说明):https://plausible.io/docs/stats-api(2026-10-18 抓取)
- 官方 Events API 文档:https://plausible.io/docs/events-api(2026-10-18 抓取)
- v2 请求 Schema(本机实测获取):
/api/docs/query/schema.json - 仪表盘内 API 文档:登录后 Settings → API Keys 页面有交互式 playground
- 本系列:《Plausible 介绍与选型指南》《Plausible Docker Compose 部署指南》《Plausible 配置参数详解》