Modulify

Query visitor analytics freely

query_site_analytics

Asks an arbitrary question of a site's visitor analytics as a Plausible Stats v2 query, such as its top pages, sources or countries.

POST /v1/query_site_analyticsScopeanalytics:readRead only

It answers what the fixed shape of get_site_analytics cannot, and it is the tool for top pages, traffic sources, countries, browsers, operating systems and devices. The site is filled in for you, so there is no site_id to send, and anything passed for it is overwritten.

Pick metrics from visitors, visits, pageviews, views_per_visit, bounce_rate and visit_duration. Set date_range to a named period such as 7d or 30d, or to a two element list of ISO dates, where a custom range longer than 3,660 days is refused. Add dimensions to break the numbers down: event:page for top pages, visit:source for traffic sources, visit:country, visit:browser, visit:os, visit:device, or time:day, time:hour or time:month for a series over time.

pagination.limit caps the rows at 1,000, a larger value is lowered to 1,000, and leaving it out returns up to that many. Pagination only applies when you break down by a dimension, and the product itself uses 8 for its breakdown cards. time:minute is not available, and time:hour needs day, 7d, 30d, month or a custom range of at most 31 days.

The response carries provisioned, the analytics domain, the results rows and the query meta. A query the analytics backend rejects fails with its reason, so an empty results list really means no matching traffic.

Each call costs 1 of the 1,200 analytics lookups access tokens share per site per hour, as Rate limits and result size explains, and nothing when the answer is already cached. Unlike the tools that read fixed numbers, it spends that lookup even on a site that was never published. Over that limit it fails with Access tokens, through MCP clients or the API, used their 1,200 analytics lookups for this site this hour. Wait and try again! See Breakdowns.

Request

Call it with a POST to https://api.modulify.ai/v1/query_site_analytics, sending the inputs below as a JSON object. The token needs the analytics:read scope.

It only reads and changes nothing, so retrying it is safe.

curl -X POST https://api.modulify.ai/v1/query_site_analytics \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"PROJECT_ID","query":{}}'

Over MCP, the same method is the query_site_analytics tool.

Inputs

Input Type Required Description
projectId string Yes The site id.
query object Yes The Plausible Stats v2 query, with the fields metrics, date_range, dimensions, filters (for example [["is", "visit:country", ["DE"]]]), order_by, pagination with its limit and offset, and include, such as time_labels true for a labeled series. site_id is set for you, and anything passed for it is overwritten.

Response

Every call answers with the JSON envelope of success, message, data, code and version. data holds the result described above, and on a method that returns a total, count carries it. The response headers carry the call's X-Request-Id and what is left of your per-minute budget in X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Errors explains every status code a call can answer with.