> For the complete documentation index, see [llms.txt](https://docs.mediarithmics.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.mediarithmics.io/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/web-tracking.md).

# Web tracking

Deploy the JavaScript tag on your websites, send the right events, and configure it server-side.

## Your goal

Get the mediarithmics tag running on the pages you want to track, sending the events in your tracking plan with the identifiers you have.

## Expected outcome

Events arriving from every tracked page, attributed to the right channel, carrying the identifiers you can supply - and no data collected before consent.

{% hint style="danger" %}
The cookies used by the tag are considered **advertising cookies**. **You must obtain user consent before using it.** See [Manage consent & Processing activities](/setup-and-monitor/ensure-privacy-and-compliance/manage-consent-and-processing-activities.md).
{% endhint %}

## Prerequisites

* A **channel** of type site for the property, and its **site token**. See [Channels](/setup-and-monitor/plan-and-integrate/set-up-the-environment/set-up-channels.md).
* A [tracking plan](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/define-your-tracking-plan.md).
* A consent mechanism in place before the tag fires.

## How the tag is integrated

The tag tracks a visitor's navigation on a website. It is imported in a JavaScript snippet that has to be executed on every page you want to track.

The two common ways to integrate it:

{% columns %}
{% column %}

### Through a tag container

Google Tag Manager or a similar solution. The snippet is copied once into a new tag, and the container inserts it wherever it is needed.
{% endcolumn %}

{% column %}

### In a shared template

The snippet goes into a general-purpose template - a shop's header template, for instance - used by all pages of the site.
{% endcolumn %}
{% endcolumns %}

The snippet's code is **non-blocking**: it does not affect page rendering time, and it can be inserted in the `<head>` of the page.

{% hint style="info" %}
To track users from your backend, use the [tracking API](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/server-side-events.md) instead. To import events or activities in bulk, use [Import data in batch](/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch.md).
{% endhint %}

## Implement the snippet

The snippet has two parts: a **technical tag** containing the JavaScript that asynchronously loads the tag - which you should not edit, except to change the tag name - and the **configuration**, which you fill in for your context: site token, event name, event properties.

```html
<script type="text/javascript">
    /* YOU SHOULD NOT EDIT THIS PART */
    /* The loader snippet provided for your site. Its last argument is the tag name. */

    mics.init("<SITE_TOKEN>");

    // Enables client-side feeds
    mics.call("syncFeeds");

    /* CUSTOMIZE THE TAG CALL BELOW */
    // remove next line to customize what you track
    mics.pushDefault();
</script>
```

{% hint style="info" %}
Get the exact loader snippet for your site from the platform rather than copying it from documentation - it is versioned, and features such as [Edge](/setup-and-monitor/plan-and-integrate/set-up-advanced-features/edge.md) require the latest version.
{% endhint %}

Three customisations are available at the snippet level:

{% tabs %}
{% tab title="Change the tag name" %}
The tag name is the last argument of the loader, and the global object the rest of your code calls. Changing it lets you implement several tags, or use a name of your own:

```javascript
// Loader initialised with the name "umbrella_corp"
umbrella_corp.init("<SITE_TOKEN>");
umbrella_corp.call("syncFeeds");
umbrella_corp.pushDefault();
```

{% endtab %}

{% tab title="Use your own domain" %}
To remove mediarithmics from your website entirely, contact technical support to get your own domain name, then pass it in the initialisation:

```javascript
umbrella_corp.init({
  mode: "VISIT",
  site_token: "<SITE_TOKEN>",
  domain_name: "<YOUR_DOMAIN_NAME>"
});
```

{% endtab %}

{% tab title="Push on an interaction" %}
You do not have to push on page load. Bind the push to an interaction instead:

```javascript
mics.init({ mode: "VISIT", site_token: "<SITE_TOKEN>" });
mics.call("syncFeeds");

$(".your_button").on("click", function () {
  mics.push("click button", {
    button_type: "button1"
  });
});
```

{% endtab %}
{% endtabs %}

## Send identifiers

Use `addIdentifier(type, identifier)` once per identifier you can supply.

```javascript
mics.addIdentifier("USER_ACCOUNT", {
    $user_account_id: "account 1",
    $compartment_token: "token1"
});

mics.addIdentifier("USER_EMAIL", {
    $email_hash: "email hash",
    $email: "email address"
});

mics.addIdentifier("USER_AGENT", {
    $user_agent_id: "user agent id"
});
```

| Type           | Expected object                                                                          |
| -------------- | ---------------------------------------------------------------------------------------- |
| `USER_ACCOUNT` | `{$user_account_id: string}` or `{$user_account_id: string, $compartment_token: string}` |
| `USER_EMAIL`   | `{$email_hash: string}` or `{$email_hash: string, $email: string}`                       |
| `USER_AGENT`   | `{$user_agent_id: string}`                                                               |

* `$email` is optional.
* `$compartment_token` is optional - if omitted, the datamart's default compartment is used.
* `$user_agent_id` is a [user agent ID](/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/user-identity/user-identifiers/user-device.md#user_agent_id-formats). Accepted agent types here are mobile advertising ID, mobile vendor ID, TV advertising ID, and custom ID.
* **Do not add network device IDs here** - they are managed from the interface. If the network device ID you need is not available, contact support.

{% hint style="warning" %}
If invalid arguments are passed to `addIdentifier`, **no error is thrown** in the browser console. Verify the result on the UserPoint, not in the console.
{% endhint %}

Several accounts can be declared by calling `addIdentifier` more than once, each with its own compartment token.

{% hint style="info" %}
The legacy method below will be removed. Move to `addIdentifier` as soon as you can.

```javascript
mics.addProperty("$user_account_id", "<USER_ACCOUNT_ID>");
mics.addProperty("$comp_token", "<COMPARTMENT_TOKEN>");
```

{% endhint %}

## Send events

### Default tracking

Out-of-the-box tracking generates a `$page_view` event - this is what the snippet does as-is:

```javascript
mics.pushDefault();
```

{% hint style="warning" %}
`$page_view` events **are dropped when the session closes** and disappear from the monitoring timeline. They are only useful to test that events reach the platform.
{% endhint %}

### Custom events

```javascript
mics.push("view my form", {
  "form subject": "auto trial"
});
```

Refer to the [predefined event names](/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/standard-events.md) and prefer them to custom names, because the platform handles automatic processing for them.

### E-commerce events

Implement the snippet at the key places, with the matching event name:

{% tabs %}
{% tab title="Home page" %}

```javascript
mics.addIdentifier("USER_ACCOUNT", {
    $user_account_id: "<USER_ACCOUNT_ID>",
    $compartment_token: "<COMPARTMENT_TOKEN>"
});

mics.push("$home_view");
```

{% endtab %}

{% tab title="Category or search results" %}
Only the **first 3 items** in the list should be declared.

```javascript
mics.push("$item_list_view", {
  "$items": [
    {"$id": "78798978"},
    {"$id": "444444"},
    {"$id": "78808900"}
  ]
});
```

`$id` is the product ID.
{% endtab %}

{% tab title="Product page" %}

```javascript
mics.push("$item_view", {
  "$items": [
    { "$id": "89999999" }
  ]
});
```

{% endtab %}

{% tab title="Basket page" %}

```javascript
mics.push("$basket_view", {
  "$items": [
    {"$id": "78794", "$price": 10.8,  "$qty": 1},
    {"$id": "78677", "$price": 56.99, "$qty": 1}
  ],
  "$currency": "EUR"
});
```

`$price` is the product price without the currency, `$qty` the quantity in the basket. `$currency` is optional - with a single catalogue the catalogue currency is used.
{% endtab %}

{% tab title="Transaction confirmation" %}

```javascript
mics.push("$transaction_confirmed", {
  "$items": [
    {"$id": "78794", "$price": 10.8,  "$qty": 1},
    {"$id": "78677", "$price": 56.99, "$qty": 1}
  ],
  "$transaction_id": "transact-XYZ",
  "$currency": "EUR"
});
```

`$id` should be **the same ID as the one used in your product feed**. `$transaction_id` holds the ID of the transaction.
{% endtab %}
{% endtabs %}

Add the user account ID wherever it is available - tracking is materially better with it.

{% hint style="info" %}
You can add any custom property available in the page's JavaScript. You can also use [activity analyzers](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/activity-analyzers.md) to enrich the data later using the product IDs, rather than sending everything from the browser.
{% endhint %}

### Profile updates from the tag

If the user is identified, you can register updates to their profile from the snippet - typically on the profile pages of your site. Use the special event `$set_user_profile_properties`: its properties and values are written as key-value pairs on the `UserProfile`.

```javascript
mics.push("$set_user_profile_properties", {
  gender: "male"
});
```

By default the **anonymous UserProfile of the datamart's default compartment** is updated, and `force_replace` is `false`. Two special properties change the target:

| Property                            | What it does                                                                                                              |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `$set_user_profile_comp_token`      | Optional. The compartment token of the compartment the profile should be written in. Defaults to the default compartment. |
| `$set_user_profile_user_account_id` | Optional. The user account ID under which the profile should be written. Without it, the anonymous profile is used.       |

```javascript
// Write to the profile identified by an account ID in a given compartment
mics.push("$set_user_profile_properties", {
    "$set_user_profile_comp_token": "my_compartment_token",
    "$set_user_profile_user_account_id": "456",
    "gender": "female"
});
```

## Server-side configuration

Some tag behaviours are configured server-side, in the same way as with a tag manager. They are found on the corresponding channel in the Navigator settings - which means you can change them without redeploying the snippet.

### Device identification

Select the identifiers the tag uses automatically to identify devices:

* mediarithmics first-party cookie
* mediarithmics third-party cookie (vector ID)

The tag can also retrieve a user or device identifier from partners you have already integrated with: ID5, First ID, and Utiq martechpass (mobile). See [Network IDs](/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/user-identity/network-ids.md).

<details>

<summary>What the mediarithmics first-party cookie can and cannot do</summary>

This method, also referred to as **`INSTALLATION_ID`**, can only be used for tracking on the specific website where it is dropped, and to a limited extent for first-party activation, acting as a PPID. It **does not enable cross-site reconciliation or cross-site targeting**.

* It is only available on the **SITE** channel type.
* It does not provide full browser coverage: some browsers, such as Safari, restrict first-party cookies set by JavaScript originating from third-party sources - which is what the tag is.
* It is a different mechanism from the replication of the mediarithmics third-party cookie onto the first-party domain (`mics_vid`), which happens systematically for caching purposes.

When activated, a first-party cookie named `mics_<custom_cookie_name>` or `mics_<site_token>` is dropped in the user's browser. The value format is described in [User Device](/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/user-identity/user-identifiers/user-device.md#cookie-based-identifiers).

</details>

### IAB Transparency and Consent Framework

Enable this if you want the tag to automatically take any TCF-compliant CMP on the website into account before creating third-party cookies and performing cookie matching.

### Cookie matching with Google and Xandr

Select whether the tag triggers cookie matching with Google and Xandr. For other partners, check with support.

### Support of the third-party cookie (vector ID)

By default, the mediarithmics third-party cookie is **not** generated if the browser does not support matching with Google and Xandr. Use this setting to force its generation even when those matchings do not succeed.

## The one-tag approach

A **one-tag approach** means tracking visitors and their behaviour with a single tracking code, rather than a different snippet per page type. It is simpler to implement and maintain, and it usually implies using an [activity analyzer](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/activity-analyzers.md) to process the collected data server-side.

The tag supports it by referencing variables that already exist in the browser's DOM.

{% tabs %}
{% tab title="Nothing but the defaults" %}
The tag already collects the URL, the referrer, the user agent, and the time, so these do not need to be provided:

```javascript
mics.init("<SITE_TOKEN>");
mics.push("hit", {});
```

{% endtab %}

{% tab title="Google Tag Manager" %}
Collect the relevant properties from the data layer:

```javascript
function micsGetAllProperties() {
    var data = {};
    if (Object.keys(dataLayer).length > 0) {
        dataLayer.forEach((item) => {
            Object.keys(item).forEach(key => {
                if (isNaN(key) && key != "event" && !key.startsWith("gtm")) {
                    data[key] = item[key];
                }
            })
        })
    }
    return data;
}

mics.init("<SITE_TOKEN>");
mics.push("hit", { "data": micsGetAllProperties() });
```

{% endtab %}

{% tab title="Commanders Act" %}
All properties are stored in the `tc_vars` variable:

```javascript
mics.init("<SITE_TOKEN>");
mics.push("hit", { "data": tc_vars });
```

{% endtab %}
{% endtabs %}

## AMP pages

AMP pages are tracked with the `amp-analytics` module, which must be present in the page environment.

```html
<amp-analytics type="mediarithmics">
  <script type="application/json">
    {
      "vars": {
        "site_token": "<SITE_TOKEN>",
        "event_name": "amp-test-pageview"
      },
      "extraUrlParams": {
        "prop1": "value1",
        "prop2": "value2"
      }
    }
  </script>
</amp-analytics>
```

| Argument              | Type   | Description                                                |
| --------------------- | ------ | ---------------------------------------------------------- |
| `site_token`          | String | The token of the website. **Required.**                    |
| `event_name`          | String | The name of the event. Optional, defaults to `$page_view`. |
| *any custom property* | String | Custom properties go in the `extraUrlParams` object.       |

## Verify

* The channel's event count over the last 7 days is non-zero in **Settings > Datamart > Channels**.
* The `JS_TAG` step shows events in ingestion monitoring. See [Monitor data ingestion](/setup-and-monitor/operate-and-monitor/monitor-data-ingestion.md).
* A real user's activities carry the identifiers and properties your plan specifies. See [Explore a user profile](/setup-and-monitor/operate-and-monitor/explore-a-user-profile.md).
* Nothing is collected before consent is given.

## Troubleshooting

| Symptom                                 | Likely cause                                                                                              |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| No events at all                        | The site token is wrong, the snippet is not executing, or consent is never granted.                       |
| Events arrive but no user is identified | `addIdentifier` received invalid arguments - it fails silently - or the compartment token does not exist. |
| Page views disappear                    | `$page_view` events are dropped at session close by design.                                               |
| A property is missing from queries      | It is not indexed in the schema, or an event rule or analyzer changed it.                                 |
| A device identifier never appears       | The corresponding registry or channel-level device identification is not enabled.                         |

## Related pages

<table data-view="cards" data-search="false"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Define your tracking plan</strong></td><td>What to send, decided before implementation.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/define-your-tracking-plan.md">Define your tracking plan</a></td></tr><tr><td><strong>App tracking</strong></td><td>The same job for mobile and CTV apps.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/app-tracking.md">App tracking</a></td></tr><tr><td><strong>Audit our tag's browser footprint</strong></td><td>The cookies the tag sets, and on which domains.</td><td><a href="/setup-and-monitor/ensure-privacy-and-compliance/audit-our-tag-s-browser-footprint.md">Audit our tag's browser footprint</a></td></tr></tbody></table>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.mediarithmics.io/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/web-tracking.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
