Handling users' cookie consent
Fetch stored cookie preferences from logged-in users and sync them to your CMP
Users set cookie consent choices in Upod. After they log in on your site, you can read those choices and apply them to your cookie banner or Consent Management Platform (CMP).
This works differently from anonymized profile data. Cookie preferences do not require a separate data-access grant in the user's vault. If the user is logged in, you can always fetch them.
When to use this
- Your site has a cookie banner or CMP and you want logged-in Upod users to skip re-consenting
- You run OneTrust (or plan to) and want Upod preferences synced automatically
- You already use Upod for login and want consent to follow the user across sites
Prerequisites
- A working Upod integration with an authenticated session (any getting started path works)
- A cookie banner or CMP on your site, unless you only need the raw preference values
Fetching cookie preferences
The simplest approach is client.getConsent(). It returns each category as a boolean, or null when the user is not logged in or has not saved preferences yet.
const client = upod.initialize({
authority: 'https://account.upod.eu',
client_id: 'your-client-id',
redirect_uri: location.origin + location.pathname,
post_logout_redirect_uri: location.origin + location.pathname,
});
client.handleCallbackIfNeeded();
client.onLogin(async () => {
const consent = await client.getConsent();
if (consent) {
applyCookiePreferences(consent);
}
});
client.onConsentChange(consent => {
if (consent) {
applyCookiePreferences(consent);
}
});onConsentChange fires after login, logout, tab focus, and when the user edits preferences in their vault. You can also listen for the upod:consentchange DOM event.
If you need the raw DPV values from the storage API, call client.fetch() directly. No purpose query parameter is required.
const raw = await client.fetch({
path: '/storage/cookies',
method: 'get',
});See the Cookie preferences reference for the full response schema and TCF mapping table.
Applying preferences manually
Map the boolean values from getConsent() to your CMP categories. Essential cookies are always on in Upod and are not returned by the API:
function applyCookiePreferences(consent) {
enableEssentialCookies();
if (consent.cookiesAndSimilar) {
enableStorageCookies();
} else {
disableStorageCookies();
}
if (consent.advertising) {
enableAdCookies();
} else {
disableAdCookies();
}
if (consent.measurement) {
enableAnalytics();
} else {
disableAnalytics();
}
}CMP adapters
If your site already runs a CMP, you can sync Upod preferences automatically instead of mapping fields yourself. Adapters ship as separate bundles so sites that do not use that CMP do not download extra code.
Each adapter calls client.getConsent() under the hood and refetches on login, logout, tab focus, and vault edits.
OneTrust
Load the main Upod bundle and the OneTrust adapter:
<script src="https://cdn.upod.eu/client/bundle.browser.js"></script>
<script src="https://cdn.upod.eu/client/upod-onetrust.browser.js"></script>Create the adapter after initializing the client:
const client = upod.initialize({
authority: 'https://account.upod.eu',
client_id: 'your-client-id',
redirect_uri: location.origin + location.pathname,
post_logout_redirect_uri: location.origin + location.pathname,
});
upodOneTrust.createOneTrustAdapter({
client,
mode: ['groups'],
mapping: {
cookiesAndSimilar: 'C0002',
measurement: ['C0002', 'C0003', 'C0004'],
advertising: 'C0003',
personalisedContent: 'C0003',
other: ['C0002', 'C0003'],
socialMedia: 'C0004',
},
alwaysOn: ['C0001'],
onLogout: 'keep',
});The OneTrust adapter is not included in bundle.browser.js, so non-OneTrust sites do not download it.
In a bundled app:
import { initialize } from '@datakluis/client-lib';
import { createOneTrustAdapter } from '@datakluis/client-lib/adapters/onetrust';
const client = initialize({
/* ... */
});
createOneTrustAdapter({
client,
mode: ['groups'],
mapping: {
cookiesAndSimilar: 'C0002',
measurement: ['C0002', 'C0003', 'C0004'],
advertising: 'C0003',
personalisedContent: 'C0003',
other: ['C0002', 'C0003'],
socialMedia: 'C0004',
},
alwaysOn: ['C0001'],
onLogout: 'keep',
});Modes
| Mode | What it does |
|---|---|
groups | Maps Upod categories to OneTrust group codes and calls OneTrust.UpdateConsent("Category", payload), then OneTrust.Close() if the banner is still open. |
dataLayer | Pushes normalized consent to window.dataLayer for Tealium or Load Rules. |
Use both when you need group-level sync in OneTrust and purpose-level handling in Tealium:
upodOneTrust.createOneTrustAdapter({
client,
mode: ['groups', 'dataLayer'],
mapping: {
/* ... */
},
dataLayer: { key: 'upodConsent' },
});Shared OneTrust groups
Several Upod categories can map to the same OneTrust group even though they cover different TCF purposes, for example measurement, advertising, personalisedContent, and other all touch C0003. The OneTrust JS API only supports group-level toggles, so you cannot turn individual categories on independently through the API.
- A shared group is on only if every category mapped to it is granted. The visitor has to opt in to all the Upod categories a group needs before it turns on.
dataLayermode: keep every category distinct in Tealium instead of relying on OneTrust group-level toggles.
Reading consent from OneTrust
The adapter also works the other way: it can read the visitor's OneTrust choice and convert it to Upod cookie preferences. createOneTrustAdapter() returns the adapter, so you can keep a reference:
const adapter = upodOneTrust.createOneTrustAdapter({
client,
mode: ['groups'],
mapping: {
/* ... */
},
alwaysOn: ['C0001'],
});
// null until the visitor has made a choice in OneTrust
const consent = adapter.read();
const unsubscribe = adapter.onChange(consent => {
console.log('OneTrust choice as Upod preferences', consent);
});
// open the OneTrust banner or preference center
adapter.showBanner();| Method | OneTrust API used | What it does |
|---|---|---|
adapter.read() | OneTrust.IsAlertBoxClosed(), OnetrustActiveGroups | Returns the current choice as Upod preferences, or null when there is no choice yet. |
adapter.onChange(cb) | OneTrust.OnConsentChanged() | Calls cb with Upod preferences whenever the visitor changes their OneTrust choice. Returns an unsubscribe function. |
adapter.showBanner() | OneTrust.ToggleInfoDisplay() | Opens the OneTrust UI. |
onChange ignores the changes the adapter makes itself when it applies Upod consent, so the two directions do not loop.
The conversion reuses your mapping. Every active OneTrust group turns on all Upod categories mapped to it, so that group stays on when Upod consent is applied back to OneTrust. With the mapping above, an active C0003 grants measurement, advertising, personalisedContent and other. A category is granted when any group it maps to is active.
Because OneTrust works per group and Upod per category, the conversion is lossy. Upod preferences that went to OneTrust come back unchanged in OneTrust terms. A OneTrust choice that does not line up with your mapping, such as C0002 on with C0004 off, can grant a category that a switched off group also covers. Let the visitor review their preferences before you save them to their Upod.
Outside the adapter, the same conversion is available as upodOneTrust.buildConsentFromOneTrustGroups(activeGroups, mapping), with upodOneTrust.parseOneTrustActiveGroups(window.OnetrustActiveGroups) to turn the OneTrust string into a list.
Forwarding the OneTrust choice to registration
When a visitor answers the OneTrust banner and then signs up with Upod, you can carry their choice into the registration flow so they do not have to fill in their cookie preferences again. Set forwardConsentToRegister: true:
const client = upod.initialize({
/* ... */
widget: 'hidden',
show_when_not_logged_in: true,
open_frequency_cap: 5,
frequency_cap_duration: '2w',
});
const adapter = upodOneTrust.createOneTrustAdapter({
client,
mode: ['groups'],
mapping: {
/* ... */
},
alwaysOn: ['C0001'],
forwardConsentToRegister: true,
});
// open the Upod widget once the visitor has answered OneTrust,
// at most 5 times per two weeks
adapter.onChange(async () => {
if (!(await client.isAuthenticated())) client.openWithFrequencyCap();
});The adapter converts every OneTrust choice to Upod preferences and passes it to client.setRegisterConsent(). When the visitor clicks Register in the widget, the redirect includes:
| Query parameter | Value |
|---|---|
additionalProfile | cookies |
cookieSource | cmp, so choices made in your CMP are counted separately from choices made in a Upod cookie screen |
cookiePreferences | acceptAll when every category is granted, rejectAll when none are, otherwise customize |
cookieCategories | Only with customize: the granted categories, e.g. cookiesAndSimilar,measurement |
The registration flow uses these values to fill in the cookie preferences and skips the cookie screens. Without cookieCategories, cookiePreferences=customize still opens the customize screen. An explicit cookiePreferences passed to client.register(), for example by the cookie modal, takes precedence.
Demo
See the live Upod widget + OneTrust example for a working demo with the real OneTrust banner. Logged-in Upod users skip the banner because the adapter applies their preferences and closes it. Other visitors see the banner with the Upod widget on top, and their OneTrust choice is carried into registration. After a OneTrust choice the widget opens at most 5 times per two weeks, see Limiting how often the widget opens.
Notes
- Authentication required. Cookie preferences are fetched in the browser with an active Upod session. If your backend needs the values, see Server-side and backend use.
- Handle failures gracefully. If the fetch fails, show your normal cookie banner.
- Keep mappings in sync. Your
mappingobject must match the group codes configured in your OneTrust admin panel.
Next steps
- Read the Cookie preferences reference for field names, TCF mapping, and raw API types
- Browse the API Reference for
client.getConsent()andclient.onConsentChange() - Try the live examples in your browser