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

# Piwik PRO

[Server](#)[ Source code](https://github.com/elbwalker/walkerOS/tree/main/packages/server/destinations/piwikpro)[ Package](https://www.npmjs.com/package/@walkeros/server-destination-piwikpro)

Server-side event delivery to the [Piwik PRO](https://piwik.pro/) Tracking API. The destination uses the mapping of the [Piwik PRO web destination](https://www.walkeros.io/docs/destinations/web/piwikpro.md): `rule.name` is a Piwik PRO JavaScript method such as `trackEvent` or `ecommerceOrder`, and `data` resolves to its arguments. A web mapping that uses the 13 [portable methods](#copy-your-web-mapping) produces the same hits on the server. Browser-only commands, such as state setters like `setUserId`, are skipped. Each push, or each flushed batch, becomes one bulk request to your account. There is no API token to manage: the destination needs only your account URL and site id.

Where this fits

Piwik PRO is a **server destination** in the walkerOS flow:

Builds Tracking API hits from your mapping and sends them in one bulk POST request, with the visitor's IP address, user agent and language taken from the incoming request.

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

```bash
npm install @walkeros/server-destination-piwikpro
```

* Integrated
* Bundled

```typescript
import { startFlow } from '@walkeros/collector';
import { destinationPiwikPro } from '@walkeros/server-destination-piwikpro';

await startFlow({
  destinations: {
    piwikpro: {
      code: destinationPiwikPro,
      config: {
        settings: {
          url: 'https://your_account_name.piwik.pro/',
          appId: 'XXX-XXX-XXX-XXX-XXX',
        },
        batch: { size: 100, wait: 1000 },
      },
    },
  },
});
```

Add to your `flow.json` destinations:

```json
"destinations": {
  "piwikpro": {
    "package": "@walkeros/server-destination-piwikpro",
    "import": "destinationPiwikPro",
    "config": {
      "settings": {
        "url": "https://your_account_name.piwik.pro/",
        "appId": "XXX-XXX-XXX-XXX-XXX"
      },
      "batch": { "size": 100, "wait": 1000 }
    }
  }
}
```

[See bundled mode setup](https://www.walkeros.io/docs/getting-started/modes/bundled.md) | [CLI reference](https://www.walkeros.io/docs/apps/cli.md)

Before the first event, fill the request context in your server source, as shown in the [ingest prerequisite](#ingest-prerequisite).

## 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](https://www.walkeros.io/docs/destinations.md#configuration). Package-specific fields live under `config.settings` and are listed below.

## Settings[​](#settings "Direct link to Settings")

| Property           | Type                            | Description                                                                                                                                                                                                                                                                                                                              | More |
| ------------------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| `url*`             | `string`                        | Piwik PRO account URL, normalized to one trailing slash. Hits go to \<url>ppms.php                                                                                                                                                                                                                                                       |      |
| `appId*`           | `string`                        | Piwik PRO site or app id, sent as idsite                                                                                                                                                                                                                                                                                                 |      |
| `timeout`          | `integer`                       | Request timeout in milliseconds. Default: 5000                                                                                                                                                                                                                                                                                           |      |
| `identified`       | `boolean \| object`             | Identified or anonymous tracking. true (default) identifies every hit, false makes every hit anonymous (uia=1, dda=1, no \_id, no uid). A consent object like { marketing: true } identifies a hit when any listed state is granted. Do not repeat these states in config.consent, or events are queued and never reach the destination. |      |
| `customDimensions` | `Record<string, Mapping.Value>` | Custom dimensions sent as dimension{id} on every hit, keyed by bare dimension id. Values are mapping values resolved against the event (like { "1": "data.size" }). Rule-level customDimensions win per key.                                                                                                                             |      |
| `ip`               | `any \| boolean`                | Visitor IP, sent as cip. Resolves against { ingest, event }. Default: \["ingest.ip", "event.user.ip"]. false switches it off. Kept on anonymous hits for country-level geolocation.                                                                                                                                                      |      |
| `userAgent`        | `any \| boolean`                | User agent, sent as ua. Resolves against { ingest, event }. Default: \["ingest.userAgent", "event.user.userAgent"]. false switches it off.                                                                                                                                                                                               |      |
| `language`         | `any \| boolean`                | Accept-Language value, sent as lang. Resolves against { ingest, event }. Default: \["ingest.language", "event.user.language"]. false switches it off.                                                                                                                                                                                    |      |
| `pageUrl`          | `any \| boolean`                | Page URL, sent as url (required by the Tracking API, a hit without it is skipped). Resolves against { ingest, event }. Default: "event.source.url". false switches it off.                                                                                                                                                               |      |
| `referrer`         | `any \| boolean`                | Referrer URL, sent as urlref. Resolves against { ingest, event }. Default: "event.source.referrer". false switches it off.                                                                                                                                                                                                               |      |
| `visitorId`        | `any \| boolean`                | Visitor id, sent as \_id on identified hits. A 16-character hex value passes through, anything else is hashed to 16 hex (sha256). Resolves against { ingest, event }. Default: "event.user.device". false switches it off.                                                                                                               |      |
| `userId`           | `any \| boolean`                | User id, sent as uid on identified hits. Resolves against { ingest, event }. Default: "event.user.id". false switches it off.                                                                                                                                                                                                            |      |
| `pageViewId`       | `any \| boolean`                | Page view id, sent as pv\_id (first 6 hex characters, else a 6-character hash). Resolves against { ingest, event }. Default: "event.source.trace", only for web events whose trace differs from the server collector trace. false switches it off.                                                                                       |      |
| `timestamp`        | `any \| boolean`                | Event time in milliseconds, sent as cdt in UNIX seconds. Resolves against { ingest, event }. Default: "event.timestamp". false lets Piwik PRO use the receive time.                                                                                                                                                                      |      |

\* Required fields

## 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](https://www.walkeros.io/docs/mapping.md).

| Property           | Type                            | Description                                                                                                                                                                                        | More |
| ------------------ | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| `goalId`           | `string \| number`              | Piwik PRO goal id (UUID or legacy integer). Adds a second hit, trackGoal, to the same request.                                                                                                     |      |
| `goalValue`        | `Mapping.Value`                 |                                                                                                                                                                                                    |      |
| `customDimensions` | `Record<string, Mapping.Value>` | Custom dimensions for this rule, keyed by bare dimension id. Values are mapping values resolved against the event (like { "1": "data.size" }). Wins per key over the destination customDimensions. |      |

## Examples

### Custom event

A promotion visible event maps to trackEvent with category, action and name as positional arguments.

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": "d7b52232325ec740",
  "trigger": "visible",
  "entity": "promotion",
  "action": "visible",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "trackEvent",
  "data": {
    "set": [
      {
        "value": "promotion"
      },
      {
        "value": "visible"
      },
      "data.name"
    ]
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&e_c=promotion&e_a=visible&e_n=Setting+up+tracking+easily&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Add to cart

A product add maps to ecommerceAddToCart with the added product.

Event

```json
{
  "name": "product add",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "context": {
    "shopping": [
      "intent",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "e145323e448c0a2d",
  "trigger": "click",
  "entity": "product",
  "action": "add",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "ecommerceAddToCart",
  "data": {
    "set": [
      {
        "set": [
          {
            "map": {
              "sku": "data.id",
              "name": "data.name",
              "price": "data.price",
              "quantity": {
                "value": 1
              },
              "variant": {
                "key": "data.color"
              },
              "customDimensions": {
                "map": {
                  "1": "data.size"
                }
              }
            }
          }
        ]
      }
    ]
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&e_t=add-to-cart&ec_products=%5B%5B%22ers%22%2C%22Everyday+Ruck+Snack%22%2Cnull%2C420%2C1%2Cnull%2C%22black%22%2C%7B%221%22%3A%22l%22%7D%5D%5D&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Cart update

A cart view maps to ecommerceCartUpdate with the cart products and the cart total as revenue.

Event

```json
{
  "name": "cart view",
  "data": {
    "currency": "EUR",
    "value": 840
  },
  "context": {
    "shopping": [
      "cart",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420,
        "quantity": 2
      },
      "context": {
        "shopping": [
          "cart",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "565b357e6b3a10dd",
  "trigger": "load",
  "entity": "cart",
  "action": "view",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "ecommerceCartUpdate",
  "data": {
    "set": [
      {
        "loop": [
          "nested",
          {
            "condition": {
              "$code": "e=>y(e)&&\"product\"===e.entity"
            },
            "map": {
              "sku": "data.id",
              "name": "data.name",
              "price": "data.price",
              "quantity": {
                "value": 1
              },
              "variant": {
                "key": "data.color"
              },
              "customDimensions": {
                "map": {
                  "1": "data.size"
                }
              }
            }
          }
        ]
      },
      "data.value"
    ]
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&e_t=cart-update&ec_products=%5B%5B%22ers%22%2C%22Everyday+Ruck+Snack%22%2Cnull%2C420%2C1%2Cnull%2C%22black%22%2C%7B%221%22%3A%22l%22%7D%5D%5D&revenue=840&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Ecommerce order

A completed order maps to ecommerceOrder with its products, order id, total, tax and shipping.

Event

```json
{
  "name": "order complete",
  "data": {
    "id": "0rd3r1d",
    "currency": "EUR",
    "shipping": 5.22,
    "taxes": 73.76,
    "total": 555
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "a8e6f6e6c9161050",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "ecommerceOrder",
  "data": {
    "set": [
      {
        "loop": [
          "nested",
          {
            "condition": {
              "$code": "e=>y(e)&&\"product\"===e.entity"
            },
            "map": {
              "sku": "data.id",
              "name": "data.name",
              "price": "data.price",
              "quantity": {
                "value": 1
              },
              "variant": {
                "key": "data.color"
              },
              "customDimensions": {
                "map": {
                  "1": "data.size"
                }
              }
            }
          }
        ]
      },
      {
        "map": {
          "orderId": "data.id",
          "grandTotal": "data.total",
          "tax": "data.taxes",
          "shipping": "data.shipping"
        }
      }
    ]
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&e_t=order&ec_id=0rd3r1d&revenue=555&ec_tx=73.76&ec_sh=5.22&ec_products=%5B%5B%22ers%22%2C%22Everyday+Ruck+Snack%22%2Cnull%2C420%2C1%2Cnull%2C%22black%22%2C%7B%221%22%3A%22l%22%7D%5D%2C%5B%22cc%22%2C%22Cool+Cap%22%2Cnull%2C42%2C1%2Cnull%2Cnull%2C%7B%221%22%3A%22one+size%22%7D%5D%5D&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Product detail view

A product view maps to ecommerceProductDetailView with the product as a single-item array.

Event

```json
{
  "name": "product view",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "context": {
    "shopping": [
      "detail",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [],
  "consent": {
    "functional": true
  },
  "id": "fdce8153957a6ee4",
  "trigger": "load",
  "entity": "product",
  "action": "view",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "ecommerceProductDetailView",
  "data": {
    "set": [
      {
        "set": [
          {
            "map": {
              "sku": "data.id",
              "name": "data.name",
              "price": "data.price",
              "quantity": {
                "value": 1
              },
              "variant": {
                "key": "data.color"
              },
              "customDimensions": {
                "map": {
                  "1": "data.size"
                }
              }
            }
          }
        ]
      }
    ]
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&e_t=product-detail-view&ec_products=%5B%5B%22ers%22%2C%22Everyday+Ruck+Snack%22%2Cnull%2C420%2C1%2Cnull%2C%22black%22%2C%7B%221%22%3A%22l%22%7D%5D%5D&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Remove from cart

A product remove maps to ecommerceRemoveFromCart with the removed product.

Event

```json
{
  "name": "product remove",
  "data": {
    "id": "ers",
    "name": "Everyday Ruck Snack",
    "color": "black",
    "size": "l",
    "price": 420
  },
  "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": "fa6c5bd0240f6589",
  "trigger": "test",
  "entity": "product",
  "action": "remove",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "ecommerceRemoveFromCart",
  "data": {
    "set": [
      {
        "set": [
          {
            "map": {
              "sku": "data.id",
              "name": "data.name",
              "price": "data.price",
              "quantity": {
                "value": 1
              },
              "variant": {
                "key": "data.color"
              },
              "customDimensions": {
                "map": {
                  "1": "data.size"
                }
              }
            }
          }
        ]
      }
    ]
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&e_t=remove-from-cart&ec_products=%5B%5B%22ers%22%2C%22Everyday+Ruck+Snack%22%2Cnull%2C420%2C1%2Cnull%2C%22black%22%2C%7B%221%22%3A%22l%22%7D%5D%5D&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Event with goal value

An order event tracks a custom event and a goal conversion whose revenue resolves from the order total.

Event

```json
{
  "name": "order complete",
  "data": {
    "id": "0rd3r1d",
    "currency": "EUR",
    "shipping": 5.22,
    "taxes": 73.76,
    "total": 555
  },
  "context": {
    "shopping": [
      "complete",
      0
    ]
  },
  "globals": {
    "pagegroup": "shop"
  },
  "custom": {
    "completely": "random"
  },
  "user": {
    "id": "us3r",
    "device": "c00k13",
    "session": "s3ss10n"
  },
  "nested": [
    {
      "entity": "product",
      "data": {
        "id": "ers",
        "name": "Everyday Ruck Snack",
        "color": "black",
        "size": "l",
        "price": 420
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "product",
      "data": {
        "id": "cc",
        "name": "Cool Cap",
        "size": "one size",
        "price": 42
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    },
    {
      "entity": "gift",
      "data": {
        "name": "Surprise"
      },
      "context": {
        "shopping": [
          "complete",
          0
        ]
      },
      "nested": []
    }
  ],
  "consent": {
    "functional": true
  },
  "id": "f22a6ae7ab800806",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "trackEvent",
  "settings": {
    "goalId": "6a0f4c1e-3b2d-4e8f-a7c9-1d2e3f4a5b6c",
    "goalValue": "data.total"
  },
  "data": {
    "set": [
      {
        "value": "order"
      },
      {
        "value": "complete"
      },
      "data.id",
      "data.total"
    ]
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&e_c=order&e_a=complete&e_n=0rd3r1d&e_v=555&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\",\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&idgoal=6a0f4c1e-3b2d-4e8f-a7c9-1d2e3f4a5b6c&revenue=555&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Page view

A page view becomes a trackPageView hit with the page title as action\_name and the page context.

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": "4d5175dfbfa0bfaf",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

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

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&action_name=walkerOS+documentation&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Page view with goal

A page view rule with a goalId still tracks the page view and adds a trackGoal hit to the same request.

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": "7d738346b3833a94",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "settings": {
    "goalId": "6a0f4c1e-3b2d-4e8f-a7c9-1d2e3f4a5b6c"
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&action_name=walkerOS+documentation&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\",\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&idgoal=6a0f4c1e-3b2d-4e8f-a7c9-1d2e3f4a5b6c&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Ping

A heartbeat event maps to ping, which extends the session without counting as a page view.

Event

```json
{
  "name": "page ping",
  "data": {
    "string": "foo",
    "number": 1,
    "boolean": true,
    "array": [
      0,
      "text",
      false
    ]
  },
  "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": "14fd7fac4e4c11fc",
  "trigger": "test",
  "entity": "page",
  "action": "ping",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "ping"
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&ping=6&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Site search

A search event maps to trackSiteSearch with keyword, category and result count.

Event

```json
{
  "name": "search submit",
  "data": {
    "query": "rucksack",
    "category": "bags",
    "results": 12
  },
  "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": "46e19a9409b84cfc",
  "trigger": "test",
  "entity": "search",
  "action": "submit",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "trackSiteSearch",
  "data": {
    "set": [
      "data.query",
      "data.category",
      "data.results"
    ]
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&search=rucksack&search_cats=%5B%22bags%22%5D&search_count=12&url=https%3A%2F%2Fwww.example.com%2F&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

### Download link

A tagged download maps to trackLink, which sends the file address as download and as the hit url.

Event

```json
{
  "name": "file download",
  "data": {
    "url": "https://www.example.com/whitepaper.pdf"
  },
  "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": "88794cf4c50df54b",
  "trigger": "test",
  "entity": "file",
  "action": "download",
  "timestamp": 1700000300000,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "browser",
    "platform": "web",
    "url": "https://www.example.com/",
    "referrer": "https://www.walkeros.io/"
  }
}
```

Mapping

```json
{
  "name": "trackLink",
  "data": {
    "set": [
      "data.url",
      {
        "value": "download"
      }
    ]
  }
}
```

Out

```javascript
sendServer("https://your_account_name.piwik.pro/ppms.php", "{\"requests\":[\"?idsite=e8f3a1c2-0b4d-4e5f-9a6b-7c8d9e0f1a2b&rec=1&send_image=0&ts_n=walkerOS&ts_v=4.7.2&download=https%3A%2F%2Fwww.example.com%2Fwhitepaper.pdf&url=https%3A%2F%2Fwww.example.com%2Fwhitepaper.pdf&urlref=https%3A%2F%2Fwww.walkeros.io%2F&_id=cc8e27118413234d&uid=us3r&pv_id=0a1b2c&cdt=1700000300\"]}", {
  "timeout": 5000
})
```

## Ingest prerequisite[​](#ingest-prerequisite "Direct link to Ingest prerequisite")

In the browser, the Piwik PRO tracker sends the visitor's IP address, user agent and language with every hit. On the server these values come from the incoming request. The `ip`, `userAgent` and `language` settings read `ingest.ip`, `ingest.userAgent` and `ingest.language` first, then fall back to `event.user`. Fill `ingest` with the `map` operator in the server source's `config.ingest`:

```json
"sources": {
  "express": {
    "package": "@walkeros/server-source-express",
    "config": {
      "settings": { "port": 8080 },
      "ingest": {
        "map": {
          "ip": { "key": "ip" },
          "userAgent": { "key": "headers.user-agent" },
          "language": { "key": "headers.accept-language" }
        }
      }
    }
  }
}
```

Without it, Piwik PRO receives no client IP, user agent or language, and locates every visitor at your server. Behind a load balancer or a CDN, `ip` is the address of the last proxy; see [client IP behind a proxy](https://www.walkeros.io/docs/sources/server/express.md#client-ip-behind-a-proxy) for the header to map instead. The other server sources take the same map, see the [request scope](https://www.walkeros.io/docs/sources/scope.md).

## What each setting sends[​](#what-each-setting-sends "Direct link to What each setting sends")

| Setting            | Default                                        | Sends                                                                                                                                                                |
| ------------------ | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`              | required                                       | Your account URL. Hits go to `<url>ppms.php`. The URL is normalized to one trailing slash.                                                                           |
| `appId`            | required                                       | The site or app id, as `idsite`.                                                                                                                                     |
| `timeout`          | `5000`                                         | Not sent. The request timeout in milliseconds.                                                                                                                       |
| `identified`       | `true`                                         | Identified or anonymous hits, see [identified and anonymous](#identified-and-anonymous).                                                                             |
| `customDimensions` | none                                           | `dimension{id}` on every hit, see [custom dimensions](#custom-dimensions).                                                                                           |
| `ip`               | `["ingest.ip", "event.user.ip"]`               | `cip`, the visitor's IP address. Kept on anonymous hits, for country-level location.                                                                                 |
| `userAgent`        | `["ingest.userAgent", "event.user.userAgent"]` | `ua`                                                                                                                                                                 |
| `language`         | `["ingest.language", "event.user.language"]`   | `lang`                                                                                                                                                               |
| `pageUrl`          | `"event.source.url"`                           | `url`. The Tracking API requires it, so an event without a page URL is skipped.                                                                                      |
| `referrer`         | `"event.source.referrer"`                      | `urlref`                                                                                                                                                             |
| `visitorId`        | `"event.user.device"`                          | `_id` on identified hits. A 16 character lowercase hex value passes through. Anything else is hashed to 16 hex characters, so walkerOS device ids are always hashed. |
| `userId`           | `"event.user.id"`                              | `uid` on identified hits.                                                                                                                                            |
| `pageViewId`       | the page trace of web events                   | `pv_id`, as 6 hex characters. See [server-side vs browser](#server-side-vs-browser).                                                                                 |
| `timestamp`        | `"event.timestamp"`                            | `cdt`, the event time in UNIX seconds.                                                                                                                               |

The last nine settings are [mapping values](https://www.walkeros.io/docs/mapping.md), resolved for every hit against `{ ingest, event }`. A path therefore names its side, like `ingest.ip` or `event.user.id`. An array tries each value in turn and uses the first one that is defined. Set a setting to `false` to leave its parameter out. With `timestamp: false`, Piwik PRO uses the time it receives the hit.

For cookieless tracking, pair `visitorId` with the [fingerprint transformer](https://www.walkeros.io/docs/transformers/fingerprint.md): let it write a hash of length 16 to `user.hash`, and set `visitorId` to `"event.user.hash"`.

## Copy your web mapping[​](#copy-your-web-mapping "Direct link to Copy your web mapping")

`rule.name` selects a Piwik PRO JavaScript method, and `data` resolves to its arguments in order. Use `set` to pass several arguments; any other value is a single argument. A `page view` without `rule.name` becomes `trackPageView`, with `rule.data` as its arguments, or else `data.title` as the title.

The server builds hits for 13 methods. A required argument is marked with `*`. When it is missing, the event is invalid and skipped. Every hit also carries the common parameters, the custom dimensions and the request context from the settings above.

| Method (JavaScript signature)                                                                 | What the server sends                                                                                          |
| --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `trackPageView([title])`                                                                      | `action_name`                                                                                                  |
| `trackEvent(category*, action*[, name[, value[, dimensions]]])`                               | `e_c`, `e_a`, `e_n`, `e_v` (a number)                                                                          |
| `trackGoal(goalId*[, conversionValue[, dimensions]])`                                         | `idgoal`, `revenue` (a number)                                                                                 |
| `trackSiteSearch(keyword*[, category[, resultCount[, dimensions]]])`                          | `search`, `search_cats` (a JSON array, a single category becomes `["..."]`), `search_count` (an integer)       |
| `trackLink(linkAddress*, linkType*[, dimensions])`                                            | `link` or `download`, by `linkType`, which must be `"link"` or `"download"`. `url` is set to the same address. |
| `trackContentImpression(contentName*[, contentPiece[, contentTarget]])`                       | `c_n`, `c_p`, `c_t`                                                                                            |
| `trackContentInteraction(contentInteraction*, contentName*[, contentPiece[, contentTarget]])` | `c_i`, `c_n`, `c_p`, `c_t`                                                                                     |
| `ecommerceProductDetailView(products*)`                                                       | `e_t=product-detail-view`, `ec_products`                                                                       |
| `ecommerceAddToCart(products*)`                                                               | `e_t=add-to-cart`, `ec_products`                                                                               |
| `ecommerceRemoveFromCart(products*)`                                                          | `e_t=remove-from-cart`, `ec_products`                                                                          |
| `ecommerceCartUpdate(products*, grandTotal*)`                                                 | `e_t=cart-update`, `ec_products`, `revenue`                                                                    |
| `ecommerceOrder(products*, { orderId*, grandTotal*, subTotal, tax, shipping, discount })`     | `e_t=order`, `ec_id`, `revenue`, `ec_st`, `ec_tx`, `ec_sh`, `ec_dt`, `ec_products`                             |
| `ping()`                                                                                      | `ping=6`                                                                                                       |

Numbers may also arrive as numeric strings. `products` is an array of 1 to 100 product objects with `sku*`, `name`, `category` (a string or up to 5 strings), `price`, `quantity`, `brand`, `variant` and `customDimensions` (keyed by bare dimension id). A product without `sku`, a category that is not a string or up to 5 strings, a price or quantity that is not a number, or more than 100 products make the event invalid.

State setters such as `setUserId` exist only in the browser. The server keeps no tracker state, so it skips any method outside this table with a warning. The user id comes from the `userId` setting instead.

A page view, a custom event with a goal and an ecommerce order:

```json
"mapping": {
  "page": {
    "view": {}
  },
  "promotion": {
    "click": {
      "name": "trackEvent",
      "data": {
        "set": [{ "value": "promotion" }, { "value": "click" }, "data.name"]
      },
      "settings": { "goalId": "6a0f4c1e-3b2d-4e8f-a7c9-1d2e3f4a5b6c" }
    }
  },
  "order": {
    "complete": {
      "name": "ecommerceOrder",
      "data": {
        "set": [
          {
            "loop": [
              "nested",
              {
                "condition": "$code:(entity) => entity.entity === 'product'",
                "map": {
                  "sku": "data.id",
                  "name": "data.name",
                  "price": "data.price",
                  "quantity": { "value": 1 }
                }
              }
            ]
          },
          {
            "map": {
              "orderId": "data.id",
              "grandTotal": "data.total",
              "tax": "data.taxes",
              "shipping": "data.shipping"
            }
          }
        ]
      }
    }
  }
}
```

### Goals[​](#goals "Direct link to Goals")

A rule's `settings.goalId` adds a second hit, `trackGoal`, to the same request. `settings.goalValue` is a mapping value for its revenue, such as `"data.total"`. A page view rule with goal settings still sends its page view. With `silent: true`, the rule sends only the goal hit.

A rule without `name` on an event that is not a page view sends only the goal when it has a `goalId`:

```json
"order": {
  "complete": {
    "settings": {
      "goalId": "6a0f4c1e-3b2d-4e8f-a7c9-1d2e3f4a5b6c",
      "goalValue": "data.total"
    }
  }
}
```

When the goal value resolves to something other than a number or a numeric string, the goal hit is invalid and the whole event is skipped. The method hit is not sent either. The same applies to any invalid hit: an event is sent completely or not at all.

## Custom dimensions[​](#custom-dimensions "Direct link to Custom dimensions")

Custom dimensions are keyed by bare dimension id, like `{ "1": "data.size" }`. 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 from the hit, even when the destination sets it.
* `trackEvent`, `trackGoal`, `trackSiteSearch` and `trackLink` also take a dimensions object as an argument, like `{ "dimension1": "l" }`. When your mapping passes one, its values win over both settings. Keys other than `dimension{id}` are dropped.

The server sends each dimension as `dimension{id}=value`, ordered by id. The goal hit carries the destination and rule dimensions. Values from a dimensions argument are sent as they are. A value you percent-encoded for the browser therefore arrives encoded. For values that need encoding in the browser, prefer the `customDimensions` settings, which each destination encodes for its own platform.

## Identified and anonymous[​](#identified-and-anonymous "Direct link to Identified and anonymous")

The `identified` setting decides whether a hit identifies the visitor.

| `identified`                                   | Hits                                                                            |
| ---------------------------------------------- | ------------------------------------------------------------------------------- |
| absent or `true`                               | Identified, the Piwik PRO default.                                              |
| `false`                                        | Always anonymous, for example on a cookieless site that never asks for consent. |
| a consent object, like `{ "marketing": true }` | Identified when any listed consent state is granted, anonymous otherwise.       |

The consent check reads the collector's consent state and the event's own consent. Events relayed from the browser carry the visitor's choice. Use `config.consent` for the states that gate tracking at all, and `identified` for the states that gate identification:

```json
"config": {
  "consent": { "analytics": true },
  "settings": {
    "url": "https://your_account_name.piwik.pro/",
    "appId": "XXX-XXX-XXX-XXX-XXX",
    "identified": { "marketing": true }
  }
}
```

caution

Do not repeat the `identified` states in `config.consent`. Events without that consent are then queued and never reach the destination, so no anonymous hit is sent.

An anonymous hit carries `uia=1` and `dda=1` and leaves out `_id` and `uid`. It keeps `cip`, so Piwik PRO can still locate the visitor by country. Each hit is decided on its own. Only the web destination can merge an earlier anonymous session into the identified visitor, with `deanonymizeUser`.

## Batching[​](#batching "Direct link to Batching")

Set a destination-level `batch` so that each flushed batch becomes one bulk request:

```json
"batch": { "size": 100, "wait": 1000 }
```

Spell out both values. The default size cap is 1000 entries, and a bare number such as `"batch": 500` sets only `wait`. [Batch scheduling](https://www.walkeros.io/docs/mapping/rule.md#batch-scheduling) explains `wait`, `size` and `age`. Without batching, every event is a request of its own in the same format.

The body of a bulk request holds one request string per hit. For a page view and a custom event it looks like this, with `ts_v` set to the package version:

```json
{
  "requests": [
    "?idsite=XXX-XXX-XXX-XXX-XXX&rec=1&send_image=0&ts_n=walkerOS&ts_v=<version>&action_name=walkerOS+documentation&url=https%3A%2F%2Fwww.example.com%2F&cip=203.0.113.7&ua=Mozilla%2F5.0&lang=de-DE&_id=cc8e27118413234d&pv_id=0a1b2c&cdt=1700000300",
    "?idsite=XXX-XXX-XXX-XXX-XXX&rec=1&send_image=0&ts_n=walkerOS&ts_v=<version>&e_c=promotion&e_a=visible&e_n=Setting+up+tracking+easily&url=https%3A%2F%2Fwww.example.com%2F&cip=203.0.113.7&ua=Mozilla%2F5.0&lang=de-DE&_id=cc8e27118413234d&pv_id=0a1b2c&cdt=1700000301"
  ]
}
```

A goal adds its hit to the same list. Skipped events are left out of the request and count as delivered. If every event of a batch is skipped, no request is sent.

A failed request (a 4xx or 5xx status, a timeout or a network error) throws, so the whole batch goes to the destination's dead-letter queue. A 429 status is logged as rate limiting first. The destination does not retry.

## Server-side vs browser[​](#server-side-vs-browser "Direct link to Server-side vs browser")

| The browser tracker fills automatically                            | Server                        | How                                                                                                  |
| ------------------------------------------------------------------ | ----------------------------- | ---------------------------------------------------------------------------------------------------- |
| Client IP, user agent, language                                    | Yes                           | `ip`, `userAgent` and `language`, from the ingest map with `event.user` fallbacks                    |
| Page URL, referrer                                                 | Yes                           | `pageUrl` and `referrer`, from `event.source`                                                        |
| Visitor id (`_id`)                                                 | Yes                           | `visitorId`, from `event.user.device`, hashed                                                        |
| User id                                                            | Yes                           | `userId`, from `event.user.id`                                                                       |
| Page view id (`pv_id`)                                             | Yes, for walkerOS web sources | The page trace: one per page load, one per `walker run` in single-page apps                          |
| Request time                                                       | Yes                           | `cdt`, from `event.timestamp`                                                                        |
| Heartbeat for time on page                                         | Partly                        | The `ping` method (`ping=6`) from a `pulse`-triggered event. walkerOS has no unload or blur trigger. |
| Automatic outlink and download tracking                            | No                            | Browser only (`enableLinkTracking`). On the server, tag the link and map its event to `trackLink`.   |
| Screen resolution, plugins, performance timings, JavaScript errors | No                            | Not sent                                                                                             |

The page view id links an event to the page view it happened on. By default it is the trace of an event from a walkerOS web source, and only when that trace differs from the server collector's own trace. Events that start on the server, and hits decoded by the GA4 transformer, get no `pv_id` unless you set `pageViewId` yourself.

## Unmapped and invalid events[​](#unmapped-and-invalid-events "Direct link to Unmapped and invalid events")

These events are skipped:

* An event that is not a page view and whose rule has neither `name` nor `goalId`.
* An event whose rule names a method outside the table, such as `setUserId`.
* A `silent` rule without a goal.
* An invalid event: a missing required argument, no page URL, a value that must be a number but is not (such as `e_v` or `revenue`), or more than 100 products.

Skips never throw. The destination logs a warning once per event name and reason, and repeats at debug level. To keep unmapped events out of the destination entirely, ignore everything with a wildcard and map what you need:

```json
"mapping": {
  "*": { "*": { "ignore": true } },
  "page": { "view": {} }
}
```

## Related[​](#related "Direct link to Related")

* [Piwik PRO web destination](https://www.walkeros.io/docs/destinations/web/piwikpro.md)
* [Express source](https://www.walkeros.io/docs/sources/server/express.md)
* [Fingerprint transformer](https://www.walkeros.io/docs/transformers/fingerprint.md)
* [Consent management](https://www.walkeros.io/docs/guides/consent.md)
