> For the complete documentation index, see [llms.txt](https://developers.didomi.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.didomi.io/cmp/web-sdk/share-consents-across-devices.md).

# Share consents across devices

{% hint style="success" %}
Sharing consents across devices (i.e. cross-device consent sync) is a premium feature. Contact your Didomi representative to enable the feature for your organization.
{% endhint %}

The Didomi cross-device consent feature enables your organization to sync an end-user's consent selections across multiple devices and environments. Consent can be shared between all environments that have syncing enabled within the same organization: multiple websites, multiple apps (same or multiple devices), multiple websites and apps together, etc...

* [Prerequisites](#prerequisites)
* [Cross-device consent sync overview](#cross-device-consent-sync-overview)
* [Configure user authentication](#configure-user-authentication)
* [Enable cross-device consent sync](#enable-cross-device-consent-sync)
* [Confirmation notice](#confirmation-notice)

{% hint style="warning" %}
**Note**: Didomi does not support cross-device consent sync for AMP sites due to its s[ingle consent status limitation](/cmp/amp.md#amp-limitations).
{% endhint %}

***

### Prerequisites

Ensure your organization meets the following criteria before continuing:

* Premium feature cross-device consent sync is enabled for your organization's Didomi account
* Websites and apps that will share consent utilize a unique identifier to identify an individual end-user in your organization's system (e.g. email, phone number, CRM ID, etc.)

### Cross-device consent sync overview

Once cross-device consent sync is successfully configured, syncing end-user consent selections will be managed via the Didomi Consents API. For each website, device, or app where syncing is enabled and the end-user's organization user ID is available in the Didomi server:

* If the end-user is visiting the website, device, or app for the first time and a sync has not taken place, Didomi will load the previously stored end-user's consent (identified from their organization user ID) via the Consents API and apply them locally.
* If the end-user already has consent data from the sync stored locally, the local data will be updated from the server via Consents API once the time configured for the sync frequency has lapsed relative to the last completed sync
* If the sync request duration exceeds the configured timeout setting, Didomi will use the locally stored consent and will attempt a sync with Didomi servers once the window for sync frequency has elapsed.

<figure><img src="/files/9EetiHNOP62MzOHS2x9k" alt="" width="563"><figcaption></figcaption></figure>

### Configure user authentication

In order to successfully sync an end-user's consent from the Didomi server with a website, app, device, Didomi needs to be able to identify the end-user.

When an end-user is identified by your organization (e.g. via a login process or other authentication method), this unique user ID should be shared with the Didomi SDK in the `window.didomiConfig` object via the `user.organizationUserId` property. This must be set before the Didomi Web SDK is embedded onto the page.

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

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

While the `organizationUserID` value can be any string (e.g. email, phone number, etc...), Didomi recommends sending a hashed version of this value to avoid exposing any potential sensitive data on page or to 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.

In addition to configuring the end-user's `organizationUserId`, your organization will also need to configure a hash digest.

* [Authentication with a hash digest](#authentication-with-a-hash-digest)
* [Supported hashing methods](#supported-hashing-methods)
* [Salting](#salting)
* [Information expiry](#information-expiry)
* [Hashing/encrypting rules](#hashing-rules)

#### 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 %}

Since the `organizationUserId` is provided in a public environment (on a webpage), we need to authenticate the value to guarantee that users cannot freely read and write consents for any `organizationUserId`.

In order to authenticate the `organizationUserId` and prove that it was authorized by the website, your organization will need to include the following hash digest in the `user` object. This digest must be computed directly by your server in an authenticated context and not on the client-side.

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

<table><thead><tr><th width="317.5">Property</th><th>Description</th></tr></thead><tbody><tr><td><pre><code>organizationUserIdAuthDigest
</code></pre></td><td><p>Computed hash digest of the ID concatenated with a secret. Secrets can be managed through the Didomi API to obtain an actual secret and its associated ID. <a href="/pages/-M29CkuzI0FBVr2ypyzM">Click here</a> to learn more about secrets.</p><div data-gb-custom-block data-tag="hint" data-style="warning" class="hint hint-warning"><p><strong>Note</strong>: The hash digest is computed on the concatenation of the <code>organization_user_id</code> and the <code>secret</code>, without any extra space added. Example: <code>organization_user_idsecret</code>.</p><p>Review <a href="#hashing-rules">Didomi hashing/encrypting rules</a> for more information on hash digest.</p></div></td></tr><tr><td><pre><code>organizationUserIdAuthSid
</code></pre></td><td>ID of the secret. Secrets can be managed through the Didomi API to obtain an actual secret and its associated ID. <a href="/pages/-M29CkuzI0FBVr2ypyzM">Click here</a> to learn more about secrets.</td></tr><tr><td><pre><code>organizationUserIdAuthAlgorithm
</code></pre></td><td>ID of the hashing algorithm used to generate the hash digest. <a href="#supported-hashing-methods">Click here</a> for more information on supported hashing methods</td></tr></tbody></table>

{% tabs %}
{% tab title="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>
```

{% endtab %}
{% endtabs %}

When Didomi receives a request, we will re-compute the digest with the secret and ensure that it matches the digest that your organization has provided.

#### Supported hashing methods

Didomi supports the following methods for computing a digest:

<table><thead><tr><th width="181">Algorithm</th><th width="154">ID</th><th>Description</th></tr></thead><tbody><tr><td>Hash MD5</td><td><code>hash-md5</code></td><td>Hexadecimal digest computed with the MD5 algorithm</td></tr><tr><td>Hash SHA1</td><td><code>hash-sha1</code></td><td>Hexadecimal digest computed with the SHA1 algorithm</td></tr><tr><td>Hash SHA256</td><td><code>hash-sha256</code></td><td>Hexadecimal digest computed with the SHA256 algorithm</td></tr><tr><td>HMAC SHA1</td><td><code>hmac-sha1</code></td><td>Hexadecimal representation of a HMAC computed with the SHA1 algorithm</td></tr><tr><td>HMAC SHA256</td><td><code>hmac-sha256</code></td><td>Hexadecimal representation of a HMAC computed with the SHA256 algorithm</td></tr></tbody></table>

#### Salting

Salting is the optional practice of adding a value (the "salt") to a value before computing the hash digest to increase security. If your organization utilizes salting when computing its hash digest then include the salt in `user.organizationUserIdAuthSalt`.

{% tabs %}
{% tab title="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>
```

{% endtab %}
{% endtabs %}

#### Information expiry

Authentication methods guarantee the integrity of the information sent to Didomi (i.e. the information originates from the client and cannot be modified by a third-party) but does not guarantee that the information cannot be reused.

In order to prevent the reuse of an encrypted end-user identifier, Didomi allows your organization to provide an optional expiry so that the identifier can no longer be used after a certain date. If your organization wishes to set an expiration date on an end-user identifier, include a valid Unix timestamp in `user.organizationUserIdExp`.

{% tabs %}
{% tab title="Example" %}

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

{% endtab %}
{% endtabs %}

#### Hashing/encrypting rules

Review the table below for more information on hashing/encrypting rules:

<table><thead><tr><th width="188">Algorithm</th><th>Digest</th></tr></thead><tbody><tr><td>Hash algorithm</td><td><p>Computed as: <code>hash('organization_user_id' + 'secret' + 'salt' + expiration)</code></p><div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><code>salt</code> and <code>expiration</code> are optional values.</p></div></td></tr><tr><td>HMAC algorithm</td><td><p>Computed as <code>hmac('organization_user_id' + 'salt' + expiration, 'secret')</code><br></p><div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><code>salt</code> and <code>expiration</code> are optional values. The <code>secret</code> is not part of the digest although it is used in the HMAC process.</p></div></td></tr></tbody></table>

### Enable cross-device consent sync

Once the `user` object is appropriately configured, enable cross-device consent sync by setting `sync.enabled` to `true` in the `window.didomiConfig` object.

{% code overflow="wrap" %}

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

{% endcode %}

In the sections below we will cover different behaviors that your organization can configure for cross-device consent sync:

* [Frequency](#frequency-1)
* [Sync timeout](#sync-timeout)
* [Consent notice delay](#consent-notice-delay)

#### Frequency

The `sync.frequency` property enables your organization to configure how often (in seconds) the sync process will run on the website. By default, the sync process is performed every 24 hours (86,400 seconds).

<table><thead><tr><th width="104.5"></th><th width="192">Frequency</th><th>Comments</th></tr></thead><tbody><tr><td><strong>Default</strong></td><td>24 hrs (86,400 secs)</td><td>Didomi recommends leaving the frequency at 24 hrs. More frequent syncs (e.g. every 8 hours) can negatively impact the end-user experience of your website since page load times would be impacted by frequent unnecessary syncs.</td></tr><tr><td><strong>Minimum</strong></td><td>6 hrs (21,600 secs)</td><td>Any frequency interval set to lower than 6 hours will be overridden to the minimum threshold of 6 hours.</td></tr></tbody></table>

{% code overflow="wrap" %}

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

{% endcode %}

#### Sync timeout

The `sync.timeout` property enables your organization to configure the maximum time allowed (in milliseconds) for the syncing process to be completed. If the syncing process takes longer than the configured time then the initialization continues as if there was no data to sync.

{% hint style="warning" %}
**Note**: By default, `sync.timeout` is set to 3 seconds (3,000 milliseconds). Didomi believes it should not be necessary to increase this threshold.
{% endhint %}

{% code overflow="wrap" %}

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

{% endcode %}

#### Consent notice delay

{% hint style="warning" %}
**Note**: `sync.delayNotice` is set to `true` by default. Omitting the property will still delay the consent notice from displaying until the sync process is complete.
{% endhint %}

The `sync.delayNotice` property enables your organization to delay the consent notice from displaying until the sync process is complete. By delaying the consent notice display you can ensure that the end-user will not see a consent notice if the sync process successfully retrieves their consent selections from Didomi servers.

{% code overflow="wrap" %}

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

{% endcode %}

### Confirmation notice

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

A confirmation notice is an optional configuration your organization can implement to communicate to end-users that their local consent has been synced from the Didomi servers.

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

{% 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 Didomi servers and the confirmation should be displayed.

```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 Didomi servers and the confirmation notice should be shown.

{% 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 %}


---

# 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 dynamically by asking a question.

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

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
