> Part of the walkerOS documentation. Project overview and full index: <https://www.walkeros.io/llms.txt>

# Matomo

[Web](#)[ Source code](https://github.com/elbwalker/walkerOS/tree/main/packages/web/destinations/matomo)[ Package](https://www.npmjs.com/package/@walkeros/web-destination-matomo) Beta

[Matomo](https://matomo.org/) 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.

Where this fits

Matomo is a **web destination** in the walkerOS flow:

## Installation[​](#installation "Direct link to Installation")

```bash
npm install @walkeros/web-destination-matomo
```

* Integrated
* Bundled

```typescript
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:

```json
"destinations": {
  "matomo": {
    "package": "@walkeros/web-destination-matomo",
    "config": {
      "loadScript": true,
      "settings": {
        "siteId": "1",
        "url": "https://analytics.example.com/"
      }
    }
  }
}
```

[See bundled mode setup](/preview/pr-749/docs/getting-started/modes/bundled.md) | [CLI reference](/preview/pr-749/docs/apps/cli.md)

## Configuration[​](#configuration "Direct link to Configuration")

This destination uses the standard destination config wrapper (consent, data, env, id, ...). For the shared fields see [destination configuration](/docs/destinations#configuration). Package-specific fields live under `config.settings` and are listed below.

## Settings[​](#settings "Direct link to 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[​](#mapping "Direct link to Mapping")

Per-event rules under `config.mapping`. For the standard rule fields (consent, condition, data, batch, name, policy) see [mapping](/docs/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.

Event

```json
{
  "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"
  }
}
```

Mapping

```json
{
  "name": "trackEvent",
  "settings": {
    "goalId": "1"
  },
  "data": {
    "set": [
      "data.name",
      "data.position"
    ]
  }
}
```

Out

```javascript
_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.

Event

```json
{
  "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"
  }
}
```

Mapping

```json
{
  "name": "trackEvent",
  "settings": {
    "goalId": "1",
    "goalValue": "data.value"
  },
  "data": {
    "set": [
      "data.name"
    ]
  }
}
```

Out

```javascript
_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.

Event

```json
{
  "loadScript": true,
  "settings": {
    "siteId": "1",
    "url": "https://analytics.example.com/"
  }
}
```

Out

```javascript
_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.

Event

```json
{
  "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"
  }
}
```

Mapping

```json
{
  "data": "data.title"
}
```

Out

```javascript
_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.

Event

```json
{
  "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"
  }
}
```

Mapping

```json
{
  "settings": {
    "goalId": "1"
  }
}
```

Out

```javascript
_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.

Event

```json
{
  "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"
  }
}
```

Mapping

```json
{
  "name": "trackSiteSearch",
  "settings": {
    "siteSearch": true
  },
  "data": {
    "set": [
      "data.query",
      "data.category",
      "data.resultsCount"
    ]
  }
}
```

Out

```javascript
_paq.push([
  "trackSiteSearch",
  "shoes",
  "products",
  42
])
```

## Unmapped events[​](#unmapped-events "Direct link to 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[​](#ecommerce "Direct link to 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 "Direct link to 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.customDimensions` applies to every hit.
* A rule's `settings.customDimensions` applies 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:

```javascript
_paq.push(['setCustomDimension', 1, 'docs']);
_paq.push(['setCustomDimension', 2, '/docs/']);
_paq.push(['trackPageView', 'walkerOS documentation']);
_paq.push(['deleteCustomDimension', 2]);
_paq.push(['setCustomDimension', 1, 'docs']);
```
