> 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/activity-analyzers.md).

# Activity analyzers

Run your own code on each activity before it is stored, to reformat, enrich, or clean it.

## Your goal

Transform activities on the way in with logic that no declarative rule can express - reshaping a payload to fit your schema, enriching events from a catalogue, filtering what you do not want.

## Expected outcome

Activities stored in the shape your schema expects, with enrichment applied consistently for every activity on the channel.

## What an activity analyzer is

An **activity analyzer** is a [plugin](/setup-and-monitor/extend-the-platform/plugin-architecture.md) that lets you **modify an activity on the fly before it is stored**. It runs as part of the [processing pipeline](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time.md#the-processing-pipeline) - at step 3, after event rules - for every activity of the channel it is associated with.

It is useful for:

* **Reformatting data** - adapting the ingestion data model to the datamart schema.
* **Enriching events** - for instance fetching product information from a product ID.
* **Improving data quality** - filtering unwanted events, matching input values to standard catalogues, parsing URLs into categories.

{% hint style="warning" %}
An activity analyzer is only executed for activities tracked **in real time** - through the user activity API, the JavaScript tag, or pixel tracking. It does **not** run on bulk activity imports, so make sure those are already correctly formatted before uploading them. See [Import activities](/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/import-activities.md).
{% endhint %}

Analyzers are attached to a channel, where they appear as **visit analyzers**. See [Channels](/setup-and-monitor/plan-and-integrate/set-up-the-environment/set-up-channels.md).

## What it can and cannot change

|            |                                                                                         |
| ---------- | --------------------------------------------------------------------------------------- |
| **Can**    | Add, remove, and modify events; add and modify properties; reshape the activity object. |
| **Cannot** | Modify the identifiers passed in the incoming activity.                                 |

{% hint style="danger" %}
Two consequences to design around:

* An analyzer can **remove** events. If it removes a `$set_user_choice` event, the corresponding user choice is never stored. See [Server-side events](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/server-side-events.md#create-or-update-a-user-choice).
* [Edge](/setup-and-monitor/plan-and-integrate/set-up-advanced-features/edge.md) requires properties to be stored **exactly as pushed by the tag**. A property that passes through an analyzer cannot be used in Edge segment queries.
  {% endhint %}

## The contract

An activity analyzer has a single endpoint to implement.

```
POST myworker/v1/activity_analysis
```

It is called every time an activity is processed. The analyzer receives an activity and responds with a new activity.

| Request field          | Type   | Description                                                                             |
| ---------------------- | ------ | --------------------------------------------------------------------------------------- |
| `activity_analyzer_id` | String | The ID of the analyzer instance to use. **Use it to retrieve the instance properties.** |
| `datamart_id`          | String | The ID of the datamart.                                                                 |
| `activity`             | Object | The UserActivity object to analyse.                                                     |

{% tabs %}
{% tab title="Success" %}
In most cases the plugin responds with the modified activity object to store:

```json
{
    "status": "ok",
    "data": {
        // New UserActivity object
    }
}
```

{% endtab %}

{% tab title="Error" %}
On an unexpected error:

```json
{
  "status": "error",
  "error": "Your error message"
}
```

{% endtab %}
{% endtabs %}

## Reading the instance context

Plugin code should not hard-code configuration. Use the `activity_analyzer_id` from the incoming request to fetch the instance and its properties:

```
GET https://api.mediarithmics.com/v1/activity_analyzers/:id
GET https://api.mediarithmics.com/v1/activity_analyzers/:id/properties
```

The first returns the instance - its name, organisation, plugin ID, group ID, and artifact ID. The second returns the properties configured on it, each with a technical name, a value, a type, an origin, and whether it is writable.

This is what lets the same plugin behave differently per instance. See [Plugin architecture](/setup-and-monitor/extend-the-platform/plugin-architecture.md) for the instance model, and [Build an activity analyzer](/setup-and-monitor/extend-the-platform/build-an-activity-analyzer.md) for developing one.

{% hint style="info" %}
The standard group ID for an activity analyzer is `{domain}.{organisation}.activity-analyzer` - for example `com.mediarithmics.activity-analyzer`.
{% endhint %}

## Choosing between the options

| Need                                                                              | Use                                                                                                                                                                                         |
| --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Extract a value from a URL, copy a property into the origin, derive an identifier | An [event rule](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/event-rules.md) - declarative, no code.                                                           |
| Rename a custom event to a predefined one, for analytics only                     | An [event transformation](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/activities-analytics.md#transforming-your-custom-events) - no code, but analytics-only. |
| Anything requiring logic, an external lookup, or arbitrary reshaping - everywhere | An **activity analyzer**.                                                                                                                                                                   |

## Verify

* The `ACTIVITY_ANALYZER` step in ingestion monitoring shows events passing through. See [Monitor data ingestion](/setup-and-monitor/operate-and-monitor/monitor-data-ingestion.md).
* The `DOCUMENT_STORE` count is consistent with it - a large drop between the two means the analyzer is removing activities.
* A real activity shows the enrichment applied.
* Identifiers are unchanged, as expected.

## 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>Build an activity analyzer</strong></td><td>Developing and deploying the plugin.</td><td><a href="/setup-and-monitor/extend-the-platform/build-an-activity-analyzer.md">Build an activity analyzer</a></td></tr><tr><td><strong>Event rules</strong></td><td>The declarative alternative.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/event-rules.md">Event rules</a></td></tr><tr><td><strong>Plugin architecture</strong></td><td>How instances and properties work.</td><td><a href="/setup-and-monitor/extend-the-platform/plugin-architecture.md">Plugin architecture</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/activity-analyzers.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.
