DEVCON 2026    |    2-5 November 2026 – QEII Centre – London, UK    |    Register now! 

Blogs

Cookie Consent Management

A Developer’s Guide to Cookie Consent and the New CMP Integration in 2026.Q3

David H Nebinger
David H Nebinger
10 من الدقائق قراءة

Cookies are one of those web technologies that start simple and become complicated very quickly.

Setting a cookie is easy. The difficult part is deciding whether you are allowed to set it, explaining what it is used for, recording the visitor's consent, preventing code from running before that consent exists, and making sure backend behavior follows the same decision.

Liferay has built-in support for cookie consent management and has continued expanding it over recent releases. It can present a cookie banner and configuration panel, categorize cookies, control whether consent-sensitive cookies are created, and provide a Cookie Policy page showing visitors what cookies the site uses.

Starting with Liferay DXP 2026.Q3, there is another important option: integrating Liferay with an external Consent Management Platform, or CMP.

That is particularly useful for organizations that already use products such as OneTrust, Cookiebot, Didomi, Usercentrics, or another enterprise CMP across their web properties.

Before getting to that new integration, though, it helps to understand how Liferay thinks about cookie consent in the first place.

Liferay's Cookie Consent Model

Liferay divides cookies into four consent categories:

The important part for developers is that these categories are more than labels displayed in a cookie banner. They are part of Liferay's cookie handling APIs.

Your application can tell Liferay:

I want to create this cookie, but it is a Functional cookie.

Liferay can then determine whether the visitor's consent permits it.

Liferay's Built-In Consent Manager

Liferay includes its own Consent Manager. It provides the cookie banner and configuration panel visitors use to select which types of cookies they want to allow.

It can operate in two basic modes. With Explicit Cookie Consent Mode enabled, non-essential cookies wait until the visitor explicitly permits them. Without it, cookies are enabled until the visitor opts out.

Recent releases have added capabilities such as consent renewal periods, storing authenticated users' consent preferences, Global Privacy Control support, and a floating control that lets users reopen their consent preferences.

Liferay's built-in Consent Manager is not intended to be a complete enterprise CMP with capabilities such as vendor scanning, automated compliance workflows, or multi-domain consent management.

For some sites, Liferay's built-in capabilities are exactly what is needed.

For others, particularly larger organizations with multiple websites and an established privacy program, consent may already be managed by an external CMP.

We'll get to that shortly.

Creating Consent-Aware Cookies

If you are writing custom functionality that creates cookies, you should not bypass Liferay and write the cookie directly.

For example, this works in a browser:

document.cookie = 'my-preference=true';

But Liferay has no opportunity to enforce the visitor's cookie preference before that cookie is created.

Instead, use Liferay's consent-aware cookie APIs.

From JavaScript

For client-side code, Liferay.Util.Cookie.set() accepts the cookie's consent type.

For example, suppose a custom feature stores an optional display preference:

const expires = new Date();

expires.setFullYear(expires.getFullYear() + 1);

const cookieSet = Liferay.Util.Cookie.set(
  'my-display-preference',
  'compact',
  Liferay.Util.Cookie.TYPES.FUNCTIONAL,
  {
    expires,
    secure: true,
  }
);

The available types correspond to Liferay's four consent categories:

  • Liferay.Util.Cookie.TYPES.NECESSARY
  • Liferay.Util.Cookie.TYPES.FUNCTIONAL
  • Liferay.Util.Cookie.TYPES.PERFORMANCE
  • Liferay.Util.Cookie.TYPES.PERSONALIZATION

The important difference is that Liferay can now take the visitor's consent into account before the cookie is created.

That means custom code should generally prefer the Liferay API over document.cookie when creating cookies subject to consent.

From Java

Server-side code has the same capability.

Liferay exposes CookiesManagerUtil.addCookie() with a consent type:

import com.liferay.portal.kernel.cookies.CookiesManagerUtil;
import 
  com.liferay.portal.kernel.cookies.constants.CookiesConstants;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public void addPreferenceCookie(
  HttpServletRequest httpServletRequest,
  HttpServletResponse httpServletResponse) {

  Cookie cookie = new Cookie(
    "my-display-preference", "compact");

  cookie.setHttpOnly(true);
  cookie.setMaxAge(365 * 24 * 60 * 60);
  cookie.setPath("/");

  CookiesManagerUtil.addCookie(
    CookiesConstants.CONSENT_TYPE_FUNCTIONAL,
    cookie,
    httpServletRequest,
    httpServletResponse,
    true);
}

