> 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/extend-the-platform/plugin-architecture.md).

# Plugin architecture

How the platform hosts your code: plugins, versions, workers, instances, and properties.

## Your goal

Understand the model before you write a plugin, so your first version is versioned, configurable, and deployable without surprises.

## Expected outcome

You can say what a plugin, a version, a worker, and an instance each are - and you know which of them your code has to be aware of at runtime.

## What a plugin is

A **plugin** is a package of code hosted by the platform, used to modify or extend the platform's features. It is a piece of logic encapsulated in a web service, and it can be developed in many languages.

The platform **hosts and monitors it directly**, which is what enables event-based triggering and fast access to the data. Once instantiated, a plugin listens on an HTTP port for requests coming from the platform, and depending on its type it must comply with a specific REST API.

{% hint style="info" %}
Use the **Plugin SDK** to get off-the-shelf endpoint connectivity and accelerate development. With Node.js, the SDK handles the instance and property fetching described below for you.
{% endhint %}

## The plugin types

| Type                               | What it does                                                                                                            | Documented in                                                                                                                 |
| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **Activity analyzer**              | Enriches real-time user tracking data.                                                                                  | [Build an activity analyzer](/setup-and-monitor/extend-the-platform/build-an-activity-analyzer.md)                            |
| **Audience segment external feed** | Sends data to a partner, either in server-side streams or by showing a pixel to users in the segment.                   | [Build a custom feed plugin](/setup-and-monitor/extend-the-platform/build-a-custom-feed-plugin.md)                            |
| **Computed field function**        | Manages a calculated field in your schema.                                                                              | [Build a computed field](/setup-and-monitor/extend-the-platform/build-a-computed-field.md)                                    |
| **Custom action**                  | Launches a custom action in automations.                                                                                | [Build a custom automation plugin](/setup-and-monitor/extend-the-platform/build-a-custom-automation-plugin.md)                |
| **Display ad renderer**            | Customises the rendering of display ads.                                                                                | -                                                                                                                             |
| **Attribution engine**             | Customises the attribution of a marketing goal to different campaigns.                                                  | -                                                                                                                             |
| **Integration batch**              | Manages data imports or exports by producing a batch of multiple items at once, one stage at a time.                    | -                                                                                                                             |
| **ML Algorithm**                   | Manages the calculation of predictions attached to a user, in an event-based manner. Used together with an ML Function. | [Affinity & Intention](/setup-and-monitor/plan-and-integrate/set-up-advanced-features/affinity-and-intention-ml-algorithm.md) |

## The five objects

They are easiest to understand as a chain: you declare a **plugin**, publish a **version** of it, the platform runs **workers** for that version, and your users create **instances** configured through **properties**.

```mermaid
flowchart TD
    P["Plugin<br/>type, group_id, artifact_id"]
    V1["Version 1.0.0<br/>code, properties, layout"]
    V2["Version 2.0.0"]
    W1["Worker"]
    W2["Worker"]
    I1["Instance<br/>on a site"]
    I2["Instance<br/>on an app"]
    P --> V1
    P --> V2
    V1 --> W1
    V1 --> I1
    V1 --> I2
    V2 --> W2
```

<details>

<summary>The same thing as a story</summary>

A developer wants an activity analyzer that parses real-time navigation data from a site and adds a product code taken from an external system.

1. The developer declares a **plugin** with the activity analyzer **type**.
2. They create **version** 1.0.0, declaring two **properties** - a string for the configuration file name to retrieve, and a boolean asking whether the code overwrites the product name - plus a **layout** for the form end users will fill in. They deploy the code attached to this version.
3. The platform automatically creates a **worker** running the code, waiting for activities.
4. A user attaches version 1.0.0 to their site and sets the properties. An **instance** is created. Each time an activity arrives for that site, the worker receives a request and adapts its logic to the context and the properties.
5. The same user attaches the same version to an app. A **second instance** is created, with its own properties.
6. The user asks for a new parameter. The developer creates **version** 2.0.0, redeclares the old properties and adds the new one, specifies a new layout, and deploys new code. The platform creates a new worker for it.
7. The user adds version 2.0.0 to the site and removes 1.0.0 from it. Activities from the site are now analysed by 2.0.0, while activities from the app are still analysed by 1.0.0.

