Skip to main content

Download an Analytics Dashboard panel as CSV or the screen as PDF, and read its Your Data sheets

Premium Intermediate

Every Analytics Dashboard panel downloads as a CSV through one route, built from the same data the panel’s own route answers, so each panel’s filter (benecaster_analytics_growth_series and the rest) shapes the file too. panel is one of growth, donations, tier-breakdown, revenue, tier-movement, feed-engagement, downloads, cohort, migration-funnel, winback or winback-trend. The other arguments are that panel’s own: date_from / date_to (required except for feed-engagement, migration-funnel and winback, which are as of now), scope, tier_slug (applied to growth, revenue, feed-engagement, winback and winback-trend, ignored elsewhere, as on the screen), interval, days and app. It has the same permission, 403 and 400 as the other Analytics Dashboard routes.

  • The answer is the file: text/csv, UTF-8 with a byte-order mark, CRLF lines, a header row of translated labels. A refusal is JSON, sent before any byte of the file.
  • Money cells are major units with the currency’s own decimals (1500 yen, 2.500 dinars), a point and no grouping, beside a currency column; currencies are never added together.
  • A text cell beginning =, +, -, @, a tab or a carriage return is prefixed with ' against formula injection. Numbers are never escaped.
  • winback names people (name, email): it is the file an administrator asked for, so keep it on the administrator’s machine.
  • The filename is {show}-{panel}-{from}-to-{to}.csv, all-my-shows under scope=all. A panel that is as of now uses {today} instead of the dates, and the win-back list uses last-{n}-days-{today}.

The PDF snapshot. GET benecaster-analytics/v1/analytics/export/pdf takes the shared filters (show_id, date_from, date_to, scope, tier_slug) and answers the whole screen as application/pdf, named {show}-analytics-{from}-to-{to}.pdf. It has the same 403 and 400, and answers 501 benecaster_analytics_pdf_unavailable on a server without PHP’s dom or mbstring. Each section reads its panel’s route data, so those routes’ filters shape it. There is no hook of its own. It is made with Dompdf, which the add-on ships renamed into BenecasterAnalyticsDashboard\Vendor\. Do not reach for those classes: they are the add-on’s own copy, and may change with any release.

Your Data sheets. Through core’s benecaster_export_sheets, badge analytics-dashboard, the add-on registers five sheets. Each sheet’s first column is show, followed by the panel’s columns:

Sheet id Holds Offered
analytics_subscriber_growth the growth table per UTC day always
analytics_tier_movement moves per tier pair, as counts always
analytics_episode_downloads show, episode, day, downloads for each show’s top 100 episodes only when a show in scope tracks downloads
analytics_feed_engagement the bands as of now always
analytics_cohort_retention the matrix laid flat only with at least 60 days of history
  • Shows. A show_id of null covers every published, non-archived show where Analytics Dashboard is active. A named show is read only if it is active there.
  • Dates. Core’s dates are read as UTC days. An empty start is the shows’ first day on record, and the range is capped at 3,660 days.
  • Adding columns. To add a column, filter benecaster_export_sheets after priority 10 and the rows filter benecaster_export_sheet_rows_{id} after priority 10, appending to both in the same order.

Code

const url = window.benecasterAnalyticsDashboard.apiUrl + 'analytics/export?panel=revenue&show_id=12&date_from=2026-08-01&date_to=2026-10-31';
const response = await fetch( url, { headers: { 'X-WP-Nonce': window.benecasterAdmin.nonce } } );
if ( ! response.ok ) {
    const error = await response.json(); // { code: 'benecaster_analytics_not_active', message, data: { status: 403 } }
}
const filename = /filename="([^"]+)"/.exec( response.headers.get( 'Content-Disposition' ) )[ 1 ]; // e.g. the-daily-dig-revenue-2026-08-01-to-2026-10-31.csv
const csv = await response.text(); // starts with a UTF-8 byte-order mark

View on GitHub →

Need this built rather than just documented? See our services →