Matomo
Matomo is an open-source, privacy-focused web analytics
platform that works self-hosted or in Matomo Cloud. This destination forwards
walkerOS events to Matomo via the _paq command queue with support for page
views, custom events, goals, site search, content tracking, and custom
dimensions.
Matomo is a web destination in the walkerOS flow:
Installation
npm install @walkeros/web-destination-matomo- Integrated
- Bundled
import { startFlow } from '@walkeros/collector';
import { destinationMatomo } from '@walkeros/web-destination-matomo';
await startFlow({
destinations: {
matomo: {
code: destinationMatomo,
config: {
loadScript: true,
settings: {
siteId: '1',
url: 'https://analytics.example.com/',
},
},
},
},
});Add to your flow.json destinations:
"destinations": {
"matomo": {
"package": "@walkeros/web-destination-matomo",
"config": {
"loadScript": true,
"settings": {
"siteId": "1",
"url": "https://analytics.example.com/"
}
}
}
}Configuration
This destination uses the standard destination config wrapper (consent, data, env, id, ...). For the shared fields see destination configuration. Package-specific fields live under config.settings and are listed below.
Settings
| Property | Type | Description | More |
|---|---|---|---|
siteId | string | Matomo Site ID (like 1, 2, etc.). Required when loadScript is true | |
url | string | Base URL of your Matomo instance, normalized to one trailing slash (like https://analytics.example.com/ or https://yourname.matomo.cloud/). Required when loadScript is true | |
disableCookies | boolean | Disable all tracking cookies for cookie-free analytics | |
enableLinkTracking | boolean | Enable automatic outlink and download tracking | |
enableHeartBeatTimer | integer | Enable heart beat timer with interval in seconds for accurate time-on-page | |
customDimensions | Record<string, Mapping.Value> | Custom dimensions applied to every hit, keyed by bare dimension id (like { "1": "data.userType" }). Each value is resolved per event. Rule-level customDimensions win per key. |
Mapping
Per-event rules under config.mapping. For the standard rule fields (consent, condition, data, batch, name, policy) see mapping.
| Property | Type | Description | More |
|---|---|---|---|
goalId | string | integer | Matomo goal ID, a positive integer like 1. Adds a trackGoal conversion alongside this event | |
goalValue | Mapping.Value | ||
siteSearch | boolean | Track as internal site search using trackSiteSearch | |
contentImpression | boolean | Track as content impression using trackContentImpression | |
contentInteraction | boolean | Track as content interaction using trackContentInteraction | |
customDimensions | Record<string, Mapping.Value> | Custom dimensions for this rule, keyed by bare dimension id (like { "3": "data.category" }). Set just before the hit and removed after it; wins per key over the destination customDimensions. |
Examples
Custom event with goal
A promotion visible event fires Matomo trackEvent and then trackGoal to record a goal conversion.
{
"name": "promotion visible",
"data": {
"name": "Setting up tracking easily",
"position": "hero"
},
"context": {
"ab_test": [
"engagement",
0
]
},
"globals": {
"pagegroup": "homepage"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "86e04a285dda4f59",
"trigger": "visible",
"entity": "promotion",
"action": "visible",
"timestamp": 1700000401,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"name": "trackEvent",
"settings": {
"goalId": "1"
},
"data": {
"set": [
"data.name",
"data.position"
]
}
}_paq.push([
"trackEvent",
"Setting up tracking easily",
"hero"
]);
_paq.push([
"trackGoal",
"1",
null
])Goal with value
A promotion event fires Matomo trackEvent and then trackGoal with a monetary goal value from event data.
{
"name": "promotion visible",
"data": {
"name": "Setting up tracking easily",
"position": "hero",
"value": 50
},
"context": {
"ab_test": [
"engagement",
0
]
},
"globals": {
"pagegroup": "homepage"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "a0f1e8f0290fea7c",
"trigger": "visible",
"entity": "promotion",
"action": "visible",
"timestamp": 1700000406,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"name": "trackEvent",
"settings": {
"goalId": "1",
"goalValue": "data.value"
},
"data": {
"set": [
"data.name"
]
}
}_paq.push([
"trackEvent",
"Setting up tracking easily"
]);
_paq.push([
"trackGoal",
"1",
50
])Initialization
Destination bootstrap loads the Matomo tracker script and configures the tracker URL and site id.
{
"loadScript": true,
"settings": {
"siteId": "1",
"url": "https://analytics.example.com/"
}
}_paq.push([
"setTrackerUrl",
"https://analytics.example.com/matomo.php"
]);
_paq.push([
"setSiteId",
"1"
]);
_paq.push([
"enableLinkTracking"
])Page view
A page view is tracked in Matomo via trackPageView with the page title from event data.
{
"name": "page view",
"data": {
"domain": "www.example.com",
"title": "walkerOS documentation",
"referrer": "https://www.walkeros.io/",
"search": "?foo=bar",
"hash": "#hash",
"id": "/docs/"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"pagegroup": "docs"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "1cf657161fb5c569",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000400,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"data": "data.title"
}_paq.push([
"trackPageView",
"walkerOS documentation"
])Page view with goal
A page view rule with a goal keeps the default trackPageView and adds a trackGoal conversion.
{
"name": "page view",
"data": {
"domain": "www.example.com",
"title": "walkerOS documentation",
"referrer": "https://www.walkeros.io/",
"search": "?foo=bar",
"hash": "#hash",
"id": "/docs/"
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"pagegroup": "docs"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "47a96d6b69253a69",
"trigger": "load",
"entity": "page",
"action": "view",
"timestamp": 1700000407,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"settings": {
"goalId": "1"
}
}_paq.push([
"trackPageView",
"walkerOS documentation"
]);
_paq.push([
"trackGoal",
"1",
null
])Site search
A search submit fires Matomo trackSiteSearch with the keyword, category, and number of results.
{
"name": "search submit",
"data": {
"query": "shoes",
"category": "products",
"resultsCount": 42
},
"context": {
"dev": [
"test",
1
]
},
"globals": {
"lang": "elb"
},
"custom": {
"completely": "random"
},
"user": {
"id": "us3r",
"device": "c00k13",
"session": "s3ss10n"
},
"nested": [
{
"entity": "child",
"data": {
"is": "subordinated"
}
}
],
"consent": {
"functional": true
},
"id": "a2f00717ec42f456",
"trigger": "test",
"entity": "search",
"action": "submit",
"timestamp": 1700000405,
"timing": 3.14,
"source": {
"count": 1,
"trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
"type": "collector",
"schema": "4"
}
}{
"name": "trackSiteSearch",
"settings": {
"siteSearch": true
},
"data": {
"set": [
"data.query",
"data.category",
"data.resultsCount"
]
}
}_paq.push([
"trackSiteSearch",
"shoes",
"products",
42
])Unmapped events
An event without rule.name that is not a page view and sets no tracking flag
(siteSearch, contentImpression or contentInteraction) sends only its goal
when the rule has settings.goalId, so a goal-only rule needs no name. Without
a goal, such an event is skipped: the destination logs a warning once per event
name, then repeats at debug level.
A goalId must be a Matomo goal ID, a positive integer like 1 or "1". The
destination skips any other goal with a warning and still sends the event's own
hit, if it has one.
Ecommerce
Matomo needs an addEcommerceItem call for each product before a cart update,
and before an order to record the order's products. A product view is
setEcommerceView followed by trackPageView. A rule sends one command per
event, so the destination cannot send these sequences.
Custom dimensions
Custom dimensions are keyed by bare dimension id, like
{ "1": "data.category" }. Each value is a mapping value, resolved for every
event.
settings.customDimensionsapplies to every hit.- A rule's
settings.customDimensionsapplies to that rule's hits and wins per key. A rule dimension that resolves to nothing removes that dimension for the hit, even when the destination sets it.
The dimensions are set with setCustomDimension right before the event's
hits, a goal included. After them, rule-only dimensions are deleted with
deleteCustomDimension and the destination values are set again, so a rule
value never leaks into later requests such as outlinks or the heart beat. With
destination dimension 1 set to globals.pagegroup and a page view rule
dimension 2 set to data.id, a page view pushes:
_paq.push(['setCustomDimension', 1, 'docs']);
_paq.push(['setCustomDimension', 2, '/docs/']);
_paq.push(['trackPageView', 'walkerOS documentation']);
_paq.push(['deleteCustomDimension', 2]);
_paq.push(['setCustomDimension', 1, 'docs']);