The available consent constants are:

  • CookiesConstants.CONSENT_TYPE_NECESSARY
  • CookiesConstants.CONSENT_TYPE_FUNCTIONAL
  • CookiesConstants.CONSENT_TYPE_PERFORMANCE
  • CookiesConstants.CONSENT_TYPE_PERSONALIZATION

The important engineering decision is choosing the correct category.

If your feature works perfectly well without the cookie, calling it Necessary just to make sure it gets created defeats the purpose of the consent model.

Don't Forget the Cookie Policy

Controlling whether a cookie can be created is only part of the implementation.

Visitors should also be able to find out what that cookie does.

Liferay provides a Cookie Policy utility page containing sections for the same four categories. The page lists cookies along with their purpose and duration.

When your application introduces a cookie that Liferay does not already know about, add it to the appropriate section of the Cookie Policy page:

  1. Navigate to Site Administration → Site Builder → Pages.
  2. Open the Cookie Policy utility page.
  3. Locate the appropriate cookie category.
  4. Click Add.
  5. Enter the cookie's information and save it.

So if we create:

my-display-preference

as a Functional cookie, it should also be documented in the Functional section of the Cookie Policy.

That gives us both parts of the contract:

Third-Party Content Is Slightly Different

Your code is not always the code creating the cookie.

Consider an embedded analytics script, YouTube video, map, chat client, or another external service.

Once the browser loads that resource, the third party may create cookies of its own.

For that case, Liferay provides the Third-Party Cookie API. This API has been available since DXP 2024.Q1/Portal GA112.

Suppose we normally have:

<iframe
  src="https://video.example.com/embed/12345"
></iframe>

The problem is that the browser immediately loads that URL.

Instead, we can write:

<iframe
  data-src="https://video.example.com/embed/12345"
  data-third-party-cookie="CONSENT_TYPE_FUNCTIONAL"
></iframe>

Liferay watches the DOM for data-third-party-cookie. If the corresponding consent exists, the resource can be loaded. Otherwise, it remains blocked.

The same idea works with scripts:

<script
  data-third-party-cookie="CONSENT_TYPE_PERFORMANCE"
  src="https://analytics.example.com/analytics.js"
  type="text/plain"
></script>

Using type="text/plain" keeps the browser from executing the script normally. Liferay can activate it when the corresponding consent exists.

For resources such as images, embeds, and iframes, src becomes data-src. For links, href becomes data-href.

At this point, Liferay has a fairly complete internal model:

But there is still one important question.

What happens when you're not using Liferay to manage cookie consent, and you're using another consent management platform instead? How do you get Liferay to display that provider's cookie banner and consume the resulting consent details?

That is where one of the new capabilities in Liferay DXP 2026.Q3 comes in.

New in 2026.Q3: External CMP Integration

Liferay DXP 2026.Q3 introduces the ability to integrate a third-party Consent Management Platform directly into Liferay.

You may encounter pieces of this functionality behind development or beta feature flags in earlier releases. Those earlier implementations were incomplete, so I would treat 2026.Q3 as the practical starting point for using the CMP integration.

This feature is especially interesting for organizations that have already standardized on an enterprise CMP.

Instead of replacing that platform with Liferay's Consent Manager, Liferay can participate in the consent architecture that already exists.

The configuration is available under:

Global Menu → Control Panel → Instance Settings → Privacy → Third-party Consent Management Platform

The configuration contains:

  • Provider Name
  • Script Tag
  • Consent Mapping Script
  • Enabled

The vendor's Script Tag is the same sort of installation code the CMP would normally ask you to place in the <head> of your website. Liferay renders it for you, allowing the CMP to load and display its own consent interface.

There Are Really Two Systems Involved

Adding the CMP script gets its banner onto the page.

But that does not automatically tell Liferay what the visitor selected.

The architecture looks more like this:

The CMP still owns the consent experience.

It can handle things such as:

  • regional rules,
  • consent presentation,
  • vendor configuration,
  • cookie scanning,
  • audit records,
  • and whatever other capabilities the CMP provides.

Liferay only needs the result.

CONSENT_STATE: The Contract Between the CMP and Liferay

Liferay normalizes the external CMP's decision into a cookie named:

CONSENT_STATE

The value is URL-encoded JSON containing Liferay's four consent categories.

Decoded, it looks like this:

{
  "CONSENT_TYPE_FUNCTIONAL": true,
  "CONSENT_TYPE_NECESSARY": true,
  "CONSENT_TYPE_PERFORMANCE": false,
  "CONSENT_TYPE_PERSONALIZATION": false
}

