# Share consents across devices

## Introduction

The Didomi CMP supports syncing to allow consent sharing across devices and environments. Consent can be shared between all environments that have syncing enabled in the same organization: multiple websites, multiple apps (same or multiple devices), multiple websites and apps together, etc.

When syncing is enabled and an organization user ID is available, if the user is visiting the page for the first time and no sync has taken place, the Didomi CMP will load the previously stored user choices from the Consents API and will apply them locally. In the case the user had already received data from the sync process, their local data will be updated from the server after the duration of time defined by the sync frequency has elapsed relative to the last time sync was completed.

If the sync request duration exceeds the timeout setting, we use the local consent and will attempt to sync on the next SDK initialization (page reload).

{% hint style="info" %}
Syncing is currently a premium feature. You can schedule a meeting with our Support team [through the console](https://support.didomi.io/how-to-enable-cross-device-from-didomi-console) to enable the feature for your account. See [this](https://support.didomi.io/how-to-enable-cross-device-from-didomi-console) article for more information.
{% endhint %}

{% hint style="warning" %}
We do not support the cross device feature for AMP sites due to the single consent status limitation of the [framework](https://developers.didomi.io/amp#amp-limitations).
{% endhint %}

## Configuration

### How to share an organization user ID with Didomi?

For the sync process to work properly, a `user.organizationUserId` property needs to be set in the Didomi configuration object:

```javascript
window.didomiConfig = {
  user: {
    organizationUserId: 'organization_user_id',
  }
};
```

This value represents the unique identifier with which the organization identifies the user for which it wants to sync the consents. This can be an email address, a user ID, etc. We recommend hashing the value to not communicate plain user IDs to Didomi.

This must be set before the Didomi Web SDK is embedded onto the page.

You need extra steps to authenticate the user ID on the Didomi side so please read on to complete your configuration.

### Which organization user ID to share with Didomi?

When the user is identified by the website through a login process or any other authentication method, a unique user ID should be shared with the Didomi SDK through the `window.didomiConfig` object.\
\
The unique user ID can be any string but we recommend sending a hashed version of your internal user ID to not expose any sensitive data on the page or to Didomi. Avoid sharing plain email addresses, user names, etc. with Didomi.

The same unique user ID will need to be shared in other environments like mobile apps. If you are sending a hashed ID, make sure that you will be able to send exactly the same ID across all environments.

{% hint style="info" %}
The user ID shared on the website will be used as the organization user ID in our [Consents API](https://developers.didomi.io/api-and-platform/consents/users). If you are accessing the user status or event from the API, you will need to specify the same user ID as what is shared on the website, including any form of anonymization or hashing method in place.\
\
The organization user ID must be consistent across your organization and all the other Didomi products you are using (APIs, Privacy Center, etc.).
{% endhint %}

### Authentication with a hash digest

{% hint style="warning" %}
**Note**: Sending authentication with a hash digest is required to share an end-user's consent across devices.
{% endhint %}

As the user ID is provided in a public environment (on a webpage), we need to authenticate it to guarantee that users cannot freely read and write consents for any user ID.

To authenticate the user ID and prove that it was authorized by the website, you will need to compute a hash digest of the user ID concatenated with a secret. This digest must be computed directly by your server in an authenticated context and not on the client-side. When it receives a request, Didomi will re-compute the digest with the secret and make sure that it matches the digest that you provided.

{% hint style="danger" %}
Using a hash digest does not guarantee the confidentiality of the user ID passed to Didomi as it is exposed in clear text on the page.
{% endhint %}

The hash digest should be provided in the `user.organizationUserIdAuthDigest` property. You will also need to provide the ID of the secret and the hashing algorithm used for generating the hash digest.

Example:

```javascript
<script type="text/javascript">
window.didomiConfig = {
  user: {
    organizationUserId: 'organization_user_id',
    organizationUserIdAuthDigest: MD5('organization_user_id' + 'secret'),
    organizationUserIdAuthSid: 'secret_id',
    organizationUserIdAuthAlgorithm: 'hash-md5'
  }
};
</script>
```

Note that the digest is computed on the concatenation of the user ID and the secret, without any extra space added. Example: `organization_user_idsecret`

#### Secrets

When computing a hash digest, a secret needs to be used. Secrets can be managed through the Didomi API to obtain an actual secret and its associated ID. [Read our documentation](https://developers.didomi.io/api/consents/secrets) to manage secrets for your organizations.

#### Hashing methods

Didomi supports the following methods for computing a digest:

| Algorithm   | ID            | Description                                                             |
| ----------- | ------------- | ----------------------------------------------------------------------- |
| Hash MD5    | `hash-md5`    | Hexadecimal digest computed with the MD5 algorithm                      |
| Hash SHA1   | `hash-sha1`   | Hexadecimal digest computed with the SHA1 algorithm                     |
| Hash SHA256 | `hash-sha256` | Hexadecimal digest computed with the SHA256 algorithm                   |
| HMAC SHA1   | `hmac-sha1`   | Hexadecimal representation of a HMAC computed with the SHA1 algorithm   |
| HMAC SHA256 | `hmac-sha256` | Hexadecimal representation of a HMAC computed with the SHA256 algorithm |

For all methods, the content to compute the digest on and the secret are the same. The method ID must be provided in the `organizationUserIdAuthAlgorithm` property.

#### Salting

For increased security, you can use a salt when computing the hash digest. You will need to provide the salt in the configuration so that Didomi can use it when verifying the user ID.

Example:

```javascript
<script type="text/javascript">
window.didomiConfig = {
  user: {
    organizationUserId: 'organization_user_id',
    organizationUserIdAuthDigest: MD5('organization_user_id' + 'secret'),
    organizationUserIdAuthSid: 'secret_id',
    organizationUserIdAuthAlgorithm: 'hash-md5',
    organizationUserIdAuthSalt: 'salt'
  }
};
</script>
```

#### Information expiration

The authentication methods guarantee the integrity of the information (i.e., the information originates from the client and cannot be modified by a third-party) but do not guarantee that information cannot be reused.

To prevent reusing an encrypted user identifier, we support the addition of expiration information. You can mark the information as having an expiration date so that it cannot be used after a certain date using the `organizationUserIdExp` parameter. This should be a valid Unix timestamp value.

Example:

```javascript
<script type="text/javascript">
window.didomiConfig = {
  user: {
    organizationUserId: 'organization_user_id',
    organizationUserIdAuthDigest: MD5('organization_user_id' + 'secret' + 'salt'),
    organizationUserIdAuthSid: 'secret_id',
    organizationUserIdAuthAlgorithm: 'hash-md5',
    organizationUserIdAuthSalt: 'salt',
    organizationUserIdExp: 1628714229
  }
};
</script>
```

{% hint style="info" %}
The rules for hashing/encrypting are:

If using a hash algorithm, the digest is computed as `hash('organization_user_id' + 'secret' + 'salt' + expiration)`, where `salt` and `expiration` are optional values.

If using an HMAC algorithm, the digest is computed as `hmac('organization_user_id' + 'salt' + expiration, 'secret')`, where `salt` and `expiration` are optional values. The `secret` is not part of the digest, although it is used in the HMAC process.
{% endhint %}

## Enabling sync

The sync process can be enabled with the `sync.enabled` configuration option in the Didomi configuration object:

```javascript
window.didomiConfig = {
  user: {
    organizationUserId: 'organization_user_id',
  },
  sync: {
    enabled: true
  }
};
```

## Behavior

### Frequency

By default, the sync process will run once every day. The value in seconds for the sync process can be specified via the `frequency` configuration option.

```javascript
window.didomiConfig = {
  user: {
    organizationUserId: 'organization_user_id',
  },
  sync: {
    enabled: true,
    frequency: 86400
  }
};
```

{% hint style="warning" %}
The `frequency` interval is 24 hours by default (86,400 seconds). It should not be necessary to set this to a lower threshold. Lower settings can negatively impact the user experience as page load times would be impacted by syncing intervals being too low and sync occurring when unnecessary.
{% endhint %}

{% hint style="danger" %}
The minimum frequency interval is 6 hours (21,600 seconds). If you set the frequency interval to a lower value, it will be overridden to 6 hours.
{% endhint %}

### Sync timeout

The maximum time allowed for the syncing process to be completed can be specified using the `sync.timeout` configuration option in the Didomi configuration object:

```javascript
window.didomiConfig = {
  user: {
    organizationUserId: 'organization_user_id',
  },
  sync: {
    enabled: true,
    timeout: 3000
  }
};
```

{% hint style="warning" %}
The `timeout` duration is set to 3 seconds (3,000 milliseconds) by default. It should not be necessary to increase this threshold.
{% endhint %}

The `sync.timeout` configuration option accepts an integer which represents the maximum time allowed (in milliseconds) for the syncing process to be completed.

If the syncing process takes longer to complete than specified in the `sync.timeout` configuration option, the initialization continues as if there was no data to sync.

### Delaying the display of the notice

The Didomi CMP enables delaying the display of the notice while the sync is in progress. This ensures that the user never sees the consent notice if syncing succeeds.

The `sync.delayNotice` configuration option can be used for delaying the notice showing until the sync is complete:

```javascript
window.didomiConfig = {
  user: {
    organizationUserId: 'organization_user_id',
  },
  sync: {
    enabled: true,
    delayNotice: true
  }
};
```

## Confirmation notice

If desired, your organization can surface a confirmation notice in order to communicate to end-users that their local consent has been synced from the Didomi backend when using cross device. The confirmation notice is an optional configuration.

{% hint style="info" %}
The design and interaction of the confirmation notice is developed and implemented by your organization.
{% endhint %}

Refer to the tabs below for how to implement your confirmation notice for single page applications and non-single page applications:

{% tabs %}
{% tab title="SPA" %}
When implementing a confirmation notice for a single page application, your organization should look at the `statusApplied` property returned from [`syncUser()`](https://developers.didomi.io/cmp/web-sdk/reference/api#syncuser) . When `statusApplied` is `true` then the end-user's local consent was synced from the Didomi backend and you should show your confirmation notice.

```javascript
const syncResult = await Didomi.syncUser();

// The end-user status actually changed from syncing
if (syncResult.statusApplied) {
  // Show your reassurance notice

  // Report the reassurance notice was shown to Didomi after dismiss
  syncResult.syncAcknowledged();
}
```

{% endtab %}

{% tab title="non-SPA" %}
When implementing a confirmation notice for a non-single page application, your organization should listen for the [`sync.ready`](https://developers.didomi.io/cmp/web-sdk/reference/events#sync.ready) event and check the `statusApplied` property. When the `statusApplied` property is `true` then the end-user's local consent was synced from the Didomi backend and you should show your confirmation notice.

{% hint style="warning" %}
**Note**: In the example below the `sync-modal` HTML and CSS is already included on the page.
{% endhint %}

```javascript
window.didomiEventListeners = window.didomiEventListeners || [];

window.didomiEventListeners.push({
  event: "sync.ready",
  listener: function ({ statusApplied, syncAcknowledged, syncError }) {
    // Only proceed if status was applied from remote backend
    if (!statusApplied) {
      return;
    }

    // Optional: handle sync error case
    if (syncError) {
      console.error("Didomi sync error:", syncError);
    }

    // Show modal; you should use your own HTML/CSS elements
    var modal = document.getElementById("sync-modal");
    var closeBtn = document.getElementById("sync-modal-close");
    if (!modal || !closeBtn) {
      console.warn("Sync modal elements not found");
      // Still acknowledge to avoid blocking tracking
      syncAcknowledged();
      return;
    }

    modal.style.display = "block";

    // When user confirms, hide modal and acknowledge sync
    var onClose = function () {
      modal.style.display = "none";
      closeBtn.removeEventListener("click", onClose);
      // Notify Didomi that the sync has been communicated to the user
      var result = syncAcknowledged();
      console.log("syncAcknowledged result:", result);
    };

    closeBtn.addEventListener("click", onClose);
  },
});
```

{% endtab %}
{% endtabs %}

## Summary

Given the information above, assuming that:

* the `organization_user_id` is set;
* the `sync.enabled` is `true`; and,
* the user is not a bot

If the sync is not completed within the timeout interval, the Web SDK does not store the sync timestamp in the Didomi token (cookie).

On the next page load, the SDK will try to sync again. If the sync is not successful, the Web SDK will continue based on the current state and will not show the notice if the consent was previously given and stored in the cookies.

We will re-sync under the following conditions:

* If the sync timestamp and frequency are both present, we sync if the sync date is older than the frequency (in seconds); or
* If the sync timestamp or the frequency is missing (undefined).


---

# Agent Instructions: Querying This Documentation

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

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.didomi.io/cmp/web-sdk/share-consents-across-devices.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
