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

# Piano Analytics

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

[Piano Analytics](https://piano.io/product/analytics/) is an enterprise analytics and audience platform. The destination configures the official Piano `pa` SDK with your site id and collection domain, and forwards events via `pa.sendEvent`. With `loadScript: true` it also loads the SDK.

Where this fits

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

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

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

* Integrated
* Bundled

```typescript
import { startFlow } from '@walkeros/collector';
import { destinationPiano } from '@walkeros/web-destination-piano';

await startFlow({
  destinations: {
    piano: {
      code: destinationPiano,
      config: {
        loadScript: true,
        settings: {
          site: 123456789,
          collectDomain: 'https://example.pa-cd.com',
        },
      },
    },
  },
});
```

Add to your `flow.json` destinations:

```json
"destinations": {
  "piano": {
    "package": "@walkeros/web-destination-piano",
    "config": {
      "loadScript": true,
      "settings": {
        "site": 123456789,
        "collectDomain": "https://example.pa-cd.com"
      }
    }
  }
}
```

[See bundled mode setup](https://www.walkeros.io/docs/getting-started/modes/bundled.md) | [CLI reference](https://www.walkeros.io/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](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 |
| ---------------- | --------------------- | ---------------------------------------------------------------- | ---- |
| `site*`          | `number`              | Piano Analytics site id (numeric), from your collection settings |      |
| `collectDomain*` | `string`              | Collection domain endpoint, like https\://xxxxxxx.pa-cd.com      |      |
| `options`        | `Record<string, any>` | Additional Piano setConfigurations options merged on init        |      |

\* Required fields

## Mapping[​](#mapping "Direct link to Mapping")

This package does not define custom rule-level settings. For the standard rule fields (consent, condition, data, batch, name, policy) see [mapping](https://www.walkeros.io/docs/mapping.md).

## Examples

### Custom event

A generic entity action fires a custom Piano event with mapped properties.

Event

```json
{
  "name": "entity action",
  "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": "7ed36be48eaf44d3",
  "trigger": "test",
  "entity": "entity",
  "action": "action",
  "timestamp": 1700000202,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```json
{
  "name": "click.action",
  "data": {
    "map": {
      "label": "data.string",
      "value": "data.number"
    }
  }
}
```

Out

```javascript
pa.sendEvent("click.action", {
  "label": "foo",
  "value": 1
})
```

### Initialization

Destination bootstrap configures Piano with the site id and collection domain.

Event

```json
{
  "settings": {
    "site": 123456789,
    "collectDomain": "https://example.pa-cd.com"
  }
}
```

Out

```javascript
pa.setConfigurations({
  "site": 123456789,
  "collectDomain": "https://example.pa-cd.com"
})
```

### Page view

A page view fires a Piano page.display event with the page name and chapter.

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": "a7ca8a89edf9a549",
  "trigger": "load",
  "entity": "page",
  "action": "view",
  "timestamp": 1700000200,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```json
{
  "name": "page.display",
  "data": {
    "map": {
      "page": "data.title",
      "page_chapter1": "globals.pagegroup"
    }
  }
}
```

Out

```javascript
pa.sendEvent("page.display", {
  "page": "walkerOS documentation",
  "page_chapter1": "docs"
})
```

### Purchase

A completed order fires a Piano transaction.confirmation event with the transaction id, revenue and currency.

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": "f0459a803a14935a",
  "trigger": "load",
  "entity": "order",
  "action": "complete",
  "timestamp": 1700000201,
  "timing": 3.14,
  "source": {
    "count": 1,
    "trace": "0a1b2c3d4e5f60718293a4b5c6d7e8f9",
    "type": "collector",
    "schema": "4"
  }
}
```

Mapping

```json
{
  "name": "transaction.confirmation",
  "data": {
    "map": {
      "transaction_id": "data.id",
      "revenue": "data.total",
      "currency": "data.currency"
    }
  }
}
```

Out

```javascript
pa.sendEvent("transaction.confirmation", {
  "transaction_id": "0rd3r1d",
  "revenue": 555,
  "currency": "EUR"
})
```

## Loading the SDK[​](#loading-the-sdk "Direct link to Loading the SDK")

With `loadScript: true`, the destination adds the SDK script `https://tag.aticdn.net/piano-analytics.js` and configures `pa` with `site`, `collectDomain` and `options` once the script has loaded. If the script fails to load, it logs a warning. Until the SDK has loaded, the destination drops every event it receives and counts it as delivered. That includes the page view a browser source sends when the flow starts.

To keep the first events, load the Piano SDK on your page before walkerOS starts and leave `loadScript` unset. The destination then configures `pa` at init.

## Event names[​](#event-names "Direct link to Event names")

Each rule's `name` becomes the Piano event name and its `data` object the event properties, as in the examples above. Without a rule, the destination sends the walkerOS event name, like `page view`, with no properties.
