Config reference
AvacyUserConfig (Partial<UserConfigType> + alcune estensioni Tier 1) è il payload accettato sia da <script type="application/json" id="avacy-config"> (auto-init), sia da window.Avacy.init(config) (programmatic). Tutte le chiavi qui sotto sono opzionali; i default vengono dal core (DEFAULT_CONFIG).
Source of truth nel codice:
packages/core/src/providers/providers.types.ts(ConfigType,UiConfig,StoreConfig,TcfFrameworkConfig, …)packages/cmp-web/src/public-api.ts(AvacyUserConfigconcore.autoInit)packages/core/src/providers/config.ts(merge inline + remote config)
type AvacyUserConfig = Partial<UserConfigType> & {
core?: Partial<UserConfigType['core']> & { autoInit?: boolean };
};
Identità e versionamento
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
publisherCountryCode | string (ISO 3166-1 alpha-2) | 'IT' | Country code del publisher, usato dal TCF (publisherCC nel TC string) e dalla logica di applicabilità di alcune normative locali. |
policyVersion | number | 1 | Versione della policy interna. Cambiandola si invalida automaticamente il consenso salvato (forza un re-consent al prossimo boot). |
cmpVersion | string | '1.0.0' | Versione del CMP scritta nel TC string. La libreria espone anche window.Avacy.version per il bundle vero (semver build). |
consentExpiryDays | number | 182 (~6 mesi) | Scadenza del consenso in giorni. Un consenso più vecchio di tanto viene considerato non valido (consent.valid: false), il banner riappare. |
Boot e auto-init
core?: {
autoInit?: boolean; // Tier 1 extension (cmp-web only)
autoLoad?: boolean; // core
}
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
core.autoInit | boolean | true | Tier 1, gate del boot automatico del bundle cmp-web. Se false, il bundle non boota da solo e l'integratore deve chiamare window.Avacy.init(). Vedi anche il pattern programmatico nel Getting Started. |
core.autoLoad | boolean | true | Core flag. Se true, al termine di Core.init viene invocato triggerLoad() (caricamento provider + emissione OnLoad listener chain). Se false, triggerLoad deve essere chiamato esplicitamente — uso avanzato, raro al di fuori dei test. |
Lingua
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
language | LanguageCode (ISO 639-1) | 'en' | Lingua attiva al boot. Le label vengono lette dalla bundle prebundled, eventualmente sovrascritta da customLabels[lang] e/o dal remote labels file. |
autoLanguage | boolean | false | Quando true, cmp-web rileva la lingua da document.documentElement.lang al boot e si riallinea ai cambi via MutationObserver. Mirror del flag auto_language di avacy_banner. |
customLabels | Partial<Record<LanguageCode, Partial<LanguageLabels>>> | undefined | Override partiali delle label per lingua. Precedenza: customLabels[lang] > remote labels > prebundled[lang] > prebundled fallback. Chiavi sconosciute vengono mergiate ma loggate come warning. |
Copertura del remote labels file
Per una lingua non prebundled (tutte tranne en/it/de), il core fa fetch di {assetPath}/languages/{lang}.json e mergia il risultato sopra il fallback inglese (LanguageProvider::loadLanguageData). Stato della copertura di packages/core/public/assets/languages/*.json al 2026-09-02, dopo un porting dal dizionario legacy services/api/config/banner_texts.php (35 lingue) fatto per chiudere un gap di continuità emerso durante un audit — dettaglio completo nell'artifact "Migrazione Banner CMP", sezione Decisioni aperte:
| Lingue | Copertura |
|---|---|
es | ~46/59 chiavi (completate da 30). Le rimanenti sono concetti nuovi del core senza equivalente legacy (glossario, stack, ecc.) — fallback EN. |
cs, hr, nl, pl, ar, bg, bs, hu, ja, pt, ru, zh | 37-41/59 chiavi ciascuna, portate dal dizionario legacy. Stesso tipo di gap residuo di es sui concetti nuovi. |
fr | Vuota per scelta esplicita (CPC interamente in inglese) — non è un gap. |
sl, sr, tr e le altre lingue non elencate sopra | Nessuna traduzione — il dizionario legacy stesso non le ha mai avute per queste lingue, quindi non è una regressione ma resta un gap aperto se si vuole coprirle (richiede traduzione ex novo, nessuna fonte da cui portare). |
Nota a margine (limite noto, non un'incognita): il core non imposta dir="rtl" né adatta il layout per lingue right-to-left — zero occorrenze di dir=/direction: rtl in packages/core e packages/cmp-web. L'arabo (ar) ha ora testo tradotto correttamente ma layout LTR.
Placeholder nel copy
Nove placeholder {{nome}} (tollerata la spaziatura interna, {{ nome }}) che vengono interpolati in qualunque label di customLabels — non solo l'informativa breve (SHORT_NOTICE_TEXT) o il sottotitolo del CPC (PREFERENCES_TEXT), come poteva sembrare dal legacy.
| Placeholder | Risolve a | Rete | Disponibile da SaaS |
|---|---|---|---|
{{vendors_count}} | Numero di fornitori attivi. Stringa vuota se non ancora noto o zero — mai il numero 0 in una frase. | Sì | Sì — tab "Informativa breve" |
{{basis_names}} | Unione dei nomi di purpose, special purpose, feature e special feature dichiarati, nell'ordine di preferencesOrder. Frase di fallback (solo en/it/de) finché non risolto. | Sì | Sì — tab "Informativa breve" |
{{purposes_names}} | Solo i purpose, stesso ordine. | Sì | No |
{{special_purposes_names}} | Solo gli special purpose. | Sì | No |
{{features_names}} | Solo le feature. | Sì | No |
{{special_features_names}} | Solo le special feature. | Sì | No |
{{stack_names}} | Solo i nomi degli stack IAB configurati (vedi tcf.stacks). | Sì | No |
{{privacy_policy_url}} | Un'àncora HTML completa (non l'URL nudo), testo da LABEL_PRIVACY_POLICY, verso PRIVACY_POLICY_URL. | No | No |
{{cookie_policy_url}} | Come sopra, per COOKIE_POLICY_URL/LABEL_COOKIE_POLICY. | No | No |
Gli ultimi tre di conservazione ({{storage_technology}}, {{item_name}}, {{expires_in_days}}) sono documentati a parte, insieme a ui.behavior.showConsentRetentionSection (vedi "La durata di conservazione si espone in due modi indipendenti" più sotto).
Il costo di rete si paga solo se il placeholder è davvero nel copy — resolvePlaceholders() espone tutti e nove come getter, ma t() legge solo quelli che il testo contiene: scriverne uno in una label è una decisione di performance, non solo di testo. Sono due le richieste possibili, non nove: {{vendors_count}} ne triggera una dedicata (vendor-list); {{basis_names}} e le quattro varianti _names più {{stack_names}} condividono la stessa richiesta (file lingua della GVL) — usarne più di uno nello stesso copy non ne raddoppia il costo.
⚠️ {{basis_names}} non è la base giuridica: nome simile, significato diverso — è l'elenco dei purpose/feature dichiarati, non se sono trattati a consenso o legittimo interesse (quello è enableLegInt, altra chiave, altro capitolo).
{{stack_names}} si risolve vuoto se tcf.stacks è assente, che è il default: un copy che lo usa deve restare leggibile anche senza. I due placeholder di policy rendono già un'àncora <a> completa — non vanno avvolti in un <a> proprio nel copy, o si ottiene un link dentro un link.
Disponibile da SaaS: oggi solo {{vendors_count}} e {{basis_names}} sono noti alla dashboard (tab "Informativa breve", campo di testo libero) — gli altri sette sono nuovi in cmp-web, nessuna tab li menziona.
Storage del consenso
store: {
type: 'cookie' | 'local-storage' | (string & {});
consentKey: string;
}
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
store.type | StoreType | 'cookie' | Implementazione di storage attiva. Built-in: 'cookie', 'local-storage'. Per custom-store registrati via registerStoreProvider — il valore è opaco al core (string & {} accetta qualunque chiave registrata). |
store.consentKey | string | 'avacy_consent' | Nome della chiave dello storage (cookie name o localStorage key). Tipicamente lasciato di default per consistenza con la dashboard SaaS. |
⚠️
store.typeè una scelta statica, decisa una volta al boot — nessun fallback automatico. Con'cookie'e una config con molti framework combinati (es. TCF + ACM), il consenso codificato può superare il limite pratico di un cookie (~4KB): la scrittura viene troncata/rifiutata silenziosamente dal browser, senza errore. Dettaglio in Internals — storage.
Archivio consensi (Consent Solution)
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
consentSolutionUrl | string | assente (funzione spenta) | Endpoint a cui ogni decisione dell'utente sui bottoni del banner viene notificata come prova del consenso. Assente ⇒ zero richieste di rete, la funzione è del tutto disattivata. |
Nella dashboard SaaS non è un campo che il cliente scrive a mano: è il toggle "Archiviazione dei consensi" (piano plus+), e l'URL lo genera la SaaS stessa verso il proprio backend ({API_URL}/{tenant}/v4/webspaces/{groupId}/consents). Resta comunque tipizzato come URL arbitrario — un integratore non deve dare per scontato né il dominio né la disponibilità.
Compliance, non solo telemetria: è la funzione equivalente a sendConsent del banner legacy — l'unica prova verificabile che l'utente ha visto e premuto un bottone specifico, non solo che un certo stato di consenso esiste nello storage locale. Il body notificato è minimale (consent_type: 'banner', optin, più un uuid di correlazione dopo la prima chiamata riuscita) — niente TC String, niente scelte decodificate: IP, dominio e versioni li compila il backend.
Comportamento in caso di fallimento: fire-and-forget dichiarato, timeout 15s, nessun retry. Un endpoint lento, giù o in errore non impedisce mai la persistenza del consenso né blocca il banner — la decisione dell'utente è sempre salvata localmente indipendentemente dall'esito dell'archiviazione. Dettaglio del meccanismo (id di correlazione, guardie anti-race, sospensione in preview) in Internals — cmp-web.
Asset path e remote config
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
assetPath | string | '/assets' | Base path (o URL CDN) da cui il bundle fetcha tutti gli asset: remote config, GVL, ACM providers list, custom labels. Normalizzato a URL completo dal ConfigProvider. Esempi: '/assets', 'https://cdn.example.com/cmp'. |
remoteConfigName | string | 'config.json' | Filename del remote config sotto assetPath. Il fetch produce un ConfigType parziale, merge in shallow con quello inline (priorità: inline > remote). |
remoteConfigUrl | string | — | URL assoluto del remote config, alternativo a remoteConfigName (ignora assetPath). Se sono presenti entrambi, remoteConfigUrl vince — stessa precedenza di customVendorsUrl/acmProvidersUrl sui rispettivi *ConfigName. |
remoteGVLName | string | 'v3' | Cartella del GVL (Global Vendor List TCF) sotto assetPath. Usata per costruire gvlUrl quando non specificato esplicitamente in frameworks[].tcf.gvlUrl. |
vendorsCount | number | derivato | Override del contatore vendor mostrato in alcune label ("X vendor partecipano…"). Se assente, viene calcolato a runtime dal framework provider attivo. |
Frameworks
frameworks: FrameworkItem[];
type FrameworkItem =
| FrameworkType // shorthand: 'tcf' | 'gcm' | 'custom' | 'acm'
| { tcf: TcfFrameworkConfig }
| { gcm: GcmFrameworkConfig }
| { custom: CustomFrameworkConfig }
| { acm: AcmFrameworkConfig };
Array di framework da attivare. Ogni entry può essere lo shorthand 'tcf' (usa i default del framework) oppure la forma a oggetto con la config full per quel framework. Default: [] (nessun framework attivo — boot minimal, raro nella pratica).
TCF (frameworks: [{ tcf: { … } }])
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
cmpId | number | 297 | CMP ID assegnato da IAB Europe. Per Avacy: 297. |
frameworkVersion | number | 2 | Versione TCF (2 = TCF v2). |
vendors | number[] | 'all' | 'all' | Lista vendor abilitati. 'all' = tutti i vendor del GVL attivo. |
gvlUrl | string | derivato da assetPath + remoteGVLName | URL completo del GVL JSON. Override esplicito se vuoi un GVL hostato altrove. |
purposeOneTreatment | boolean | false | Flag TCF purposeOneTreatment (pubCustomization): dichiara che il purpose 1 (storage info) è trattato dal publisher fuori dal TCF. Default false perché la normativa italiana richiede che l'utente esprima il consenso sul purpose 1. ⚠️ Governa solo il bit nella TC String: non nasconde il purpose 1 dal CPC (a differenza del banner legacy, dove la chiave faceva entrambe le cose). |
enableLegInt | 'all' | { purposes?, vendors? } | (off) | Opt-in per legittimo interesse. Se omesso, nessun purpose o vendor è legIntInteractable. 'all' = { purposes: 'all', vendors: 'all' }. ⚠️ Cambia la base giuridica scritta nella TC String, non solo la UI — vedi sotto. |
objectLegIntOnReject | boolean | true | Su RejectAll: se true, azzera anche hasLegitimateInterest. Se false, lascia LI al valore corrente e flippa solo hasConsent. |
stacks | number[] | (assente) | Raggruppa purpose/special feature nel CPC secondo gli stack IAB del GVL. Non una lista di preferenze: deve essere un insieme disgiunto — vedi sotto. |
Restringere vendors nasconde automaticamente le finalità/funzionalità che nessun vendor superstite dichiara più. Non è una chiave nuova, è un effetto collaterale di vendors: purpose, special purpose, feature e special feature con zero vendor dichiaranti non compaiono come card a sé nel CPC — parità col banner legacy (PurposeContainerSnippet si comportava già così). Un integratore che testa con una lista di vendor ristretta e nota sparire alcune voci del secondo layer deve sapere che è voluto, non un bug del filtro.
⚠️ Un'eccezione riguarda solo i purpose: se un fornitore custom dichiara lo stesso purpose TCF (CustomVendorConfig.purposes: [{framework: 'tcf', id}]), il purpose resta visibile anche se nessun vendor TCF superstite lo dichiara più — il conteggio vendor mostrato nel CPC somma le due fonti. Special purpose, feature e special feature non hanno questa via di salvezza: per loro il filtro dipende solo da vendors (packages/core/src/providers/frameworks/main-framework.ts:99-147).
Base giuridica del legittimo interesse (enableLegInt)
enableLegInt non nasconde dei controlli nella UI: cambia la base giuridica che il CMP scrive per un vendor nella TC String. È la cosa più controintuitiva della superficie TCF, ed è il motivo per cui vale la pena leggerla prima di toccare la chiave in produzione.
Con la chiave assente (il default), il core scrive una Publisher Restriction di tipo REQUIRE_CONSENT su ogni purpose che un vendor dichiara sotto legittimo interesse e come flessibile (flexiblePurposes): quel purpose passa a consenso per quel vendor. Un purpose che il vendor dichiara sotto LI ma non flessibile diventa invece di fatto vietato per quel vendor — "should not process", nella terminologia della specifica.
Misurato sulla GVL in produzione: dei 358 vendor con almeno un purpose sotto legittimo interesse, 194 li hanno tutti flessibili, 128 nessuno, 36 in parte — 398 coppie (vendor, purpose) non commutabili semplicemente riaccendendo la UI. Con vendors: 'all', spegnere enableLegInt produce 6 Publisher Restriction su 677 coppie (vendor, purpose): sono poche, ma sono per-vendor e cambiano cosa un fornitore può fare, non solo cosa un utente vede.
Tre cose da sapere prima di usarla:
- Spegnerla è una scelta di base giuridica, non estetica: sposta l'onere legale su cui il vendor può processare quel dato, non solo un interruttore nel secondo layer.
- Accenderla per un sottoinsieme (
enableLegInt: { purposes: [...] }o{ vendors: [...] }) restringe solo le altre combinazioni — non è "tutto o niente". - Il legittimo interesse resta comunque vietato per i purpose 1, 3, 4, 5, 6 in TCF v2.2: accendere
enableLegIntnon li riporta sotto LI, la specifica lo esclude a prescindere dalla config.
Il dettaglio vendor nel CPC mostra la base effettiva: toccando la chiave, le stesse finalità possono cambiare sezione (consenso ↔ legittimo interesse) o sparire dall'elenco di un vendor. Esempio misurato, la stessa config che builds/web/assets/example.html spedisce — vendors: [29] (ETARGET SE, legIntPurposes: [2, 7, 10], flexiblePurposes: []): con LI spento al vendor resta una sola finalità su quattro (la 1, dichiarata a consenso); accendendo enableLegInt le altre tre tornano sotto legittimo interesse.
Stack IAB (stacks) — whitelist disgiunta, non una lista di preferenze
tcf.stacks raggruppa purpose e special feature nel secondo layer usando gli "stack" definiti dalla GVL — la stessa etichetta collettiva che IAB usa per accorpare finalità imparentate (es. "Pubblicità basata su dati limitati e misurazione delle prestazioni degli annunci"). Ma il TCF vieta di presentare lo stesso purpose in due gruppi diversi, e nella GVL reale gli stack si sovrappongono pesantemente: il purpose 2 sta in 28 stack su 45, e solo il 21% delle coppie di stack è disgiunto. Chi configura questa chiave a intuito, elencando gli stack che sembrano rilevanti, sbaglia circa 4 volte su 5.
Cosa succede quando la whitelist configurata non è disgiunta:
- L'ordine conta: il primo stack dichiarato che rivendica un purpose lo tiene.
- Uno stack sovrapposto viene scartato INTERO, non tagliato ai soli purpose non contesi. La ragione è che la descrizione IAB di uno stack non è modificabile: un gruppo dimezzato mostrerebbe un testo che nomina finalità che non contiene più.
- Il CMP scarta gli stack in eccesso con un warning in console (
[tcf] tcf.stacks: stack N is ignored because it overlaps…) — nessun errore bloccante, e nessun integratore lo leggerà se non lo sta cercando.
L'insieme disgiunto massimo già misurato sulla GVL è [1, 2, 10, 11, 21]: copre i purpose 2→10 e le due special feature, e lascia singoli solo il purpose 1 (non appartiene a nessuno stack) e l'11. È il punto di partenza da dare come configurazione, non solo un esempio.
Due vincoli aggiuntivi, non negoziabili via config:
- Nome e descrizione dello stack vengono dalla GVL e non sono sovrascrivibili da
customLabels— le TCF Policies lo vietano al publisher. Personalizzarli richiederebbe di alzare il flaguseNonStandardTextsnella TC String, oggi semprefalse. - La whitelist non tocca solo il CPC. Nel first layer, il nome dello stack sostituisce i nomi dei purpose che raggruppa dentro il placeholder
{{basis_names}}del copy — e l'ordine in cui{{basis_names}}li elenca segueui.behavior.preferencesOrder: chi riordina le sezioni del CPC riordina anche la frase del banner.
GCM (frameworks: [{ gcm: { … } }]) — Google Consent Mode v2
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
enabled | boolean | false | Abilita la propagazione default → update su gtag('consent', …). |
remoteGVLName | string | — | Override del nome cartella GCM-related asset sotto assetPath. |
mapToPurpose | GcmMapToPurposeEntry[] | — | "Inferred mode": invece di esporre i 7 purpose GCM nel CPC, deriva il consenso GCM dagli altri framework. Ogni entry: { fw: 'tcf' | 'custom' | array, purpose: number | number[], gcmPurpose: number[] }. Con array su fw/purpose, tutte le sorgenti devono concedere (AND). |
Custom (frameworks: [{ custom: { … } }])
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
customVendorsUrl | string | — | URL assoluto del JSON con vendor/purpose custom. Mutualmente esclusivo con customVendorsConfigName. |
customVendorsConfigName | string | — | Filename del config custom sotto assetPath. Risolto come assetPath + '/' + customVendorsConfigName. |
customVendorsConfig | CustomVendorsConfig (inline) | — | Config inline (evita la fetch HTTP). Utile per test e siti statici. |
customFetch | typeof fetch | window.fetch | Override della funzione fetch. Usato per stubbing nei test e per piattaforme con fetch non standard. |
enableLegInt | 'all' | { purposes?, vendors? } | (off) | Vedi tcf.enableLegInt, semantica identica. |
objectLegIntOnReject | boolean | true | Vedi tcf.objectLegIntOnReject. |
ACM (frameworks: [{ acm: { … } }]) — Google Additional Consent Mode
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
acmProvidersUrl | string | — | URL assoluto della lista ATP (Google Additional Tech Provider). |
acmProvidersConfigName | string | — | Filename ATP sotto assetPath. |
acmProvidersConfig | AcmProvidersConfig (inline) | — | Config inline. |
acmFetch | typeof fetch | window.fetch | Override fetch. |
UI (ui: UiConfig)
Comportamento UX di banner first-layer e CPC second-layer. Funzionalità/logica del consenso NON vivono qui — sono in frameworks o nelle scelte UX vincolate dal TCF.
Le chiavi di comportamento vivono sotto ui.behavior; ui.branding, ui.font e ui.colors sono documentati più sotto. ui.layout è un namespace riservato ancora da documentare qui.
Banner e CPC applicano sempre la variante "compatta" quando rilevano window.self !== window.top: non è configurabile da ui.behavior. Un editor che incorpora il CMP nel proprio iframe e vuole mostrare il layout standard deve caricare la build cmp-saas-preview (packages/cmp-web/builds/cmp-saas-preview/), che disattiva la detection a livello di bundle, non di config.
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
ui.behavior.showRejectAllButton | boolean | true nella build base, false esplicito per RAI | Bottone "Rifiuta tutto" nel footer del banner, paritetico ad "Accetta tutto" — stesso peso visivo, stesso handler di closeWithoutConsents (triggerConsent({type: 'RejectAll'})): i due controlli differiscono solo per posizione/peso, mai per semantica del consenso. Disponibile da SaaS: sì, come reject_all (tab Aspetto → Testi area principale). Vedi sotto per il vincolo con closeWithoutConsents. |
ui.behavior.closeWithoutConsents | false | 'text' | 'closeIcon' | false nello schema, ma 'closeIcon' nella build base (vedi vincolo sotto) | Azione "Continua senza accettare" nel banner. Funzionalmente equivalente a RejectAll. 'text' = pulsante outline con testo; 'closeIcon' = pulsante icon-only. Legacy true mappato a 'text'. |
ui.behavior.activateVendorsOnLegalScopeSelections | boolean | false | Se true, abilitare un purpose / special feature nel CPC abilita automaticamente i toggle dei vendor che lo supportano. |
ui.behavior.hideIntroOnScroll | boolean | false | Se true, il sottotitolo sotto l'heading del CPC collassa (opacity → 0, height → 0) dopo > 100px di scroll nel pannello. Mirror del legacy hide_intro_on_scroll. |
ui.behavior.closePreferencesOnBulkSelect | boolean | true | Se true, "Accetta tutto / Rifiuta tutto" nel preference center chiude il pannello dopo aver pubblicato il consenso. Se false, il pannello rimane aperto e si re-renderizza sul nuovo stato. |
ui.behavior.showPrivacyPolicyLink | boolean | false | Mostra il link alla Privacy Policy nel first-layer. Doppio gate: appare solo se true e se PRIVACY_POLICY_URL è impostata per la lingua attiva (vedi sotto) — un flag attivo senza URL non produce un link rotto, semplicemente non mostra nulla. |
ui.behavior.showCookiePolicyLink | boolean | false | Come sopra, per la Cookie Policy (COOKIE_POLICY_URL). Se entrambi i link sono visibili, un separatore li divide. |
ui.behavior.shieldPosition | 'left' | 'right' | 'right' | Lato dello schermo per lo shield persistente post-consenso (icona che riapre il CPC). |
ui.behavior.showShieldTooltip | boolean | false | Se true, il click sull'icona dello shield apre un tooltip con i link Privacy/Cookie Policy (stesso doppio gate di showPrivacyPolicyLink/showCookiePolicyLink) più un'azione per aprire il CPC, invece di aprire subito il CPC. Chiudibile con Esc. |
ui.behavior.closeWithoutSaving | boolean | false | Pulsante "chiudi senza salvare" nel footer del CPC: chiude il pannello senza pubblicare le modifiche fatte ai toggle. Vedi sotto per due comportamenti non ovvi. Disponibile da SaaS: sì, come close_without_saving (tab Aspetto → Banner). |
ui.behavior.showConsentRetentionSection | boolean | true nella build base | Aggiunge una voce di nav e una sezione "Conservazione" in coda al CPC, con tecnologia di storage, nome della chiave e durata massima. Non è lo stesso nome del legacy (show_cmp_cookie_retention_time) né della prima stesura di questo PBI (showCmpCookieRetentionTime, mai arrivata al codice) — vedi sotto per l'indipendenza dai placeholder {{storage_technology}}/{{item_name}}/{{expires_in_days}}. Disponibile da SaaS: sì, come show_cmp_cookie_retention_time (tab Impostazioni avanzate). |
showRejectAllButton / closeWithoutConsents — vincolo di coesistenza (PBI 19, 2026-08-19): un banner non mostra mai due modi testuali di rifiutare nello stesso primo layer. Quando showRejectAllButton è true, closeWithoutConsents non può valere 'text' — solo 'closeIcon' o false. Se lo si imposta comunque a 'text' (o al legacy true), il valore viene silenziosamente forzato a 'closeIcon', con un console.warn ([ConfigProvider] ui.behavior.showRejectAllButton is true: closeWithoutConsents cannot be 'text', forcing 'closeIcon'.) — non un errore bloccante, non visibile a chi non guarda la console (packages/core/src/providers/config.ts:147-159).
Secondo pezzo, per chi confronta con la build precedente: nella build base il default di closeWithoutConsents è cambiato da assente/false a 'closeIcon', insieme all'accensione di showRejectAllButton. Chi non vedeva nessuna azione nell'header del banner nella build generica ora ne vede una. RAI non è impattata: spegne showRejectAllButton esplicitamente nella propria config (builds/rai/src/config.json).
ui.behavior.closeWithoutSaving — due cose che non si vedono leggendo solo il tipo:
- Il pulsante compare solo a consenso già dato (
avacy-cpc.tsx:1150, condizionecloseWithoutSaving === true && isConsentGiven(...)). Chi accende la chiave e prova ad aprire il CPC alla prima visita — prima di aver mai dato un consenso — non lo vede, e può concludere che la chiave non funziona: non è un bug, è per costruzione. - Colore: 3 campi dedicati in
ui.colors—btnCloseWithoutSavingBackground,btnCloseWithoutSavingBackgroundHover,btnCloseWithoutSavingTextColor— stesso pattern degli altri ruoli pulsante (catalogo completo dei campi colore ancora da scrivere). Disponibile da SaaS: no — nessuna delle tab espone un color picker dedicato a questo ruolo oggi. - Il testo del pulsante (
PREFERENCES_CLOSE_BTN) è tradotto solo in inglese, italiano e tedesco — le 3 lingue compilate nel bundle. Nelle altre 7 il pulsante dirà sempreClose, anche se il resto della CPC è nella lingua del sito: per 6 di quelle è coerente, perché la loro CPC è comunque tutta in inglese, ma in spagnolo no —es.jsonha 30 label tradotte, quindi una CPC spagnola avrà tutto tradotto tranne questo pulsante. Disponibile da SaaS: no — è un default fisso lato server (banner_texts.php), zero occorrenze inservices/frontend: il cliente non lo personalizza, riceve solo la traduzione che gli forniamo di default (in valutazione se e quando esporlo, vedi PBI 31 sulle traduzioni).
ui.secondLayerConsentOnGlobalSelection non è una chiave configurabile: non esiste nei tipi né ha un consumer nel core. Il comportamento è hardcoded sul true del legacy — "Accetta tutto / Rifiuta tutto" nel CPC salva sempre subito, senza "Salva e continua" — e il ramo false non è riproducibile. Chi arriva dal legacy con questa chiave assente (default legacy false) vedrà quindi un comportamento diverso da prima; solo RAI, che in produzione aveva già true esplicito, ha parità piena.
La durata di conservazione si espone in due modi indipendenti
Due meccanismi diversi mostrano la stessa informazione, e non sono collegati: accendere l'uno non spegne né sa dell'altro. Su un cliente che li usa entrambi, la durata compare due volte.
- I tre placeholder nel copy (
{{storage_technology}},{{item_name}},{{expires_in_days}}, vedi sopra "Placeholder nel copy") — esistono da sempre, guidati dal testo diPREFERENCES_TEXT, non da un flag. Oggi li usa solo RAI. ui.behavior.showConsentRetentionSection(sopra) — sezione dedicata in coda alla nav del CPC, indipendente dal copy.
Se un cliente ha già i tre placeholder nel proprio PREFERENCES_TEXT e la sezione è accesa (default true nella build base), l'utente vede la stessa durata due volte nello stesso pannello.
Le 4 label della sezione, e la quinta che manca apposta: PREFERENCES_RETENTION_HEADING (titolo nav + sezione), PREFERENCES_RETENTION_TEXT (intro, HTML), PREFERENCES_RETENTION_TECHNOLOGY e PREFERENCES_RETENTION_ITEM_NAME (etichette delle rispettive righe). La riga della durata non ha una label propria: riusa PREFERENCES_STORAGE_MAX_AGE, la stessa etichetta delle righe di max-age nella disclosure dei singoli vendor — cambiarla cambia due punti del CPC, non uno.
Il valore della durata passa da formatDuration (Intl), non dal copy: localizza e pluralizza da solo ("1 giorno" vs "182 giorni"), quindi non è sovrascrivibile — ed è per questo che è corretto in tutte e 10 le lingue supportate, mentre le altre tre label sono tradotte solo in inglese, italiano e tedesco (stessa eccezione spagnola già vista per PREFERENCES_CLOSE_BTN: il resto della CPC spagnola è tradotto, queste tre etichette no). I due punti fra etichetta e valore li mette il CSS: metterli anche nel copy li raddoppia.
Il valore della tecnologia (cookie, local storage, SharedPreferences, UserDefaults, syndication) è quello che dichiara il provider di storage attivo, non tradotto — un cliente che ne vuole uno diverso a schermo non ha oggi una leva.
Righe senza valore non compaiono: se state.storage?.technology è vuoto, o consentExpiryDays non è impostata, quella riga non si vede — mai una riga con un lato vuoto.
Link Privacy/Cookie Policy — URL e testo per lingua
L'URL e il testo visibile dei link non vivono in ConfigType: sono per lingua, quindi vivono in customLabels, come qualunque altra label. Chiavi da impostare per ogni lingua supportata dal sito (un default mancante per una lingua ⇒ nessun link per quella lingua, anche a flag attivo):
| Chiave label | Descrizione |
|---|---|
PRIVACY_POLICY_URL | URL della propria Privacy Policy. Vuota di default — va impostata dal cliente. |
COOKIE_POLICY_URL | URL della propria Cookie Policy. Vuota di default. |
LABEL_PRIVACY_POLICY | Testo del link. Default "Privacy Policy" (en/it), "Datenschutzerklärung" (de) — override solo se si vuole un testo diverso. |
LABEL_COOKIE_POLICY | Testo del link. Default "Cookie Policy" (en/it), "Cookie-Richtlinie" (de). |
{
"ui": {
"behavior": {
"showPrivacyPolicyLink": true,
"showCookiePolicyLink": true
}
},
"customLabels": {
"it": {
"PRIVACY_POLICY_URL": "https://example.com/privacy",
"COOKIE_POLICY_URL": "https://example.com/cookie"
},
"en": {
"PRIVACY_POLICY_URL": "https://example.com/en/privacy",
"COOKIE_POLICY_URL": "https://example.com/en/cookie"
}
}
}
Branding (ui.branding)
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
ui.branding.enableBranding | false | 'light' | 'dark' | assente (disattivato) | Watermark "Avacy" nel first-layer e nel CPC. Il gate è contrattuale, non tecnico: la chiave resta lato client come le altre. |
ui.branding.logoUrl | string | assente | Logo del cliente/tenant, mostrato accanto al titolo nel first-layer. Non più mostrato nel CPC (rimosso il 2026-07-31, ratificato il 2026-08-17). Fallback pulito (elemento rimosso) se l'immagine non carica. |
ui.branding.shieldIconUrl | string | assente | Icona custom del widget persistente post-consenso, al posto dell'icona di default Avacy. Vedi sotto per il contratto di ricolorazione e per chi può impostarla via SaaS. |
Icona custom del widget preferenze — ricolorazione
Un file SVG referenziato da shieldIconUrl viene ricolorato automaticamente se contiene, nei propri attributi fill, il placeholder:
fill="var(--avacy-shield-primary-bg, #fallback)"
Il valore risolve a ui.colors.shieldColor (via la custom property --avacy-shield-primary-bg), quindi l'icona segue il colore del tema del cliente senza dover caricare un file diverso per ogni brand. accentPrimary non esiste più in UiColorsConfig (eliminata nel PBI 08): la chiave corretta è shieldColor. Se il file non contiene il placeholder, o è un formato raster (PNG/JPG), viene mostrato così com'è, nessuna ricolorazione.
Requisito: il server che ospita il file SVG deve rispondere con header CORS permissivi (Access-Control-Allow-Origin) — a differenza di un normale <img src>, l'icona viene scaricata via fetch() per poter leggere e iniettare il suo contenuto. Se il fetch fallisce (rete, 404, CORS mancante), il widget mostra l'icona di default Avacy, senza rompersi.
Chi può impostarla via SaaS (policy di prodotto, non un limite del CMP): il componente tratta shieldIconUrl come una chiave generica — non fa alcuna distinzione per tenant. Ma nella SaaS non è (e non è mai stata) un campo self-service: nessuna delle tab di "Generazione banner" la espone. Oggi l'unico tenant che riceve un valore è EasyConsulting, iniettato lato backend per retrocompatibilità (EasyConsultingOverrides.php, applicato via BannerConfigHookService::applyFilters() — non visibile né modificabile dal cliente).
Per tutti gli altri clienti SaaS, oggi lo shield non è personalizzabile in alcun modo, né icona né colore: la dashboard non parla ancora lo schema nuovo. Verificato in appearance-texts-colors.tsx (branch development): il colorMapping del picker "Link e interazioni" scrive oggi solo le chiavi legacy accent_primary/accent_secondary — nessun riferimento a shieldColor o a qualunque chiave shield. Quando la migrazione frontend della SaaS sarà completata, quel picker scriverà anche ui.colors.shieldColor (assieme ad altri 6 campi, stesso bucket) — ma sarà comunque solo il colore di sfondo, non la sostituzione della grafica: quella resta riservata a EasyConsulting. Chi scrive config direttamente (RAI, o un futuro consumer non-SaaS) non ha invece questa restrizione: è una policy della SaaS, non un vincolo tecnico del CMP.
{
"ui": {
"branding": {
"shieldIconUrl": "https://cdn.example.com/icons/my-shield.svg"
}
}
}
Distanziare lo scudo dai bordi della pagina
Lo scudo è ancorato di default a 1rem dal basso e dal lato su cui è posizionato (ui.behavior.shieldPosition). Se il sito ha altri elementi fissi che si sovrappongono (una chat, un'altra cookie bar, un bottone fisso), si scosta con due CSS custom property dal foglio di stile del sito — non sono una chiave di configurazione, non hanno un default in DEFAULT_CONFIG e non compaiono nello schema ConfigType:
:root {
--avacy-shield-offset-bottom: 4rem; /* distanza dal basso */
--avacy-shield-offset-side: 4rem; /* distanza dal lato su cui è posizionato */
}
| Variabile | Default | Descrizione |
|---|---|---|
--avacy-shield-offset-bottom | 1rem | Distanza dal bordo inferiore della pagina. |
--avacy-shield-offset-side | 1rem | Distanza dal bordo laterale su cui lo scudo è posizionato. Segue automaticamente il lato configurato (destra o sinistra) — non serve impostarne due. |
Accettano qualunque unità CSS valida per una lunghezza (px, rem, %, calc(), incluso env(safe-area-inset-bottom) per tenere conto dell'home indicator su iOS).
⚠️ Se si imposta un valore non valido come lunghezza (es. un numero senza unità), il browser non torna al default: la proprietà si comporta come se non fosse impostata affatto, e lo scudo può spostarsi in una posizione inattesa. Controllare sempre visivamente dopo aver personalizzato questi valori.
Disponibile da SaaS: non ancora — oggi si imposta solo dal CSS del sito. È prevista una gestione futura da dashboard (nota di Erica, 2026-09-01); finché non arriva, questa resta l'unica via.
Font (ui.font)
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
ui.font.fontFamily | string | assente | Font-family per corpo, titoli e label — una sola chiave per tutte e tre le famiglie. Valore assente, vuoto o di soli spazi ⇒ nessuna custom property emessa, resta il default del design system. Disponibile da SaaS: non ancora — la dashboard non parla lo schema nuovo (migrazione frontend SaaS non iniziata). Oggi raggiungibile solo scrivendo config direttamente (RAI) o dal CSS del sito (vedi sotto). |
Override dal CSS del sito — tre slot indipendenti
fontFamily non scrive direttamente il font-family finale: alimenta la custom property --avacy-font-family-config, che sta nella posizione di fallback di una catena var() a tre livelli. Il sito ospite può sovrascrivere la config, per singolo scope, con tre custom property proprie:
:root {
--avacy-global-font-family-custom: 'Inter', sans-serif; /* corpo — fallback anche per titoli e label */
--avacy-heading-font-family-custom: 'Playfair Display', serif; /* solo titoli */
--avacy-label-font-family-custom: 'Inter', sans-serif; /* solo label */
}
Chi imposta solo --avacy-global-font-family-custom cambia corpo, titoli e label insieme (titoli e label ricadono sul globale se non impostati singolarmente). Chi vuole differenziare i titoli imposta anche --avacy-heading-font-family-custom, e così per le label. Le tre custom property vincono sempre su fontFamily, indipendentemente dall'ordine di caricamento dei fogli di stile: attraversano il boundary dello shadow DOM per eredità, quindi si impostano su :root o su un qualunque antenato della pagina ospite — non serve toccare il bundle.
Nessun caricamento automatico del webfont: impostare una famiglia qui non inietta un <link> o una regola @font-face — a differenza del legacy (font_autoload), rimosso perché caricare un webfont da un provider esterno prima del consenso è un problema di sostanza per un CMP, non di forma. Il sito deve rendere disponibile il font da sé, in entrambi gli scenari seguenti.
Come impostare il proprio font
Font già disponibile sul sito (font di sistema, o un font che il sito carica già per conto proprio) — nessun caricamento aggiuntivo, si indica solo il nome:
{
"ui": {
"font": {
"fontFamily": "Arial, sans-serif"
}
}
}
Font da un provider remoto (es. Google Fonts) — il sito lo include a modo suo, poi lo referenzia nella config:
<!-- nella pagina ospite, prima o dopo il boot del CMP: indifferente -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
{
"ui": {
"font": {
"fontFamily": "Inter, sans-serif"
}
}
}
In entrambi i casi funziona identicamente anche via CSS con i tre slot --avacy-*-font-family-custom sopra: cambia solo dove il valore vive, non il meccanismo di caricamento. È lo stesso schema che usa RAI in produzione (rai-custom.css, tutte e tre le famiglie a Inter, dichiarata staticamente nel proprio CSS — nessuna delle due porta a un caricamento gestito dal CMP).
Colori (ui.colors)
63 campi, tutti opzionali (assente ⇒ resta il default del design system — a differenza del font, ogni campo mappato ha sempre un valore, anche se il campo non compare in nessuna config). Fonte autorevole: COLOR_TOKEN_MAP in packages/cmp-web/src/helpers/theming.ts, che ogni campo qui sotto scrive su una custom property applicata inline su :root — vince sempre su qualunque stylesheet, incluso un CSS custom del cliente, indipendentemente dall'ordine di caricamento.
Tre trappole che un elenco piatto non racconta:
- I campi bottone sono nominati per ruolo business, non per stile. Non esistono
primary/secondary/outline/textcome nel legacy: ogni bottone del CMP ha un ruolo (accept,reject,customize, …) e un campo dedicato. Chi cerca "il colore del bottone primario" non trova niente — deve sapere quale bottone, non che aspetto ha. textColorPrimaryetextColorSecondarysono invertiti rispetto al nome. Eredità del legacy:textColorPrimaryè il testo secondario/muto (chiaro),textColorSecondaryè il testo principale (scuro). Vedi il box sotto.- I campi di palette globale sono condivisi da più componenti (tab, checkbox, link, notice, CPC, label): hanno un blast radius diverso dai colori bottone, che restano isolati al proprio ruolo.
Bottoni per ruolo
Ogni ruolo ha 3 campi (background, background hover, colore testo), tranne dove annotato. Nessun ruolo "tertiary" — quel concetto di stile è caduto insieme a primary/secondary/outline/text.
| Ruolo | Dove | Background | Background hover | Testo | Altro |
|---|---|---|---|---|---|
Accept (Accetta tutto) | banner | btnAcceptBackground | btnAcceptBackgroundHover | btnAcceptTextColor | — |
Reject (Rifiuta tutto, PBI 19) | banner | btnRejectBackground | btnRejectBackgroundHover | btnRejectTextColor | Default identico ad Accept — nessun colore "negativo" dedicato, decisione in attesa di review Design. |
Customize (Personalizza → apre CPC) | banner + shield | btnCustomizeBackground | btnCustomizeBackgroundHover | btnCustomizeTextColor | Stesso ruolo/colore in entrambi i punti, anche se rendono con forme diverse. |
CloseWithoutConsent ("Continua senza accettare") | banner | btnCloseWithoutConsentBackground | btnCloseWithoutConsentBackgroundHover | btnCloseWithoutConsentTextColor (+ btnCloseWithoutConsentTextColorHover) | + btnCloseWithoutConsentBorder (bordo, tratto distintivo di questo ruolo). L'hover si riempie (non si scurisce), per questo background/testo hover sono campi indipendenti, non incatenati al base. |
ActivateAll (Attiva tutto, CPC) | CPC | btnActivateAllBackground | btnActivateAllBackgroundHover | btnActivateAllTextColor | — |
DeactivateAll (Disattiva tutto, CPC) | CPC | btnDeactivateAllBackground | btnDeactivateAllBackgroundHover | btnDeactivateAllTextColor | — |
Save (Salva e continua, CPC) | CPC | btnSaveBackground | btnSaveBackgroundHover | btnSaveTextColor | — |
CloseWithoutSaving ("Chiudi" del footer CPC, PBI 14) | CPC | btnCloseWithoutSavingBackground | btnCloseWithoutSavingBackgroundHover | btnCloseWithoutSavingTextColor | Default identico a Save (i due stanno affiancati) — non confondere con CloseWithoutConsent, altro bottone, altro layer. |
Back (torna alla lista, CPC) | CPC | — (sempre trasparente) | — | btnBackTextColor (+ btnBackTextColorHover, cambia famiglia di colore, non solo intensità) | Non un ruolo di consenso, ma configurabile — RAI lo personalizza in produzione. |
icon-only (varianti icona sola, es. CloseWithoutConsent in forma icona) non ha campi colore propri.
Palette globale — condivisa da più componenti
| Chiave | Custom property | Descrizione |
|---|---|---|
textColorPrimary | --avacy-color-secondary-text | ⚠️ Nome invertito: nel design system è il testo secondario/muto (chiaro), non il principale. Eredità del ruolo legacy (text_color_primary era già il grigio chiaro lì). |
textColorSecondary | --avacy-color-text | ⚠️ Nome invertito: è il testo principale (scuro/quasi-nero), non il secondario. |
backgroundColor | --avacy-color-bg | Sfondo principale di banner e CPC. |
secondaryBackgroundColor | --avacy-color-secondary-bg | Sfondo secondario (es. bordo sotto il watermark). |
Non esiste più un concetto di "colore d'accento" condiviso (accentPrimary/accentSecondary, eliminati nel PBI 08): ogni elemento sotto ha la propria variabile granulare — vedi tab/checkbox/link/shield/notice qui sotto, che nel legacy riusavano tutti accent_primary.
Altri componenti
| Chiave | Custom property | Dove/cosa |
|---|---|---|
checkboxBorderColor | --avacy-checkbox-border-color | Bordo del checkbox non selezionato. |
checkboxBackground | --avacy-checkbox-bg | Sfondo del checkbox non selezionato. |
checkboxBackgroundChecked | --avacy-checkbox-bg-checked | Sfondo del checkbox selezionato. |
checkboxBorderChecked | --avacy-checkbox-border-checked | Bordo del checkbox selezionato — campo indipendente dal background. |
checkboxCheckColor | --avacy-checkbox-check-color | Colore della spunta dentro il checkbox selezionato. |
sliderBackground | --avacy-toggle-track-bg | Track del toggle, stato spento. |
sliderBackgroundChecked | --avacy-toggle-track-bg-checked | Track del toggle, stato acceso. |
sliderBackgroundCircle | --avacy-toggle-thumb-bg | Pallino/thumb del toggle. |
tabDesktopTextColor | --avacy-tab-color-hover/-active | Testo del tab desktop (sidebar) in hover/active — non confondere con tabTextColor. |
tabIndicatorColor | --avacy-tab-accent-color | Indicatore verticale del tab attivo (desktop). |
tabColor | --avacy-tab-color | Testo del tab desktop a riposo. |
tabIndicatorColorInactive | --avacy-tab-indicator-color-inactive | Indicatore verticale dei tab inattivi (desktop) — non confondere con tabIndicatorColor. |
tabBackground | --avacy-tab-fill-bg | Sfondo pieno del tab/pillola in hover/active, solo variante mobile. La variante desktop non riempie mai lo sfondo. |
tabTextColor | --avacy-tab-fill-color | Testo sopra tabBackground — stesso ambito, solo mobile. |
linkColor | --avacy-link-color | Link (CPC, glossario, shield). |
linkColorHover | --avacy-link-hover-color | Link in hover. |
cpcBackground | --avacy-cpc-bg | Sfondo del pannello CPC. |
cpcTextColor | --avacy-cpc-color | Testo principale del CPC. |
cpcTextSecondaryColor | --avacy-cpc-text-secondary | Testo secondario/muto del CPC. |
cpcBorderColor | --avacy-cpc-border-color | Divisori tra le sezioni disclosure nella lista del CPC. |
stackMembersBackground | --avacy-cpc-stack-members-bg | Sfondo del box membri di uno stack IAB TCF (PBI 16) quando la card è espansa. |
shieldColor | --avacy-shield-primary-bg | Icona persistente post-consenso (shield), solo quando non è un'icona custom con proprio fallback — vedi Branding sopra. |
labelColor | --avacy-label-color | Label condivise (label del toggle, titolo accordion). |
noticeBackground | --avacy-notice-bg | Sfondo del componente notice (es. box di legittimo interesse). |
noticeColor | --avacy-notice-color | Testo e icona del notice (--avacy-notice-icon-color eredita in catena). |
errorTextColor | --avacy-color-error-text | Testo di errore (es. caricamento fallito nella lista disclosure). |
focusColor | --avacy-color-focus | Outline di :focus-visible, condiviso da tutti gli elementi interattivi, nessuna eccezione — un solo slot, non personalizzabile per singolo elemento. ⚠️ Il default del design system (#bedeff) non rispetta WCAG 1.4.11 (~1.4:1): aprendo questo colore alla config, il contrasto diventa responsabilità del cliente. |
overlayBackground | --avacy-overlay-bg | Overlay scuro dietro banner e CPC. Accetta qualunque sintassi CSS color, incluso rgba con alpha. |
scrollbarThumbColor | --avacy-scrollbar-thumb-bg | Pallino/thumb della scrollbar custom (CPC). |
scrollbarTrackColor | --avacy-scrollbar-track-bg | Binario della scrollbar custom (CPC). |
disclosureSubtitleColor | --avacy-disclosure-subtitle-color | Sottotitolo nei pannelli disclosure (CPC). |
Logger
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
loggers | LoggerType[] ('console') | [] (silenzioso) | Quali logger attivare. 'console' stampa info/warning/error su DevTools. Il valore può essere sovrascritto runtime via window.Avacy.setDebug(true) (persiste in localStorage, applicato al prossimo boot). |
Filtri (advanced)
| Chiave | Tipo | Default | Descrizione |
|---|---|---|---|
filters | ContextFilters | — | Pipeline dichiarativa di filtri applicati da CoreContext.setData prima di scrivere il context e di notificare i subscriber. Una funzione per chiave del context, sync only. Uso avanzato — vedi ContextFilters nel core. |
Esempio completo (TCF + custom + UI tweak)
{
"publisherCountryCode": "IT",
"language": "it",
"policyVersion": 2,
"consentExpiryDays": 365,
"core": { "autoInit": true, "autoLoad": true },
"store": { "type": "cookie", "consentKey": "avacy_consent" },
"loggers": ["console"],
"assetPath": "https://cdn.example.com/avacy",
"remoteConfigName": "config.json",
"frameworks": [
{
"tcf": {
"cmpId": 297,
"frameworkVersion": 2,
"vendors": "all",
"purposeOneTreatment": false,
"enableLegInt": "all",
"objectLegIntOnReject": true
}
},
{
"custom": {
"customVendorsConfigName": "custom-vendors.json"
}
}
],
"ui": {
"behavior": {
"closeWithoutConsents": "text",
"closePreferencesOnBulkSelect": true
}
},
"customLabels": {
"it": {
"ACCEPT_ALL_BTN": "Acconsento"
}
}
}
See also
init— boot programmatico con override config- Tier 2 —
getConfig— snapshot read-only della config dopo il merge inline + remote