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.

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):

{
    "status": "success",
    "data": { "nb_visits": 1234 }
}

Job still running or newly queued:

{
    "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.

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.