> 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/ensure-privacy-and-compliance/manage-consent-and-processing-activities.md).

# Manage consent & Processing activities

Register processing activities, capture user choices, and enforce them with privacy walls.

## Your goal

Store the choices your users make, and have the platform enforce them automatically - blocking the storage of data you are not entitled to keep, and keeping users out of segments they should not be in.

## Expected outcome

Processing activities registered, choices arriving from your sources, and privacy walls in place on the channels, compartments, and segments that need them.

## The three steps, in order

```mermaid
flowchart LR
    P["1. Register<br/>processing activities"]
    C["2. Record<br/>user choices"]
    W["3. Implement<br/>privacy walls"]
    P --> C --> W
```

1. **Register processing activities** in the platform, representing what you expect to do with the data and its legal basis.
2. **Record user choices** as events, wherever the user acknowledges what is done with their data. The choices and their history are stored per user.
3. **Implement privacy walls** by linking your channels, compartments, and segments to the relevant processing activities.

{% hint style="danger" %}
**Do not reverse steps 2 and 3.** Privacy walls on channels and compartments prevent the platform from storing data it should not - which means a wall enforced before the choices exist drops data you were entitled to keep, and dropped data cannot be recovered.

If you start using the feature on a datamart where you have **already** captured user data, make sure a **sufficient number of UserPoints have been updated with a user choice** before enforcing, to avoid losing data at ingestion or seeing a drop in segment volumes. Ask your account manager for advice before setting these configurations.
{% endhint %}

The legal groundwork that precedes all three is in [Define your privacy & compliance framework](/setup-and-monitor/ensure-privacy-and-compliance/define-your-privacy-and-compliance-framework.md).

## Processing activities

A **processing activity** represents what you expect to do with the data. In GDPR terms it pairs a **purpose** with a **legal basis**; the GDPR requires you to define the purposes of your data collection, and each processing must have an associated legal basis.

Processing activities are defined at **community** level.

| Field            | Type    | Description                                                                                                                 |
| ---------------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
| `id`             | String  | The primary ID on the platform, defined by the platform. Used to identify a processing in an authenticated environment.     |
| `name`           | String  | A descriptive name, displayed in the interface dropdowns.                                                                   |
| `purpose`        | String  | The explained purpose of your processing. **Must be consistent with the information you gave your users.**                  |
| `legal_basis`    | Enum    | The legal basis. **Can only be set at creation, and cannot be modified later.**                                             |
| `technical_name` | String  | External ID, for use by authenticated API only.                                                                             |
| `token`          | String  | External ID, for use when capturing choices from a website with the JavaScript tag.                                         |
| `community_id`   | String  | Processing entries are defined at community level.                                                                          |
| `archived`       | Boolean | Deactivates and hides a processing. No new choice can be attached to an archived processing, and it is no longer displayed. |

```json
{
  "id": "2",
  "community_id": "1125",
  "name": "Targeted advertising",
  "purpose": "Collecting navigation events to perform user profiling and broadcast targeted advertising",
  "legal_basis": "CONSENT",
  "technical_name": "mics-advertising-processing",
  "token": "mics-advertising-processing",
  "archived": false
}
```

{% hint style="info" %}
Note the two external IDs. `technical_name` is for authenticated API calls; `token` is what you put in a website tag, precisely because a tag runs in an untrusted environment.
{% endhint %}

### Create one

{% tabs %}
{% tab title="In the interface" %}
Go to **Settings > Organisation > Processing Activities** and use **New Data Processing**.

{% stepper %}
{% step %}

### Select the legal basis

This comes first because it determines the type of user choice you can capture - consent, consent refusal, or opposition. Once the processing is created, **the legal basis cannot be modified**, as choices may already have been captured.

