A modern, drop-in GDPR-style cookie consent banner for OutSystems Reactive Web. It shows a first-visit banner with equally-prominent Accept / Reject / Customize options, remembers the user's choice, lets them change or withdraw it any time, records every choice for accountability, and gives you a simple HasConsent() check to gate your own tracking scripts.
HasConsent()
Platform: OutSystems 11 (O11) · Type: Reactive Web · Curation target: Community / Trusted
This component helps you implement a consent mechanism. It does not, by itself, make your app compliant with GDPR, ePrivacy, CCPA, or any other law, and nothing here is legal advice. You remain responsible for knowing which cookies and scripts your app uses, writing an accurate cookie/privacy policy, choosing the correct legal basis, and confirming your setup with your own legal or data-protection advisor. Use this component as the UI and plumbing; the compliance decisions are yours.
Cookie Consent puts a configurable consent banner on every screen of your app. On a user's first visit it asks how they want their data handled; it then stores that choice so it doesn't ask again until your policy changes or the choice expires. You gate your non-essential scripts (analytics, marketing, etc.) behind a simple consent check, and every choice is optionally logged to an entity for your records.
OnConsentChanged
Showing a banner is not the same as complying. The real requirement is that non-essential cookies and scripts must not run until the user consents. So the important part of this component isn't the banner — it's the consent gate. Use HasConsent("analytics") (or the OnConsentChanged event) to decide when to initialize your tracking, and don't fire those scripts until consent is granted.
HasConsent("analytics")
Two rules the component is built to respect: Reject must be as easy as Accept (the buttons share one style and size), and users must be able to withdraw consent as easily as they gave it (the re-open link).
.oap
HasConsent
OpenPreferences
CookieCategory
PolicyURL
CookieConsent
PolicyVersion
"1.0"
ExpiryDays
180
BannerText
EnableAudit
True
GrantedCategories
CategoryKey
"analytics"
"marketing"
"functional"
Granted
"necessary"
No parameters. Reopens the preferences panel showing the user's current choices, so they can change or withdraw consent.
The component ships four standard categories via the CookieCategory static entity:
necessary
functional
analytics
marketing
Necessary requires no consent under most regimes and is always granted; everything else defaults to off until the user opts in. (Custom categories are a planned enhancement.)
The banner reappears automatically when any of these is true: the user has never chosen; the stored PolicyVersion differs from the current one (so bumping the version re-prompts everyone after a policy change); or the stored choice is older than ExpiryDays. Otherwise the banner stays hidden and the app uses the remembered choice.
When EnableAudit is on, every choice writes a ConsentRecord with: a generated consent id, the categories granted, the policy version, the action taken (Accept All / Reject All / Custom / Withdraw), and the timestamp. This gives you an accountability trail if you're ever asked to demonstrate consent. By design it stores no IP address or personal identifiers — keep it that way unless you have a specific, documented reason and legal basis to add them.
ConsentRecord
// Only initialize analytics once the user has allowed it If HasConsent("analytics") → run your analytics init logic
Or react to changes at the moment the user decides:
Handle CookieConsent.OnConsentChanged(GrantedCategories): If HasConsent("marketing") → enable marketing tags Else → disable them
Never place your tracking so that it runs before this check.
The banner and preferences panel ship with a modern look — a floating card, pill buttons, a frosted modal, subtle entrance animation, full responsiveness, and a reduced-motion fallback. All colors are driven by CSS variables, so you can rebrand the whole component by overriding a single value in your app's theme:
/* Match the banner to your brand color */ .occ-banner, .occ-panel { --occ-accent: #7c3aed; }
The available variables are --occ-accent, --occ-accent-hover, --occ-surface, --occ-text, --occ-muted, and --occ-border. Override any of them to fit your design system; leave them alone for the default green theme.
--occ-accent
--occ-accent-hover
--occ-surface
--occ-text
--occ-muted
--occ-border
The banner shows every visit.Make sure the block is placed once on the shared Layout (not re-mounted per screen in a way that resets state), and that the client variables aren't being cleared. Also check ExpiryDays isn't set very low.
The banner never shows.A stored choice already exists for the current PolicyVersion. Bump PolicyVersion (or clear the browser's site data) to see it again.
My analytics still runs after Reject.The component doesn't stop scripts on its own — you must gate them with HasConsent / OnConsentChanged. Anything not behind that check will still run.
Users can't change their mind.Add the "Cookie settings" link calling OpenPreferences, ideally in the footer on every page.
Preferences open but show default choices instead of the saved ones.This means the current consent isn't being read when the panel opens. Ensure OpenPreferences refreshes the panel's category state before showing it.
Published on the OutSystems Forge as open, reusable code. Free to use and adapt in your OutSystems projects.