The Consent Mapping Script is responsible for translating whatever model the external CMP uses into this model.

Conceptually, the mapping looks like this:

function writeLiferayConsent(state) {
  const value = encodeURIComponent(JSON.stringify(state));

  let attributes =
    '; Path=/; SameSite=Lax; Max-Age=31536000';

  if (location.protocol === 'https:') {
    attributes += '; Secure';
  }

  document.cookie =
    `CONSENT_STATE=${value}${attributes}`;
}

function updateFromCMP(cmpConsent) {
  writeLiferayConsent({
    CONSENT_TYPE_NECESSARY: true,
    CONSENT_TYPE_FUNCTIONAL: cmpConsent.functional,
    CONSENT_TYPE_PERFORMANCE: cmpConsent.analytics,
    CONSENT_TYPE_PERSONALIZATION: cmpConsent.personalization,
  });
}

That code is intentionally generic.

The interesting part is not writing CONSENT_STATE.

It is this:

  • cmpConsent.functional
  • cmpConsent.analytics
  • cmpConsent.personalization

Every CMP represents those concepts differently.

Liferay Handles the Script Ordering

One subtle but useful part of the implementation is how Liferay renders these scripts.

Liferay renders the CMP's Script Tag first, followed by the Consent Mapping Script, both in the page <head>.

That ordering lets the mapping script subscribe to the mechanisms provided by the CMP.

Depending on the vendor, that might mean:

window.addEventListener(...)

or:

CMP.on(...)

or:

CMP.getConsentDetails().then(...)

or registering a callback into a queue that the CMP processes when it finishes initializing.

This is an important detail because CMPs typically load asynchronously. A good integration has to handle both the initial page load and subsequent changes to consent.

Why Map Consent Back to Liferay?

Some CMPs can automatically prevent analytics and other scripts from running until the visitor consents.

If that covers everything your site requires, the CMP may already be enforcing a large part of the client-side behavior.

But Liferay itself also makes decisions based on consent.

A good example is Remember Me.

REMEMBER_ME is categorized as a Functional cookie.

If the external CMP says that Functional cookies are not allowed and the mapping script writes:

{
  "CONSENT_TYPE_FUNCTIONAL": false
}

Liferay's backend will not create the REMEMBER_ME cookie during sign-in, even if the visitor selected the Remember Me option.

That is why the mapping matters.

Now the same consent decision can influence external scripts, custom Liferay code, and Liferay's own backend behavior.

One Default Behavior Worth Knowing

There is one implementation detail worth paying attention to during testing.

If CONSENT_STATE is:

  • missing,
  • malformed, or
  • missing one of its keys,

Liferay treats the corresponding consent type as granted. Necessary consent is always honored.

That makes the startup behavior of the external CMP important.

If the CMP uses automatic script blocking, it may already prevent anything sensitive from executing while consent is unknown.

If you are relying on CONSENT_STATE itself as part of the enforcement model, however, make sure your mapping establishes the intended state at initialization rather than waiting only for the user to change something.

Liferay Provides Examples for Popular CMPs

Fortunately, you do not have to approach every CMP integration from a blank JavaScript file.

Liferay provides documented Consent Mapping Script examples for several widely used platforms:

CMP What the Example Shows
Cookiebot Maps Necessary, Preferences, and Statistics into Liferay's consent model
CookieScript Maps Strict, Functionality, Performance, and Targeting categories
Didomi Demonstrates mapping project-specific purposes into Liferay categories
OneTrust Maps OneTrust category IDs into Liferay consent types
Osano Maps Essential, Analytics, and Personalization
Termly Handles Termly's combined category model
Usercentrics Demonstrates integration with the current Usercentrics v3 API

I think these examples are one of the most useful parts of the feature because they demonstrate both sides of the integration:

You will still need to verify the mapping against your own CMP configuration.

For example, OneTrust commonly uses category IDs such as C0001, C0002, C0003, and C0004, but those IDs are configurable per tenant. Confirm the actual category configuration used by your environment.

Didomi takes a different approach. Its consent system is purpose-based and those purpose IDs are specific to your Didomi project, so the mapping must use the IDs configured for that environment.

Usercentrics v3 provides direct equivalents for Essential and Functional by default, while Performance and Personalization require you to decide how your particular configuration should map them.

These differences are exactly why having a mapping layer is valuable.

