Each report exists three ways, and they all return the same data:
- an ability, such as
vireo-analytics/get-top-pages, for PHP and the Abilities API - an MCP tool, such as
vireo-analytics-get-top-pages, for AI assistants - a REST route, such as
GET /wp-json/vireo-analytics/v1/stats/top-pages, for scripts
Every one is read-only and needs a user with the view_vireo_analytics capability. Pro’s also need an active Vireo Pro license.
Common inputs
| Input | Type | Notes |
|---|---|---|
start |
date, YYYY-MM-DD |
Defaults to 30 days before end. Required on the free REST routes. |
end |
date, YYYY-MM-DD |
Defaults to today. Required on the free REST routes. |
limit |
integer, 1 to 100 | Default shown per entry. No paging. |
Dates are in your site’s timezone and kept within the last two years. On the free REST routes a badly formatted date returns 400; elsewhere it falls back to the default.
Abilities, and so MCP tools, accept only the inputs listed for them. Any other key is refused with ability_invalid_input. The REST routes ignore query parameters they don’t use.
Shapes
Every ability returns a JSON object. When the data is a list, it sits under rows: {"rows": [...]}, or {"rows": []} when there’s nothing to report. The same object comes back from PHP, from the Abilities API’s /run route, from MCP, and from the REST routes, except the routes marked † below, which return a plain array.
Abilities
The free plugin’s abilities:
| Ability | REST route | Extra input | Returns |
|---|---|---|---|
get-totals |
/stats/totals |
pageviews, visitors, days, avg_daily, avg_time_on_page_seconds, timed_views, bounce_rate_percent |
|
get-daily-stats |
/stats/daily † |
rows, one per day: date, pageviews, visitors |
|
get-hourly-stats |
/stats/hourly |
rows, one per hour: date, hour, pageviews, visitors. At most the last two days of the range; defaults to today. |
|
get-changes |
/stats/changes |
limit (3) |
The range against the one before: pageviews, visitors, change_pct, prior, a summary sentence, headline, detail, mix, pages and sources that gained and lost, and health warnings |
get-highlights |
/stats/highlights |
limit (3) |
start, end and highlights: each a kind and a ready-to-quote text. Defaults to the last seven full days. |
get-top-pages |
/stats/top-pages † |
limit (10) |
rows: post_id, path, title, pageviews, visitors, avg_time_on_page_seconds |
get-top-referrers |
/stats/top-referrers † |
limit (10) |
rows: url (the referring host), pageviews, visitors |
get-traffic-sources |
/stats/channels |
rows, one per channel (direct, search, ai, social, referral): source, label, pageviews, visitors, share_pct |
|
get-referrer-detail |
/stats/referrer |
host (required), limit (10) |
host, label, source, period totals, daily series, and the pages it sent people to |
get-ai-referrals |
/stats/ai-referrals |
start, end, since (the first day crawlers were counted, when that’s later than start), referred_visitors, crawler_requests, crawler_requests_per_reader, and by_source per assistant |
|
get-search-console |
/stats/search-console |
limit (10), post_id or path |
connected; then site-wide summary (clicks, impressions, position, ctr) and top queries, or with post_id or path, that page’s queries |
get-countries |
/stats/countries † |
limit (20) |
rows: code, name, pageviews, visitors |
get-devices |
/stats/devices |
browsers, os and device_types, each rows of label, visitors, pct |
|
get-events |
/stats/events † |
name, limit (10) |
rows of top events: name, count, unique_count. With name, that event’s values. |
get-event-detail |
/stats/event/{name} |
name (required), limit (20) |
period totals, daily series, value_count and top values |
get-post-stats |
/stats/post/{id} |
post_id (required) |
post_id, title, url, lifetime, period, daily, referrers |
get-404s |
/stats/404s |
limit (20) |
rows (path, hits, top_referrer), broken_links (path, hits, linked_from, linking_pages) and probes |
get-bot-stats |
/stats/bots |
filtered_requests, counted_pageviews, share_of_all_requests_pct, ai_crawler_requests, and by_category (category, label, hits) |
|
get-vitals |
/stats/vitals |
rows, one per metric (lcp, inp, cls): metric, label, p75, display, rating, samples |
|
get-annotations |
/stats/annotations |
rows of chart notes: id, date, label |
|
get-year-review |
/stats/year-review |
year (current year) |
The Year in review for one calendar year. Takes no start or end. |
get-goals |
/stats/goals † |
Needs Pro. rows, one per goal: id, name, type, pattern, value, active, completions, unique_completions, total_value |
Ability names start with vireo-analytics/; the table leaves that out. /stats/goals/{id} returns one goal’s detail.
† Over REST, these routes return the list as a plain array instead of {"rows": [...]}. Everywhere else, and on every other route, the shape is as shown.
Paths, queries, referrers and event values come from visitors. Every ability strips control characters, line breaks and brackets from them before returning them.
Time on page and bounce rate, from Vireo Analytics 0.13.0:
| Field | Type | Meaning |
|---|---|---|
avg_time_on_page_seconds |
integer or null |
Average active seconds per timed view. On get-totals for the whole site, on each get-top-pages row for that page. null when no view in the range reported a time. |
timed_views |
integer | On get-totals: how many views the average covers. 0 when there are none. |
bounce_rate_percent |
number or null |
On get-totals: the share of visitors who viewed one page, to one decimal place. null when bounce counting covers no day in the range, or no visitors were counted. |
What’s counted has the exact definitions. Neither figure can be split by country, device or source.
Pro abilities
All need an active Vireo Pro license. On REST, start and end are optional here and default to the last 30 days.
| Ability | REST route | Extra input | Returns |
|---|---|---|---|
get-realtime |
/stats/realtime |
none, not even dates | active_last_5_minutes, window_minutes, the top pages, referrers and countries over the last 15 minutes with visitors and their change on the 15 before, and arrived_via by channel |
get-campaigns |
/stats/campaigns |
limit (20) |
campaigns: source, medium, campaign, visitors, pageviews |
get-site-searches |
/stats/site-searches |
limit (20) |
searches: query, searches, results |
get-outbound-clicks |
/stats/outbound |
limit (10) |
external_sites (host, clicks) and affiliate_links (path, clicks) |
get-downloads |
/stats/downloads |
limit (10) |
downloads: host, path, clicks |
get-engagement |
/stats/engagement |
limit (10) |
site and per-page pages: samples, avg_seconds, avg_scroll_pct. From Pro 1.4.2 with Vireo Analytics 0.13.0 or later, avg_seconds is the free plugin’s time on page, and null when there’s none for the range. |
get-entry-exit-pages |
/stats/entry-exit |
limit (10) |
entry_pages and exit_pages: path, entries, exits, exit_ratio |
get-page-paths |
/stats/page-paths |
path, limit (20) |
Without path, the top pairs (from, to, visits). With it, where people went next (to, visits, share_pct). |
get-authors |
/stats/authors |
limit (10) |
authors: author_id, name, posts_read, pageviews, visitors, avg_per_post |
get-post-types |
/stats/post-types |
post_types: each type with its number of posts read, pageviews, visitors and share |
|
get-taxonomy-terms |
/stats/taxonomy-terms |
taxonomy (category), limit (10) |
taxonomy, tracked_taxonomies, and terms: term_id, name, slug, pageviews, visitors, url |
get-page-vitals |
/stats/page-vitals |
metric (lcp, inp or cls; default lcp), limit (10) |
metric, unit, and the worst pages first: path, p75, samples, rating. Pages under 10 samples are left out. |
get-cities |
/stats/cities |
limit (10) |
database_ready, and cities: country, region and city with pageviews and visitors |
get-funnels |
/stats/funnels |
funnels: id, name, and steps (step, goal_id, goal, visitors, pct_from_previous, pct_from_first) |
Pro: connected sites
Added in Pro 1.2.0, for agencies reading several sites through one install. Site 0 is the install you’re calling; connected sites are numbered from 1.
| Ability | REST route | Extra input | Returns |
|---|---|---|---|
get-sites |
/stats/sites |
limit (100) |
count of connected sites, the plan’s limit, accepts_site (the tools that take site), and sites: id, name, url, this_site, last_data |
get-sites-overview |
/stats/sites-overview |
start, end, prior_start, prior_end, and sites, busiest first: the get-sites fields plus pageviews, visitors, prior_pageviews, prior_visitors, pageviews_change_pct, visitors_change_pct |
The site input
With Pro 1.2.0 active, these free abilities take an extra site input (integer, default 0) to read a connected site instead of this one: get-totals, get-daily-stats, get-hourly-stats, get-changes, get-highlights, get-top-pages, get-top-referrers, get-traffic-sources, get-referrer-detail, get-ai-referrals, get-countries, get-devices, get-events, get-event-detail, get-404s, get-bot-stats, get-vitals, get-annotations.
- It works through abilities, MCP and the Abilities API’s
/runroute. The free/stats/...REST routes don’t take it and answer for this install. - An id that matches no connected site returns
vireo_site_unknown(404 over REST). - Pro’s own abilities don’t take
site: a non-zerositereturnsvireo_site_unsupported(400). The free abilities not listed above refuse it as an unknown input (ability_invalid_input, 400). - Without an active Pro license, any non-zero
sitereturnsvireo_site_pro(403), and a user who can’t read that site’s numbers getsvireo_site_forbidden(403). - Answers for a connected site are flattened the same way as this site’s.
Pro: store abilities
Registered only while a supported store is active: WooCommerce, Easy Digital Downloads, FluentCart, Freemius, Paid Memberships Pro, Restrict Content, MemberPress, LifterLMS, GiveWP or SureCart. Each takes store (woo, edd, fluentcart, freemius, pmpro, rcp, memberpress, lifterlms, give or surecart) to limit it to one store; leave it out for all of them.
| Ability | REST route | Extra input | Returns |
|---|---|---|---|
get-revenue |
/stats/revenue (own shape, below) |
store |
Net revenue, orders, conversions, items, visitors, revenue_per_visitor, currency |
get-daily-revenue |
store |
days: date, revenue, orders |
|
get-revenue-forecast |
/stats/revenue-forecast |
store; takes no date range |
available, reason, history_days, min_history_days, store, currency. When available: month (start, end, so_far, days_left, expected, low, high), next_30 (start, end, expected, low, high), and the projected days and month_days (date, revenue). Under 28 days of orders, or no revenue in the last 8 weeks, gives available: false with a reason and message. |
get-revenue-by-source |
/stats/sources (own shape, below) |
store, limit (10) |
sources by source, medium and campaign, with orders and average order value |
get-revenue-by-landing-page |
/stats/landing-pages |
store, limit (10) |
pages: path, orders, revenue, aov, entries, conversion |
get-top-products |
/stats/products (own shape, below) |
store, limit (10) |
products: product_id, name, views, add_to_cart, purchases, revenue, conv_rate |
get-store-funnel |
/stats/store-funnel |
store |
stages from product view to purchase: stage, count, share of the stage before, and whether the store reports it |
get-subscriptions |
/stats/subscriptions |
store, limit (10) |
mrr, subscribers, currency, other_currencies, period (start_mrr, end_mrr, net, new, expansion, reactivation, contraction, churn, subscriber counts, active_at_start, active_at_end, logo_churn_rate), a 12-month trend, and MRR by_source and by_landing_page |
get-stores |
Which stores are connected and which have orders in the range (with_orders) |
/stats/revenue, /stats/products and /stats/sources came before the abilities and keep their own response shape. /stats/revenue returns range, store, totals, daily, revenue_per_visitor and currency; /stats/products and /stats/sources return their rows as a plain list. All three require start and end.
Three more reports are REST routes only, with no ability or MCP tool. They take start, end, limit and store like /stats/revenue, and return the summary fields with a list beside them:
| REST route | Returns |
|---|---|
/stats/abandonment |
abandoned, value, valued, checkouts, rate, carts, and sources: source, medium, campaign, abandoned, value |
/stats/coupons |
orders, with_coupon, discount, share, and coupons: code, orders, revenue, discount, aov |
/stats/refunds |
orders, full, partial, amount, placed, rate, and refunds: store, order_id, date, refunded_date, total, refunded, full, is_renewal, source, medium, campaign, url |
Each also returns currency. Revenue is net of refunds. Totals are in the store’s currency, without conversion.
REST routes
All are GET under /wp-json/vireo-analytics/v1, and authenticate as described in Pull your stats with the REST API. The route for each report is in the tables above.
One more route isn’t for reading data: with Pro and Freemius, POST /freemius/webhook receives Freemius’s payment events. See Revenue tracking.
Abilities API routes
| Route | Use |
|---|---|
GET /wp-json/wp-abilities/v1/abilities?category=vireo-analytics |
List Vireo’s abilities, with their input and output schemas |
GET /wp-json/wp-abilities/v1/abilities/{name}/run?input[key]=value |
Run one. The name keeps its slash, for example vireo-analytics/get-totals. |
MCP
/wp-json/vireo-analytics/mcp serves every ability above as a tool, named with a dash in place of the slash: vireo-analytics-get-top-pages. A developer can change the list with the vireo_mcp_tools filter.