</details>

### Plugin

The top-level declaration. It is attached to a specific **organisation** and has a specific **type**.

It is classified by a **`group_id`** and an **`artifact_id`**:

* `group_id` is the name of the context, usually a reversed domain name such as `com.mediarithmics.creative.display`. Lowercase alphanumeric characters, dots, hyphens, and underscores.
* `artifact_id` is the technical name of the plugin, such as `image-iframe`. Lowercase alphanumeric characters, hyphens, and underscores - **no dots**.

{% hint style="warning" %}
Create **unique** `group_id` / `artifact_id` combinations: together with the version, they act as identifiers.

Each plugin type has its own standard for group and artifact IDs, given in that type's documentation.
{% endhint %}

### Versions

A plugin supports **multiple versions**, each with its own codebase, layouts, properties, declarations, and configuration files, and several can be available at once. A version number is three digits with an optional suffix - `1.0.0`, `1.2.0-rcl`.

```mermaid
stateDiagram-v2
    [*] --> DRAFT: version created
    DRAFT --> DEPLOYING: deployment triggered
    DEPLOYING --> TESTING: container created
    DRAFT --> TESTING
    TESTING --> LIVE: validated
    LIVE --> DECOMMISSIONED: no active instances remain
    DECOMMISSIONED --> ARCHIVED
```

| Status           | What it means                                                                                                                             |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `DRAFT`          | The initial state. Editable, but not usable until deployed.                                                                               |
| `DEPLOYING`      | For hosted containers: the platform is creating the container.                                                                            |
| `TESTING`        | Accessible to organisation administrators only. Can still be updated and tested in production, but **users cannot create instances yet**. |
| `LIVE`           | Available to all users, and **cannot be modified**. Can be designated as the `current_version`, making it the default.                    |
| `DECOMMISSIONED` | Still visible, no longer usable. A version can only be decommissioned **if no active instances exist in production**.                     |
| `ARCHIVED`       | Removed from the interface.                                                                                                               |

**When to create a new version** - when you need to edit properties, or when you want plugins already added by users to keep their existing behaviour.

You do **not** create a version to fix something in the code, or to change a delay in a configuration file. You **do** create one if the user should enter a new property value, or if your code changes so that existing instances should not use it.

| Updating a version, you can change                    | You cannot change |
| ----------------------------------------------------- | ----------------- |
| Configuration files, external services, code, layouts | Properties        |

Creating a new version means redeclaring properties - changed or not - re-uploading configuration files, redeclaring external services and making sure they are enabled, redeploying the code with an updated version number in the build definition, and redeclaring the layouts.

### Workers

To scale the processing of your plugin, the platform deploys its code **several times on different servers** and load-balances between them. Each of those deployments is a **worker**.

A new worker is created each time you create a version, or when scaling is needed. During that process the worker's `/init` route is called for initialisation and authentication, and it joins the other workers once its `/status` route responds ready.

### Instances

An **instance** is created in the interface when a user configures a plugin for a use case. It links a plugin version, **property values**, and a **context** of execution - a segment, a channel, a datamart.

Configuring the same plugin for a different target does not necessarily create a new worker, but it always creates a new instance. **Your code must therefore retrieve the instance to adapt to its context**:

{% stepper %}
{% step %}

### Find the instance in the request

Its ID is always in the request body - `creative_id` for a display ad renderer, `activity_analyzer_id` for an activity analyzer.
{% endstep %}

{% step %}

### Fetch the properties of that instance

And cache them for future use.
{% endstep %}

{% step %}

### Process according to that configuration

{% endstep %}
{% endstepper %}

{% hint style="danger" %}
This is the single most important thing to get right. A plugin that hard-codes its configuration works for one instance and silently misbehaves for the second - and the second is created by a user, not by you.
{% endhint %}

### Properties

A version declares the properties available in its instances.

