Implement cookie consent in your SPA
Introduction
Goal
Implement cookie consent in a Bloomreach SPA SDK-based frontend application.
Background
Several Bloomreach Commerce Experience Cloud features, including the Discovery pixel and Content personalization, use cookies to store information about users. In many jurisdictions, this requires explicit consent from the user.
It is up to the frontend development team to implement cookie consent in their application. This page provides an example implementation for React frontends using the popular Osano Cookie Consent Javascript library.
Tip
A slightly different implementation using the react-cookie-consent library can be found in the Reference SPA.
Implementation
Add the Osano Cookie Consent library
Install the cookieconsent library in your application:
npm install cookieconsent
Add the Osano Cookie Consent CSS and Javascript to public/index.html
(just before the closing </head>
element):
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/cookieconsent@3/build/cookieconsent.min.css" />
<script src="https://cdn.jsdelivr.net/npm/cookieconsent@3/build/cookieconsent.min.js"></script>
Create a Cookie Consent utility library
Create a cookie consent utility library in src/utils/cookieconsent.ts
:
/* eslint-disable max-len */
declare global {
interface Window {
cookieconsent?: {
status: {
allow: 'allow';
deny: 'deny';
dismiss: 'dismiss';
};
initialise(
config: {
[key: string]: unknown;
onInitialise(status: keyof Required<Window>['cookieconsent']['status']): void;
onStatusChange(status: keyof Required<Window>['cookieconsent']['status']): void;
},
complete: (popup: Required<Window>['cookieconsent']['Popup']) => void,
): void;
utils: {
getCookie(name: string): string;
};
Popup: unknown;
};
}
}
const COOKIE_CONSENTS_EXPIRATION_VALUE = 28; // Days
export const isConsentReceived = (): boolean => {
const { cookieconsent } = window || {};
return !!cookieconsent && cookieconsent.utils.getCookie('cookieconsent_status') === cookieconsent.status.allow;
};
let isConsentInitialised = false;
const CookieConsentInit = (): void => {
if (isConsentInitialised) return;
window.cookieconsent?.initialise?.(
{
palette: {
popup: {
background: '#000',
},
button: {
background: '#f1d600',
},
},
cookie: {
expiryDays: COOKIE_CONSENTS_EXPIRATION_VALUE,
},
showLink: false,
type: 'opt-in',
onInitialise: (status) => {
if (status === window.cookieconsent?.status.allow) {
// add cookie consent dependent code that should run on start up
}
},
onStatusChange: (status) => {
if (status === window.cookieconsent?.status.allow) {
// add cookie consent dependent code that should run any time the status is changed
}
},
},
(popup) => {
isConsentInitialised = !!popup;
},
);
};
export default CookieConsentInit;
Notes:
- Use the Osana Cookie Consent configuration wizard to create your own custom configuration for the cookie consent popup. See the Osano Cookie Consent Javascript API for advanced options.
- You can add any code that depends on cookie consent and should run on the cookie consent library's initialization to the
onInitialise
callback hook. From the Osano Cookie Consent Javascript API:- "This is called on start up, with the current chosen compliance. It can be used to tell you if the user has already consented or not as soon as you initialise the tool."
- You can add any code that depends on cookie consent and should run when the cookie consent status changes to the
onStatusChange
callback hook. From the Osano Cookie Consent Javascript API:- "This is called any time the status is changed. This can be used to react to changes that are made to the compliance level. You can use the popup instance functions from within these callbacks too. I.E. ‘this.hasAnswered()’ and ‘this.hasConsented()’."
- See the example implementation for details on how segment-based content personalization can integrate cookie consent.
- You can import
isConsentReceived
elsewhere in your code and use it to conditionally render cookie content dependent components likeBrPixel
(see below).
Create a CookieConsent component
Create a CookieConsent
component in src/components/CookieConsent.tsx
:
import { useEffect } from 'react';
import CookieConsentInit, { isConsentReceived } from '../utils/cookieconsent';
interface CookieConsentProps {
isPreview: boolean;
path: string;
}
export const CookieConsent = ({ isPreview, path }: CookieConsentProps): null => {
useEffect(() => {
if (!isPreview) {
CookieConsentInit();
}
}, [isPreview]);
useEffect(() => {
if (!isPreview && isConsentReceived()) {
// add cookie consent dependent code that should run any time the page is rendered
}
}, [path, isPreview]);
return null;
};
Note:
- You can add any code that depends on cookie consent and should run each time the page is rendered within the
if (!isPreview && isConsentReceived()) { }
condition insideCookieConsent
.
In src/components/index.ts
, add:
export * from './CookieConsent';
Add the Cookie Consent popup to your app
In src/App.tsx
, add CookieConsent
to the list of components imported from './components':
import {
/* existing components */
CookieConsent,
} from './components';
Then add the following somewhere within you <BrPage>
element to render the cookie consent popup:
<BrPageContext.Consumer>
{(page) => <CookieConsent isPreview={!!page?.isPreview()} path={configuration.path ?? '/'} />}
</BrPageContext.Consumer>
Conditional rendering of components depending on cookie consent
Optionally, also add to src/App.tsx
:
import { isConsentReceived } from './utils/cookieconsent';
Then use isConsentReceived()
to toggle cookie consent dependent components like BrPixel
. For example:
{({ smAccountId, smDomainKey }) =>
isConsentReceived() && (
<BrPixel
accountId={smAccountId ?? ''}
domainKey={smDomainKey ?? ''}
page={page!}
pageType="search"
pageLabels="pacific,nut,bolt,commerce"
type="pageview"
/>
)
}
Summary
The example implementation presented on this page provided four ways to handle code that requires cookie consent:
- Code depending on cookie consent that should run on the cookie consent library's initialization → place in the cookieconsent utility library inside the
onInitialise
callback hook. - Code depending on cookie consent that should run when the cookie consent status changes → place in the cookieconsent utility library inside the
onStatusChange
callback hook. - Code depending on cookie consent that should run each time a page is rendered → place in the CookieConsent component inside the
if (!isPreview && isConsentReceived()) { }
condition. - Frontend components that should only be rendered if cookie consent is accepted → import
isConsentReceived
from the cookieconsent utility library and use as condition for rendering.
Updated about 1 month ago