get-timeseries
Retrieve website traffic trends over time, broken down by day, week, or month. Ideal for trend analysis and building charts.
Instructions
Get traffic trends over time. Returns data points broken down by time interval (day, week, or month). Use this for trend analysis and charts.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| site_id | Yes | Domain of the site (e.g. 'example.com') | |
| metrics | No | Metrics to retrieve | |
| date_range | No | Time period. Use a preset like '30d' or a custom range ['2024-01-01', '2024-01-31'] | 30d |
| interval | No | Time granularity for the series | date |
| filters | No | Filters array using Plausible v2 syntax, e.g. [['is', 'event:page', ['/blog*']]] |
Implementation Reference
- src/index.ts:157-191 (handler)The handler function for the 'get-timeseries' tool. It accepts site_id, metrics, date_range, interval (day/week/month), and optional filters. It maps the interval to a dimension key (time:day, time:week, or time:month), queries the Plausible API via client.query(), then formats results as an array of {date, ...metrics} objects and returns JSON.
async ({ site_id, metrics, date_range, interval, filters }) => { const dimensionKey = interval === "date" ? "time:day" : interval === "week" ? "time:week" : "time:month"; const result = await client.query({ site_id, metrics, date_range, dimensions: [dimensionKey], filters: filters ?? undefined, }); // Format as an array of { date, ...metrics } const rows = result.results.map((r) => { const row: Record<string, unknown> = { date: r.dimensions[0] }; metrics.forEach((m, i) => { row[m] = r.metrics[i]; }); return row; }); return { content: [ { type: "text", text: JSON.stringify({ site_id, date_range, interval, data: rows }, null, 2), }, ], }; } ); - src/index.ts:147-156 (schema)Input schema for get-timeseries: site_id (string), metrics (array using metricsSchema), date_range (using dateRangeSchema), interval (enum: date|week|month, defaults to 'date'), and filters (using filtersSchema).
{ site_id: z.string().describe("Domain of the site (e.g. 'example.com')"), metrics: metricsSchema, date_range: dateRangeSchema, interval: z .enum(["date", "week", "month"]) .describe("Time granularity for the series") .default("date"), filters: filtersSchema, }, - src/index.ts:144-191 (registration)Registration of the 'get-timeseries' tool via server.tool(), with description 'Get traffic trends over time...' and the accompanying schema and handler.
server.tool( "get-timeseries", "Get traffic trends over time. Returns data points broken down by time interval (day, week, or month). Use this for trend analysis and charts.", { site_id: z.string().describe("Domain of the site (e.g. 'example.com')"), metrics: metricsSchema, date_range: dateRangeSchema, interval: z .enum(["date", "week", "month"]) .describe("Time granularity for the series") .default("date"), filters: filtersSchema, }, async ({ site_id, metrics, date_range, interval, filters }) => { const dimensionKey = interval === "date" ? "time:day" : interval === "week" ? "time:week" : "time:month"; const result = await client.query({ site_id, metrics, date_range, dimensions: [dimensionKey], filters: filters ?? undefined, }); // Format as an array of { date, ...metrics } const rows = result.results.map((r) => { const row: Record<string, unknown> = { date: r.dimensions[0] }; metrics.forEach((m, i) => { row[m] = r.metrics[i]; }); return row; }); return { content: [ { type: "text", text: JSON.stringify({ site_id, date_range, interval, data: rows }, null, 2), }, ], }; } ); - src/index.ts:63-99 (helper)Shared schema definitions used by get-timeseries: dateRangeSchema, metricsSchema (enumerating possible metrics like visitors, pageviews, bounce_rate, etc.), and filtersSchema.
// Shared schema fragments const dateRangeSchema = z .union([ z.enum(["day", "7d", "30d", "month", "6mo", "12mo", "year", "all"]), z.tuple([z.string(), z.string()]).describe("Custom range: [start, end] in YYYY-MM-DD format"), ]) .describe("Time period. Use a preset like '30d' or a custom range ['2024-01-01', '2024-01-31']") .default("30d"); const metricsSchema = z .array( z.enum([ "visitors", "visits", "pageviews", "views_per_visit", "bounce_rate", "visit_duration", "events", "scroll_depth", "percentage", "conversion_rate", "group_conversion_rate", "average_revenue", "total_revenue", "time_on_page", ]) ) .describe("Metrics to retrieve") .default(["visitors", "pageviews", "bounce_rate", "visit_duration"]); const filtersSchema = z .array(z.any()) .optional() .describe( "Filters array using Plausible v2 syntax, e.g. [['is', 'event:page', ['/blog*']]]" ); - src/plausible-client.ts:61-79 (helper)The PlausibleClient.query() method used by the get-timeseries handler to make the API call to /api/v2/query.
async query(params: PlausibleQueryParams): Promise<PlausibleQueryResult> { const response = await fetch(`${this.baseUrl}/api/v2/query`, { method: "POST", headers: { Authorization: `Bearer ${this.apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify(params), }); if (!response.ok) { const body = await response.text(); throw new Error( `Plausible API error (${response.status}): ${body}` ); } return response.json() as Promise<PlausibleQueryResult>; }