Ship-ready reference for integrators using the standalone JavaScript build of AesirX CMP. Covers init/config, events, feature Opt‑In, vendor recipes (GA4, YouTube, Google Maps, Intercom), CSP guidance, QA checklists, and ISO/IEC 27560 mapping.
1. Getting Started
Include & Initialize
- Include the CMP bundle (self-hosted recommended)
<script src="/assets/aesirx-consent.min.js" defer></script>- Initialize AFTER the bundle has loaded
<script>
// Holdback definitions (executed after user consent)
// There are 5 available categories:
// - essential
// - functional
// - analytics
// - advertising
// - custom
//
// "name" can be customized to describe your specific integration.
window.aesirxHoldBackJS = [
{
category: "analytics",
name: "Google Analytics",
script: () => {
// Load google analytics script
console.log("analytics scripts");
},
},
{
category: "advertising",
name: "Google Tag Manager",
script: () => {
// Load Google Tag Manager script
console.log("Tag Manager scripts");
},
},
// Add more vendor entries here...
];
window.funcAfterConsent = () => {
// These will load only after the user has given consent
console.log("user consented");
};
window.funcAfterReject = () => {
// These will load only after the user has reject consent
console.log("user rejected consent");
};
</script>Read full setup instructions
2. Events
All events are dispatched on window as CustomEvents.
| Event Name | Defines category for hold back js |
| aesirxHoldBackJS | User grants consent |
| funcAfterConsent | User withdraws consent |
| funcAfterReject | When it fires |
3. Feature Opt‑In (per‑feature modal)
Use Opt‑In when a specific feature (e.g., payment, embedded map, video, chat) needs consent at the moment of use.
Global (vanilla JS)
<button data-optin-open="payment">Enable payment</button>
<script>
window.optInConsentData = [
{
title: "payment",
content:
"<div>We need consent to enable payment (explain vendor & purpose).</div>",
handleAccept: async function () {
// run payment feature logic here
},
handleReject: async function () {
// run alert reject feature here
},
replaceAnalyticsConsent: false,
},
];
// Semantic trigger—no direct class toggles
document.addEventListener("click", (e) => {
const t = e.target.closest("[data-optin-open]");
if (t)
document.querySelector(".opt-in-consent.payment").classList.add("show");
});
</script>NextJS
Create a provider for Opt-In Consent
import { createContext, useContext, useEffect, useState } from "react";
import dynamic from "next/dynamic";
const OptInConsent = dynamic(
() => import("aesirx-consent").then((module) => module.OptInConsent),
{
ssr: false,
loading: () => <></>,
}
);
// Expose handleOpen + isConsentPayment for consumption anywhere in the app
const ConsentContext = createContext({
handleOpen: undefined,
isConsentPayment: false,
});
const ConsentContextProvider = ({ children }) => {
return <ConsentContextApp>{children}</ConsentContextApp>;
};
const ConsentContextApp = ({ children }) => {
const [showModal, setShowModal] = useState(false); // Controls if modal is visible
const [isConsentPayment, setIsConsentPayment] = useState(false); // Track if user already consented
/**
* handleOpen()
* - This function is used to trigger the opt-in modal.
* - You can call this anywhere in your application using useConsentContext().
*/
const handleOpen = () => {
setShowModal(true);
};
/**
* handleConsentPayment()
* - Triggered when the user ACCEPTS the opt-in consent.
* - Sets isConsentPayment to true and closes the modal.
* - You can also persist the status here if needed.
*/
const handleConsentPayment = () => {
setIsConsentPayment(true);
setShowModal(false);
};
/**
* handleRejectPayment()
* - Triggered when the user REJECTS consent.
* - The modal is simply closed without applying consent.
*/
const handleRejectPayment = () => {
setShowModal(false);
};
/**
* useEffect()
* - Runs on first load of the page.
* - Checks if payment consent was already granted during this session.
* - If true → skip showing modal and treat as already consented.
*/
useEffect(() => {
if (sessionStorage.getItem("aesirx-analytics-optin-payment") === "true") {
handleConsentPayment();
}
}, []);
return (
<ConsentContext.Provider
value={{
handleOpen,
isConsentPayment,
}}
>
<OptInConsent
optInConsentData={[
{
title: "payment",
content: `<div>YOUR_CONTENT_INPUT_HERE</div>`,
show: showModal,
handleConsent: handleConsentPayment,
handleReject: handleRejectPayment,
},
// ... You can add more opt-in consent modals depending on your needs
]}
/>
{children}
</ConsentContext.Provider>
);
};
const useConsentContext = () => useContext(ConsentContext);
export { ConsentContextProvider, useConsentContext };To enable the opt-in consent modal globally in your application, you need to wrap your root component with ConsentContextProvider. This makes the consent state and the handleOpen() trigger function available anywhere in your app via useConsentContext().
// Replace "path/to/ConsentContext" with the actual path to your file,
// for example: "@/context/ConsentContext" or "../context/ConsentContext"
import { ConsentContextProvider } from "path/to/ConsentContext";
<ConsentContextProvider>
<Component {...pageProps} />
</ConsentContextProvider>Trigger opt-in consent modal from a component
ReactJS
Create a provider for Opt-In Consent
import { createContext, useContext, useEffect, useState } from "react";
import dynamic from "next/dynamic";
const OptInConsent = dynamic(
() => import("aesirx-consent").then((module) => module.OptInConsent),
{
ssr: false,
loading: () => <></>,
}
);
// Expose handleOpen + isConsentPayment for consumption anywhere in the app
const ConsentContext = createContext({
handleOpen: undefined,
isConsentPayment: false,
});
const ConsentContextProvider = ({ children }) => {
return <ConsentContextApp>{children}</ConsentContextApp>;
};
const ConsentContextApp = ({ children }) => {
const [showModal, setShowModal] = useState(false); // Controls if modal is visible
const [isConsentPayment, setIsConsentPayment] = useState(false); // Track if user already consented
/**
* handleOpen()
* - This function is used to trigger the opt-in modal.
* - You can call this anywhere in your application using useConsentContext().
*/
const handleOpen = () => {
setShowModal(true);
};
/**
* handleConsentPayment()
* - Triggered when the user ACCEPTS the opt-in consent.
* - Sets isConsentPayment to true and closes the modal.
* - You can also persist the status here if needed.
*/
const handleConsentPayment = () => {
setIsConsentPayment(true);
setShowModal(false);
};
/**
* handleRejectPayment()
* - Triggered when the user REJECTS consent.
* - The modal is simply closed without applying consent.
*/
const handleRejectPayment = () => {
setShowModal(false);
};
/**
* useEffect()
* - Runs on first load of the page.
* - Checks if payment consent was already granted during this session.
* - If true → skip showing modal and treat as already consented.
*/
useEffect(() => {
if (sessionStorage.getItem("aesirx-analytics-optin-payment") === "true") {
handleConsentPayment();
}
}, []);
return (
<ConsentContext.Provider
value={{
handleOpen,
isConsentPayment,
}}
>
<OptInConsent
optInConsentData={[
{
title: "payment",
content: `<div>YOUR_CONTENT_INPUT_HERE</div>`,
show: showModal,
handleConsent: handleConsentPayment,
handleReject: handleRejectPayment,
},
// ... You can add more opt-in consent modals depending on your needs
]}
/>
{children}
</ConsentContext.Provider>
);
};
const useConsentContext = () => useContext(ConsentContext);
export { ConsentContextProvider, useConsentContext };To enable the opt-in consent modal globally in your application, you need to wrap your app with ConsentContextProvider. This makes the consent state and the handleOpen() trigger function available anywhere in your app via useConsentContext().
- If using CRA → index.js
- If using Vite → main.jsx
Trigger opt-in consent modal from a component
import { useConsentContext } from "path/to/ConsentContext";
const EnablePaymentButton = () => {
const { handleOpen } = useConsentContext();
return <button onClick={handleOpen}>Consent Payment</button>;
};
export default EnablePaymentButton;4. Opt‑In Consent: End‑to‑End Example (Vanilla)
A minimal, production‑safe example showing a feature Opt‑In for payment with clear Accept/Reject flows and a semantic trigger.
<!-- Trigger somewhere in your UI -->
<button data-optin-open="payment" class="btn">Enable payment</button>
<!-- Optional inline fallback (hidden by default) -->
<div data-feature-fallback="payment" hidden>
Payment is unavailable until you provide consent.
</div>
<script>
// 1) Define the Opt‑In item (as an ARRAY, not a string)
window.optInConsentData = [
{
title: "payment",
content:
"<p>We use a third‑party payment provider. Accept to enable checkout.</p>",
handleAccept: async function () {
// Execute your payment bootstrap here
initPaymentWidget();
},
handleReject: async function () {
const fb = document.querySelector('[data-feature-fallback="payment"]');
if (fb) fb.hidden = false;
},
replaceAnalyticsConsent: false,
},
];
// 2) Semantic trigger to open the Opt‑In
document.addEventListener("click", (e) => {
const t = e.target.closest("[data-optin-open]");
if (t)
document.querySelector(".opt-in-consent.payment").classList.add("show");
});
// Example payment bootstrap (replace with your real code)
function initPaymentWidget() {
if (window.__paymentLoaded) return;
window.__paymentLoaded = true;
const s = document.createElement("script");
s.src = "https://payments.example.com/widget.js";
s.async = true;
if (window.__cspNonce) s.nonce = window.__cspNonce;
document.head.appendChild(s);
}
</script>5.Vendor Recipes
Now that your CMP is installed and configured, you can start adding vendor integrations.
6. Content Security Policy (CSP)
Provide your users a working baseline:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-<server-nonce>' https://www.googletagmanager.com https://www.google-analytics.com https://www.youtube-nocookie.com https://widget.intercom.io;
frame-src 'self' https://www.youtube-nocookie.com;
connect-src 'self' https://region1.google-analytics.com https://api-iam.intercom.io https://nexus-websocket-a.intercom.io;
img-src 'self' data: https://i.ytimg.com;
style-src 'self' 'unsafe-inline'; /* or nonce your inline styles */7. Accessibility & UX
- Modal: role, aria-labelledby, aria-describedby, focus trap, ESC to close.
- Keyboard path to Accept/Reject. No alert() for rejections; use inline fallbacks.
- Clear purpose descriptions; no pre‑ticked toggles.
- Respect GPC where required; reflect status in UI text.
8. Appendix - ISO/IEC 27560 Mapping (Consent Receipt)
AesirX CMP maintains first‑party consent logs compatible with 27560 fields. Typical record fields:
| Field (ISO/IEC 27560) | AesirX CMP Field / Note |
| Controller Identifier | First‑party site/app identifier |
| Data Subject Identifier | Pseudonymous session ID (no direct personal data) |
| Purpose(s) | purposes map (essential, functional, analytics, advertising, custom) |
| Processing Basis | Consent (granular) |
| Consent Status | Given / Withdrawn / Updated |
| Timestamp | ms since epoch |
| UI Version / Policy Hash | version + policy/notice hash (configurable) |
| Signals | GPC honored (boolean + region context) |
| Proof Artifacts | Internal log refs; optional ZKP receipt (future‑ready) |
Export profile: Provide an exporter to output JSON/CSV for audits. (If using ZK proofs, store the proof receipt hash and reference to on‑chain anchor.)
10. Embedding in Popular CMS & Ecommerce (Generic)
The standalone bundle works anywhere you can inject HTML/JS. Prefer self‑hosting and add CSP nonces if your site uses a strict CSP.
WordPress (theme/site without plugin)
- Where: header.php (or via a Code Snippets plugin) for bundle include; initialize in a small inline




