Ecency analytics
How Ecency uses Plausible for cookie-free analytics, the public post views endpoint and connecting your own Plausible instance.
Ecency counts page views with Plausible Analytics, a privacy-friendly tool that doesn’t use cookies. This page covers the public endpoint for a post’s view stats. It also shows how to connect a self-hosted copy of the Ecency web app to your own Plausible Community Edition (CE) server.
Post view stats: POST /api/stats
Section titled “Post view stats: POST /api/stats”Anyone can read the view stats of a single post. This is the endpoint behind the stats shown on Ecency posts.
const res = await fetch("https://ecency.com/api/stats", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: "/@alice/my-first-post", metrics: ["visitors", "pageviews", "visit_duration"], date_range: "30d", }),});const stats = await res.json();if (!res.ok || typeof stats.status === "number") { // Error: see "Errors" below. Some errors come back as HTTP 200 with a status in the body.}Request body:
| Field | Required | Allowed values |
|---|---|---|
url |
Yes | The path of one post. It must end in /@author/permlink (a community or tag prefix is fine, such as /hive-123/@alice/my-first-post). Query strings and # fragments are ignored. It may be URL-encoded. |
metrics |
Yes | 1 to 4 unique values from visitors, visits, pageviews, visit_duration. |
dimensions |
No | Empty, or one of visit:source, visit:device, visit:country_name. |
date_range |
No | day, 7d, 30d, month, 6mo or 12mo (the default), or a pair of dates such as ["2026-01-01", "2026-10-01"]. all is not accepted. |
filterBy |
No | event:page (default, the post was viewed during the visit) or visit:entry_page (the visit started on the post). |
The response is Plausible’s Stats API v2 query result, passed through as is. For example:
{ "results": [{ "metrics": [120, 185, 42], "dimensions": [] }], "meta": {}, "query": { "site_id": "ecency.com", "metrics": ["visitors", "pageviews", "visit_duration"] }}Each metrics array follows the order of the metrics you asked for. With a dimension, you get one result per value (for example one per country).
Errors:
400for invalid JSON, metrics, dimensions or date range.403whenurlisn’t a single post path (for example/,/trendingor a profile).502or504when the analytics service fails or times out. Plausible’s own error status is passed through too.
Two errors come back with HTTP status 200 and the real status in the body, so check the body too, not just
res.ok:
{"status": 400}whenurlis missing.{"status": 404}when stats are turned off on that server (Plausible isn’t enabled).
A successful response never has a top-level status field.
Results are cached for a few minutes, so cache them on your side as well and don’t poll.
The SDK wraps this endpoint as getPageStatsQueryOptions(url, dimensions?, metrics?, dateRange?) in @ecency/sdk. See the SDK docs.
Profile-wide stats come from a separate route, /api/profile-insights. It needs a signed-in user and only returns numbers to the profile’s owner or to an Ecency Pro member.
Self-hosting: connect your own Plausible
Section titled “Self-hosting: connect your own Plausible”This part is for people running their own copy of the Ecency web app (vision-web). Out of the box the app reports to Ecency’s own Plausible instance, so change it before you go live.
1. Run Plausible CE
Section titled “1. Run Plausible CE”Follow the setup in Plausible’s official Community Edition repository. In short, on a host with Docker and the Docker Compose plugin:
# Use the current release tag shown in the CE READMEgit clone -b <release-tag> --single-branch https://github.com/plausible/community-edition plausible-cecd plausible-ce
echo "BASE_URL=https://plausible.example.com" >> .envecho "SECRET_KEY_BASE=$(openssl rand -base64 48)" >> .envecho "HTTP_PORT=80" >> .envecho "HTTPS_PORT=443" >> .env
docker compose up -dCheck the CE README for the full list of options and for upgrade notes between major versions. Then open your BASE_URL, create an account and add your site’s domain.
2. Set the environment variables
Section titled “2. Set the environment variables”| Variable | Used for |
|---|---|
PLAUSIBLE_API_HOST |
Your Plausible URL, for example https://plausible.example.com. |
PLAUSIBLE_DOMAIN |
The site domain you added in Plausible, for example example.com. |
PLAUSIBLE_API_KEY |
A Stats API key, created in Plausible under your account settings, API keys. It’s a read key. Only the server uses it, for /api/stats and /api/profile-insights. Page views are sent by the tracking script and don’t need a key. |
These feed the visionFeatures.plausible block in apps/web/src/config/config.ts:
plausible: { enabled: true, host: process.env.PLAUSIBLE_API_HOST || "<Ecency's instance>", siteId: process.env.PLAUSIBLE_DOMAIN || "ecency.com", apiKey: process.env.PLAUSIBLE_API_KEY}Set enabled: false to turn off the stats endpoints.
3. Point the tracking script at your server
Section titled “3. Point the tracking script at your server”The environment variables don’t change the tracking script. You have to edit two files:
-
apps/web/src/app/layout.tsxloads the script with a hardcoded domain:<Script defer data-domain="ecency.com" data-api="/pl/api/event" src="/pl/js/script.js" />Change
data-domainto yourPLAUSIBLE_DOMAIN. -
apps/web/next.config.jshas two rewrites that proxy/pl/js/script.jsand/pl/api/eventto Ecency’s Plausible server. Change both destinations to your Plausible host:{ source: "/pl/js/script.js", destination: "https://plausible.example.com/js/script.js" },{ source: "/pl/api/event", destination: "https://plausible.example.com/api/event" },
Because the script and events go through /pl/ on your own domain, the browser never contacts a third-party analytics host.
4. Check it works
Section titled “4. Check it works”Redeploy the web app and open a few pages. Watch them appear in your Plausible dashboard’s realtime view. Then open a post and call /api/stats for it to confirm the Stats API key works.