Liferay does not have to understand every category model that every CMP vendor invents.

It only has to understand:

  • Necessary
  • Functional
  • Performance
  • Personalization

The Mapping Script Is an Adapter

Architecturally, I think the best way to look at the Consent Mapping Script is as an adapter.

That separation has another advantage.

Suppose the organization switches from one CMP to another.

Your fragments can still say:

<div
  data-third-party-cookie="CONSENT_TYPE_PERFORMANCE"
>
  ...
</div>

Your Java code can still say:

CookiesConstants.CONSENT_TYPE_FUNCTIONAL

Your JavaScript can still say:

Liferay.Util.Cookie.TYPES.PERFORMANCE

Those applications do not need to know whether the consent came from Cookiebot, OneTrust, Usercentrics, or something else.

Only the mapping between the external CMP and Liferay changes.

That is a much cleaner dependency boundary than spreading vendor-specific consent logic throughout the application.

Don't Enable Two (or more) Consent Managers

There is one configuration mistake that is particularly easy to make while experimenting with the new feature.

Do not leave both Liferay's built-in Consent Manager and an external CMP enabled.

Liferay does not prevent you from doing this, but both consent banners can then be displayed.

Pick one system to own the user-facing consent experience.

If you are integrating an external CMP, that platform should normally own the banner and consent interaction.

Liferay becomes a consumer and enforcer of the resulting consent state.

Testing the Integration

Cookie consent testing is one of those cases where a normal browser window can create misleading results.

Consent is intentionally persistent. Your browser may already have the CMP's cookies, Liferay's cookies, local storage entries, or other state from an earlier test.

You can manually clear all of that, but there is an easier approach.

Use a private or incognito browser window for consent testing.

Closing the private session and opening another one gives you a predictable fresh visitor without having to remember which cookies or storage entries need to be removed.

I would test the integration in four stages.

1. Test the Initial Visit

Open the site in a new private or incognito session.

Verify that the external CMP's banner appears and that Liferay's built-in banner does not.

If both appear, check which consent managers are enabled.

2. Test Different Consent Decisions

Do not test only Accept All.

Try:

  • rejecting all optional cookies,
  • enabling only Functional,
  • enabling Performance but not Personalization,
  • changing an earlier decision,
  • and accepting everything.

If your CMP's categories do not line up exactly with Liferay's, pay particular attention to the combinations affected by your mapping decisions.

3. Inspect CONSENT_STATE

After each choice, open the browser's developer tools and inspect:

CONSENT_STATE

URL-decode the value and confirm that it matches what you expect.

For example:

{
  "CONSENT_TYPE_FUNCTIONAL": true,
  "CONSENT_TYPE_NECESSARY": true,
  "CONSENT_TYPE_PERFORMANCE": false,
  "CONSENT_TYPE_PERSONALIZATION": false
}

4. Test the Behavior, Not Just the Cookie

A correct JSON value is useful, but it is not the real test.

If Performance consent is false, verify that the analytics script actually remains blocked.

If Functional consent is false, test Remember Me.

If the user changes consent after the page has loaded, verify that CONSENT_STATE changes too.

Then close the private browser session, start a new one, and repeat the test.

The full path you want to verify is:

Cookie Consent Is Now an Integration Point

Liferay's cookie support has several layers, and they solve different problems.

If you are creating your own cookie, use Liferay's consent-aware cookie APIs.

If your page loads third-party content that may create cookies, classify that content using data-third-party-cookie.

If you introduce a new cookie, document it in the Cookie Policy utility page.

If Liferay owns the consent experience, use the built-in Consent Manager.

And starting with Liferay DXP 2026.Q3, if your organization already has an external CMP, you can let that platform continue owning the consent experience while Liferay consumes the decision.

The resulting architecture is straightforward:

For me, that is the interesting part of this new 2026.Q3 feature.

You do not have to choose between using your organization's existing CMP and taking advantage of Liferay's consent-aware cookie handling.

The CMP can remain the authority for collecting consent, while Liferay uses that decision everywhere it needs to enforce it.

And because the integration boundary is Liferay's four-category consent model rather than a particular vendor, your Liferay applications do not need to become OneTrust applications, Cookiebot applications, or Usercentrics applications.

They remain Liferay applications.

The mapping layer handles the difference.

تعليقات الصفحة

Related Assets...

لا توجد نتائج

More Blog Entries...

David H Nebinger
سبتمبر ٢٣, ٢٠٢٦
Victor Ware
سبتمبر ١٥, ٢٠٢٦