```json
{
  "technical_name": "provider",
  "value": { "value": "mediarithmics" },
  "property_type": "STRING",
  "origin": "PLUGIN_STATIC",
  "writable": false,
  "deletable": false
}
```

Three origins:

| Origin          | Meaning                                                                                                                                                                                                                         |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PLUGIN_STATIC` | Reserved for mandatory properties defined by mediarithmics. Every version must define two: `name` and `provider`. You can set their values, but change nothing else. Not writable, so the value is identical in every instance. |
| `PLUGIN`        | Your custom properties, declared per version. Set `writable: true` to give a default value that instances can override, or `false` for a value shared by all instances.                                                         |
| `INSTANCE`      | Properties specific to one instance of a version.                                                                                                                                                                               |

`provider` is usually `mediarithmics` for plugins made by mediarithmics, and the integrator or customer name otherwise.

{% hint style="info" %}
For usability, keep to **no more than 15 `PLUGIN` properties** per version. Beyond that, use a `DATA_FILE` property.
{% endhint %}

**Property types**

| Type        | Value shape                                                                                      |
| ----------- | ------------------------------------------------------------------------------------------------ |
| `STRING`    | `{"value":"mystring"}`                                                                           |
| `INT`       | `{"value":12}`                                                                                   |
| `DOUBLE`    | `{"value":12.45}`                                                                                |
| `BOOLEAN`   | `{"value":true}`                                                                                 |
| `URL`       | `{"url": "https://example.com"}`                                                                 |
| `ASSET`     | `{"original_file_name": "cat.png", "asset_id": "1333", "file_path": "/1/public/assets/cat.png"}` |
| `DATA_FILE` | `{"uri": "", "last_modified": null}`                                                             |

Some plugin types add their own property types, documented with that type.

### Data files

A `DATA_FILE` property points to a file uploaded to the platform - usually JSON - containing information the plugin uses at runtime.

Use one instead of many properties when you want to:

* update several versions or instances at once by uploading a new version of the file,
* store a large number of advanced properties,
* keep properties that only power users should touch out of the ordinary form.

### Layouts

A **layout** lets you customise the new-instance and edit-instance screens: grouping properties into categories, and choosing the type of field representing each one. A layout is bound to a **plugin version**.

## Controlling how hard a plugin is called

Some plugins call external providers with their own API limits, and not every plugin handles the errors that occur when those limits are hit. **Throttlings** reduce plugin calls before the limits are reached.

A throttling limits a given plugin version in three ways - you must define **at least one**:

| Field             | What it limits                                                                       |
| ----------------- | ------------------------------------------------------------------------------------ |
| `max_qps`         | Calls per second. It can be decimal: `0.5` means at most one call every two seconds. |
| `max_concurrency` | Simultaneous calls.                                                                  |
| `timeout_ms`      | Maximum call duration - the call is killed beyond it.                                |

Throttlings can be defined at four scopes: `GLOBAL`, `CONTAINER`, `ORGANISATION`, and `DATAMART`. For the organisation and datamart scopes, `throttling_key` holds the corresponding ID, and `plugin_endpoint` names the routes affected - for example `/v1/user_segment_update`.

```
POST   /v1/plugins/:plugin_id/versions/:version_id/throttlings
GET    /v1/plugins/:plugin_id/versions/:version_id/throttlings
PUT    /v1/plugins/:plugin_id/versions/:version_id/throttlings/:throttling_id
DELETE /v1/plugins/:plugin_id/versions/:version_id/throttlings/:throttling_id
```

## 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 a custom feed plugin</strong></td><td>The most common plugin to build.</td><td><a href="/setup-and-monitor/extend-the-platform/build-a-custom-feed-plugin.md">Build a custom feed plugin</a></td></tr><tr><td><strong>Build an activity analyzer</strong></td><td>Transforming activities as they arrive.</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>Build a computed field</strong></td><td>Calculating a field on the UserPoint.</td><td><a href="/setup-and-monitor/extend-the-platform/build-a-computed-field.md">Build a computed field</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/extend-the-platform/plugin-architecture.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.