What each basis implies is tabulated in [Define your privacy & compliance framework](/setup-and-monitor/ensure-privacy-and-compliance/define-your-privacy-and-compliance-framework.md#choosing-a-legal-basis).
{% endstep %}

{% step %}

### Define the rest

* The **name** that appears in the dropdown lists, for data ingestion and segmentation.
* The **purpose** of the processing, as exposed to your data subjects.
* The **technical name**, if you need an external key for integration.
  {% endstep %}
  {% endstepper %}
  {% endtab %}

{% tab title="By API" %}

```
POST https://api.mediarithmics.com/v1/processings
```

```json
{
  "community_id": "<your_community_id>",
  "name": "Analytics",
  "purpose": "Collecting navigation events to build aggregated reports on site usage",
  "legal_basis": "LEGITIMATE_INTEREST",
  "technical_name": "mics-analytics-processing",
  "token": "mics-analytics-processing"
}
```

Processings can be listed with `GET /v1/processings?community_id=:communityId`, and updated or deleted on `/v1/processings/:id`.
{% endtab %}
{% endtabs %}

## User choices

A **user choice** represents the choice a user makes for one of your processing activities.

Each time a user makes a choice, you send it as a user event named `$set_user_choice` with a set of metadata; it is then computed and stored. Choices can also be created directly by API.

```json
{
    "$processing_id": "1004",
    "$choice_ts": 1561622248000,
    "$choice_acceptance_value": true,
    "$creation_ts": 1561622248000,
    "$channel_id": "1234",
    "$choice_source_id": "1001",
    "$user_agent_id": "vec:123456789",
    "$compartment_id": "1234",
    "$user_account_id": "123456789",
    "$email_hash": {
        "$hash": "a1b2c3d4e5",
        "$email": "random@example.com"
    },
    "custom_property_1": "custom_value_1"
}
```

| Field                                                                      | Description                                                                                                                                                                                           |
| -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `$processing_id`                                                           | The processing activity concerned. Mandatory by API; set automatically from `$processing_token` on a `$set_user_choice` event.                                                                        |
| `$choice_ts`                                                               | When the choice was given by the user. Mandatory by API; set automatically from the event's `$ts`.                                                                                                    |
| `$choice_acceptance_value`                                                 | The acceptance value. Mandatory by API; set automatically from the event property of the same name.                                                                                                   |
| `$creation_ts`                                                             | **System field.** The creation timestamp of the choice. Cannot be modified, by API or by event.                                                                                                       |
| `$channel_id`                                                              | The channel the choice was collected on. Optional by API; set automatically from the [activity origin](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time.md#activity-origin). |
| `$choice_source_id`                                                        | The source of the choice. Optional by API; set automatically from `$choice_source_token`. See below.                                                                                                  |
| `$user_agent_id`, `$user_account_id` with `$compartment_id`, `$email_hash` | The identifiers. From a `$set_user_choice` event they are copied from the activity; through the `/user_choices` API they come from the request payload, or from the URL if the payload has none.      |
| *any custom property*                                                      | Optional. Set automatically from the event's custom properties - this is where the evidence of a valid consent lives.                                                                                 |

## Capture choices

Three integration types, each for a different situation.

{% tabs %}
{% tab title="Client-side JavaScript" %}
**Strongly recommended when you have a CMP on your website** capturing choices. It captures the choice at the source and at the moment it is made, with minimal integration cost.

The setup mirrors regular website tracking:

* Prepare a JavaScript snippet with a `$set_user_choice` event.
* Place it so that it is triggered **every time a user gives a choice on the CMP**.

When executed, the snippet loads the mediarithmics tag and a pixel that pushes the choice event. Server-side, the platform associates the choice with the user and the related processing activity.

See [Web tracking](/setup-and-monitor/collect-and-manage-your-data/collect-data-in-real-time/web-tracking.md).
{% endtab %}

{% tab title="File-based" %}
**Recommended when choices come from files** you export from another system - an initial load from a CRM or a back-end consent repository, for instance.

See [Import user consent](/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/import-user-consent.md) and [Import user choices](/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/import-user-choices.md).
{% endtab %}

{% tab title="API" %}
**Recommended when an application in your landscape acts as master data management** for user choices, storing them from several sources.

The platform exposes APIs to get, update, and delete a user choice for one user, based on any of their identifiers - including a change log endpoint for history. 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).

A choice can also be set directly on the UserPoint, without creating a user activity.
{% endtab %}
{% endtabs %}

## Privacy walls

A **privacy wall** uses user choices to automatically allow or block the processing of personal data for a given user. Walls exist at three levels, and **the rule differs by level**.

| Level           | What it controls                                                 | The rule                                                                                            |
| --------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| **Channel**     | `UPSERT` of user activities of type `SITE_VISIT` and `APP_VISIT` | The upsert is allowed if the user has allowed **at least one** of the linked processing activities. |
| **Compartment** | `UPSERT` of user profiles                                        | The upsert is allowed if the user has allowed **at least one** of the linked processing activities. |
| **Segment**     | Segment computation                                              | The user is allowed in the segment if they have allowed **all** the linked processing activities.   |

{% hint style="warning" %}
"At least one" on ingestion, "all" on segments. Linking many activities to a channel is permissive; linking many to a segment is restrictive.
{% endhint %}

Activities of type `TOUCH`, `EMAIL`, and `DISPLAY_AD` are **not covered yet**. User choices are **not supported** for the User Activation, User Lookalike, and Edge segment types.

To configure one, go to the settings of the object you want to link and add the processing activities. The channel and compartment procedures are in [Channels](/setup-and-monitor/plan-and-integrate/set-up-the-environment/set-up-channels.md) and [Compartments](/setup-and-monitor/plan-and-integrate/set-up-the-environment/set-up-compartments.md); the segment procedure is in the `Audience & Activation` section.

### What happens when a user changes their mind

This differs by object type, and the difference matters:

| Object                                                         | Effect of a changed choice                                                                                                                                                                                                                                                           |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Upserted data** - activities, profiles, `USER_LIST` segments | The decision to upsert or drop is taken **just before saving** into the datamart. **New upserts are blocked**, but data already captured is kept and follows the standard [cleaning rules](/setup-and-monitor/collect-and-manage-your-data/clean-and-delete-data/cleaning-rules.md). |
| **`USER_QUERY` segments**                                      | The segment query is automatically extended with conditions on user choices, so **the user exits the segment** - they no longer match the query.                                                                                                                                     |

For activities, the decision takes into account the presence of a `$set_user_choice` event **in the activity itself**, which is what makes the client-side integration work on a first visit.

## When several sources set the same choice

{% hint style="info" %}
Ask your mediarithmics contact to activate this feature if you need it.
{% endhint %}

When a new choice overwrites an existing one on the same processing, you may need a priority based on where the choice came from - user settings in a logged-in environment versus a CMP popup, or a direct exercise of rights versus a CMP cache in the browser.

The optional `$choice_source_id` field relates each choice to a reference table, which mediarithmics can create per client, giving each source a **weight**:

| id   | name                  | token                   | weight |
| ---- | --------------------- | ----------------------- | ------ |
| 1001 | CMP                   | `me-cmp_local`          | 1      |
| 1002 | Website user settings | `me-user_settings`      | 2      |
| 1003 | CRM file              | `me-member_crm_file`    | 2      |
| 1004 | Exercise of rights    | `me-exercise_of_rights` | 3      |

Set the source with `$choice_source_token` on a `$set_user_choice` event - the platform translates it into `$choice_source_id` - or with `$choice_source_id` directly on the `/user_choices` API.

How it affects updates:

* A choice collected via a `$set_user_choice` event overwrites the existing one **only if its source weight is equal to or higher** than the existing one's.
* **No choice source is equivalent to the lowest weight.**
* The rule is **not applied** to a choice updated through the authenticated datamart APIs.
* The rule is **not applied** in the case of a merge.

## Choices and UserPoint merges

Choices are taken into account when two UserPoints merge, but **choice updates never trigger a merge**.

For a given processing, choice change logs are merged like activities in the timeline. Among the active values, **the one with the latest `$creation_ts` is kept active** on the surviving UserPoint; the other is added to the change log.

## Declare choices in the schema

{% hint style="danger" %}
**User choices and their custom properties must be declared in the** [**schema**](/setup-and-monitor/collect-and-manage-your-data/design-your-data-model-and-schema/schema-definition.md) **for the feature to work.**
{% endhint %}

Any property can be indexed, and these four **should** be: `processing_id`, `choice_ts`, `creation_ts`, and `choice_acceptance_value`. The others - standard or custom - are mostly used to prove the validity of a choice, so indexing them may not be necessary.

```graphql
type UserPoint @TreeIndexRoot(index:"USER_INDEX") {
    id: ID!
    activity_events: [ActivityEvent!]!
    choices: [UserChoice!]!
}

type UserChoice {
    id: ID!
    processing_id: String! @TreeIndex(index:"USER_INDEX")
    choice_acceptance_value: Boolean! @TreeIndex(index:"USER_INDEX")
    choice_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
    creation_ts: Timestamp! @TreeIndex(index:"USER_INDEX")
    channel_id: String
    user_agent_id: String
    email_hash: String
    compartment_id: String
    user_account_id: String
    custom_field: String @Property(path: "custom_field")
}
```

## Auditing choices with OTQL

Once indexed, choices are queryable like anything else - which is how you answer an audit question or check a rollout before enforcing.

```sql
-- List all processings and their observed values
SELECT {
    processing_id @map {
        choice_acceptance_value @map
    }
}
FROM UserChoice

-- Count the users who accepted a processing
SELECT @count {}
FROM UserPoint
WHERE choices {
    processing_id = "1001"
    AND choice_acceptance_value = true
}

-- A choice-based segment
SELECT {id}
FROM UserPoint
WHERE [segment_query_conditions]
    AND choices {
        processing_id = "1001"
        AND choice_acceptance_value = true
    }
```

## Verify

* Every processing activity has a legal basis that matches what your CMP asks the user.
* `UserChoice` is declared in the published schema, with the four properties indexed.
* A count of accepting users returns a plausible number **before** you enforce any wall.
* After enforcing, ingestion volumes for the channel do not collapse. See [Monitor data ingestion](/setup-and-monitor/operate-and-monitor/monitor-data-ingestion.md).
* A test user who withdraws consent stops having new data stored, and exits `USER_QUERY` segments.

## 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 privacy &#x26; compliance framework</strong></td><td>The legal groundwork and the legal-basis table.</td><td><a href="/setup-and-monitor/ensure-privacy-and-compliance/define-your-privacy-and-compliance-framework.md">Define your privacy &amp; compliance framework</a></td></tr><tr><td><strong>Import user consent</strong></td><td>Loading the choices you already hold.</td><td><a href="/setup-and-monitor/collect-and-manage-your-data/import-data-in-batch/import-user-consent.md">Import user consent</a></td></tr><tr><td><strong>Exercise rights of the user</strong></td><td>Access and erasure requests.</td><td><a href="/setup-and-monitor/ensure-privacy-and-compliance/exercise-rights-of-the-user.md">Exercise rights of the user</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/ensure-privacy-and-compliance/manage-consent-and-processing-activities.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.
