# Matomo Stats The Matomo stats feature proxies requests to a configured Matomo Analytics instance so the frontend can display page statistics without exposing the Matomo API key. Requests are processed asynchronously through a Redis-backed job queue and results are cached for 24 hours, keeping the editing interface responsive even for slow analytics queries. ## Overview A `GET` on the `@matomo-stats` endpoint takes the Matomo query parameters, computes a deterministic job ID from them, and: 1. returns the cached result immediately if one exists, 2. returns the result of an already-finished job for the same query, 3. reports the status of a still-running job, or 4. enqueues a new background job and reports it as pending. The background worker calls the Matomo API with the configured endpoint and API key, then caches the result in Redis for 24 hours. Identical queries share the same job, so concurrent requests never duplicate work. ## REST API ### GET @matomo-stats The query parameters of the request are forwarded to Matomo (the API key is added server-side; never send it from the client). The response shape depends on whether a result is already available. ```http GET /Plone/@matomo-stats?module=API&method=VisitsSummary.get&period=range&date=last12&format=JSON HTTP/1.1 Host: localhost:8080 Accept: application/json ``` **Result available (cached or finished job):** ```json { "status": "success", "data": { "nb_visits": 1234 } } ``` **Job still running or newly queued:** ```json { "status": "pending", "job_id": "5f3a...", "job_status": "queued" } ``` When pending, poll the same endpoint with the same parameters until `status` becomes `success` (or `error`). Because the job ID is derived from the query parameters, polling does not create new jobs. ```javascript async function fetchMatomoStats(params) { const query = new URLSearchParams(params).toString(); while (true) { const response = await fetch(`/Plone/@matomo-stats?${query}`, { headers: { 'Accept': 'application/json' } }); const data = await response.json(); if (data.status !== 'pending') { return data; } await new Promise(resolve => setTimeout(resolve, 1500)); } } const stats = await fetchMatomoStats({ module: 'API', method: 'VisitsSummary.get', period: 'range', date: 'last12', format: 'JSON' }); console.log(stats.data.nb_visits); ``` If Matomo is not configured (missing endpoint or API key), the endpoint responds with HTTP 503 and `{"status": "error", "error": "Matomo not configured"}`. On a worker-side failure the cached result carries `status: "error"` and an `error` message describing the HTTP status, a timeout, or the exception. ## Configuration Matomo integration is configured through registry records: `wcs.backend.stats.matomo.endpoint` The Matomo API endpoint URL. `wcs.backend.stats.matomo.apikey` The Matomo API authentication token. Added to outgoing requests server-side and never exposed to clients. `wcs.backend.stats.matomo.site_id` The Matomo site ID for this site. `wcs.backend.stats.matomo.site_base_url` The public base URL of the site (for example `https://www.webcloud7.ch`), used to build per-page query URLs. `wcs.backend.stats.matomo.queries` A JSON array of query presets, each with an `id`, a `label_key`, a `query` object (the Matomo API parameters) and a `result_field` (or `result_type`). These presets drive the statistics panel shown to editors. The default configuration provides a 12-month visitor count and a feedback-events query. All four endpoint, key, site ID and base URL records must be set for the integration to be active.