# CMP JavaScript SDK
Dieses Dokument beschreibt die Einbindung des öffentlichen CMP-Bundles (`/cmp/v1/cmp.js`), Script-/Iframe-Blocking, Google Consent Mode v2, IAB TCF 2.3/GPP und das `window.cmp`-API.
> Der globale Name liegt in einer Konstante (`CmpBrand::WINDOW_API` / `SDK_NAME`). Aktuell: **`cmp`**. Später umbenennbar, ohne Logik zu ändern.
## Installation (Snippet)
**Das CMP-Script muss als Erstes in `<head>` stehen.** Statische Tags *vor* dem CMP können nicht gestoppt werden (Auto-Blocking-Limitation).
```html
<script>
window.cmp = window.cmp || { q: [] };
window.__CMP_BASE__ = {
apiBase: "https://IHRE-CMP-DOMAIN",
propertyKey: "PROPERTY_PUBLIC_KEY"
};
window.dataLayer = window.dataLayer || [];
function gtag(){ dataLayer.push(arguments); }
gtag("consent", "default", {
ad_storage: "denied",
ad_user_data: "denied",
ad_personalization: "denied",
analytics_storage: "denied",
functionality_storage: "denied",
personalization_storage: "denied",
security_storage: "granted",
wait_for_update: 500
});
</script>
<script src="https://IHRE-CMP-DOMAIN/cmp/v1/cmp.js" async></script>
```
Aufrufe vor dem Laden werden über die Queue `cmp.q` bzw. Stub-Methoden (`consentAll`, `show`, `on`, …) gespeichert und nach dem Boot abgespielt.
Optional: `window.__CMP_BASE__.country = "US"` (Demo/Tests) oder Server-Header `CF-IPCountry` / `Bunny-Country-Code` / `X-Country`. Query `?country=US` am Config-Endpoint.
## Manuelles Blocking
```html
<script type="text/plain" data-cmp-vendor="755" src="https://example.com/tag.js"></script>
<script type="text/plain" data-cmp-custom="hotjar">/* inline */</script>
<script type="text/plain" data-cmp-purposes="1,3" src="…"></script>
<iframe data-cmp-src="https://www.youtube.com/embed/…" data-cmp-custom="youtube"></iframe>
```
Nach Consent werden Scripts neu erzeugt (damit sie ausführen), Attribute und Reihenfolge bleiben erhalten. Blockierte Iframes zeigen einen Platzhalter mit „Inhalt laden“.
## Auto-Blocking
MutationObserver + Patch von `document.createElement` / `appendChild` / `insertBefore` halten Scripts/Iframes/Img-Pixel zurück, deren Host in Custom-Vendor-Domains oder der Tracker-Domain-Map liegt. Nach Consent: Release. Nach Ablehnen/Widerruf: bekannte Cookies der nicht freigegebenen Vendoren werden gelöscht (Namen/Muster aus der Vendor-Config).
**Limitation:** CMP muss zuerst in `<head>` stehen; bereits geladene Tags davor sind nicht stoppbar.
## API (`window.cmp`)
| Methode | Beschreibung |
|---------|--------------|
| `consentAll()` | Alle Zwecke/Vendoren akzeptieren (gleicher Pfad wie Button: TC-String, Cookie, Consent-Log, GCM, Unblock) |
| `declineAll()` | Ablehnen / Opt-out |
| `show()` | Banner/Einstellungen erneut öffnen |
| `getConsent()` | Snapshot: purposes, vendors, customVendors, regime, tcString, gppString, … |
| `hasConsent(vendorIdOrCustomKey)` | `cmp.hasConsent(755)` oder `cmp.hasConsent("hotjar")` |
| `on(event, cb)` / `off` | Events: `ready`, `consent`, `shown`, `hidden` |
| `setLanguage(lang)` | Config neu laden mit Sprache (z. B. `"fr"`) |
### Beispiele
```js
cmp.on("ready", () => console.log(cmp.getConsent()));
cmp.on("consent", (snap) => console.log("consent", snap));
document.querySelector("#accept").onclick = () => cmp.consentAll();
document.querySelector("#privacy").onclick = () => cmp.show();
```
## `__tcfapi` / `__gpp`
- EU/UK/CH: IAB TCF stub + CmpApi (`__tcfapi`).
- US (`gpp_us`): minimales `__gpp` mit US National Section (Opt-out). `navigator.globalPrivacyControl` wird automatisch als Opt-out gehonored. Banner mit „Do Not Sell or Share“.
## Google Consent Mode v2
Default `denied` (+ `wait_for_update`) im Stub. Nach Consent: `gtag('consent','update',…)` gemäß Property-Mapping (`ad_storage`, `analytics_storage`, …). Außerhalb Opt-in-Regimes konfigurierbar `granted`/`denied`.
## GTM
CMP vor dem GTM-Container laden. Consent Mode Defaults im Stub setzen. Tags an Consent-Checks / `cmp.hasConsent` koppeln oder über geblockte Domains laufen lassen.
## Cookie-Declaration (PR B)
Öffentliche Tabelle über `#cmp-cookie-declaration` — siehe Folge-PR.
## Regime
| Regime | Länder | Modell |
|--------|--------|--------|
| `tcf_eu` | EU/EEA | Opt-in TCF |
| `tcf_uk` | GB/UK | Opt-in TCF (UK-Texte) |
| `ch` | CH | Opt-in TCF |
| `gpp_us` | US | Opt-out / GPP / DNS |
| `notice_only` / `none` | Rest | konfigurierbar pro Property |
## Sprache
Auto: `navigator.language` / `<html lang>`, Fallback Property-Default. GVL-Zwecktexte kommen aus `purposes-{lang}.json` (Import-Job). Banner-UI-Strings und Overrides pro Sprache über `config.json` (nicht im Bundle).
## Troubleshooting
1. Banner erscheint nicht → veröffentlichte Config? Network `config.json` 200?
2. Scripts laufen vor Consent → CMP nicht zuerst in `<head>`?
3. Queue greift nicht → Stub `window.cmp = window.cmp \|\| { q: [] }` vor dem Bundle?
4. GCM bleibt denied → `gtag`/dataLayer vor CMP? Mapping in Property-Settings prüfen.
5. Demo-Land testen → `/demo/KEY?country=US`
## Cookie-Declaration
Einbettung der öffentlichen Cookieliste:
```html
<div id="cmp-cookie-declaration"></div>
<script>
fetch("https://IHRE-CMP-DOMAIN/c/PROPERTY_KEY/cookie-declaration.json?lang=de")
.then(r => r.json())
.then(data => {
const el = document.getElementById("cmp-cookie-declaration");
el.innerHTML = "<table>" + data.cookies.map(c =>
`<tr><td>${c.name}</td><td>${c.vendor||""}</td><td>${c.purpose||""}</td><td>${c.duration||""}</td><td>${c.description||""}</td></tr>`
).join("") + "</table>";
});
</script>
```
Oder per iframe: `/c/PROPERTY_KEY/cookie-declaration` (HTML).