Skip to main content

Config reference

AvacyUserConfig (Partial<UserConfigType> + alcune estensioni Tier 1) è la forma di tutte le sorgenti di config: il banner.json del webspace pubblicato dal SaaS (lo scarica il loader v3), il blocco <script type="application/json" id="avacy-config"> in pagina e l'argomento di init(config). 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 (AvacyUserConfig con core.autoInit)
  • packages/cmp-web/src/init.ts + packages/core/src/merge-config.ts (merge delle sorgenti in pagina)
  • packages/core/src/providers/config.ts (merge con DEFAULT_CONFIG e con remoteConfigUrl/remoteConfigName)
type AvacyUserConfig = Partial<UserConfigType> & {
core?: Partial<UserConfigType['core']> & { autoInit?: boolean };
};

Precedenza tra le sorgenti​

La config effettiva nasce da più sorgenti. Dalla più forte alla più debole:

  1. Locale, cioè quello che sta nella pagina o la gestisce. In ordine: l'argomento di init(config), il flag di debug (loggers), window.avacyFilters (filters), il blocco #avacy-config. L'argomento di init() conta solo al primo boot e solo se chiami tu init() (import della libreria): il loader v3 lo chiama senza argomento, e un window.Avacy.init(config) successivo è un no-op.
  2. Remota: il banner.json del webspace, scaricato dal loader v3. Il loader ci scrive sopra assetPath, che punta agli asset della release: anche questo, quindi, cede a un assetPath scritto in pagina.
  3. Base: DEFAULT_CONFIG del core.

Il merge è profondo sugli oggetti (a qualunque livello) e sostituisce gli array. Un #avacy-config con solo { "ui": { "behavior": { "showShield": false } } } cambia quel campo e tiene colori, font e il resto di ui di banner.json. Un array scritto in pagina (frameworks, addons, loggers, …) invece prende il posto di quello remoto per intero: chi lo scrive lo fa apposta.

Due eccezioni:

  • cmpVersion e core.autoLoad li impone il bundle, qualunque sorgente li scriva.
  • Gli add-on da scaricare li decide solo banner.json. Un addons in pagina sostituisce la lista che il core avvia, quindi può spegnere un add-on del webspace o cambiarne le impostazioni. Non può accenderne uno che il SaaS non ha attivato: il loader non lo scarica.

Senza blocco inline e senza debug vale banner.json, con l'assetPath della release, sopra DEFAULT_CONFIG.

Due merge diversi​

  • Sorgenti in pagina (banner.json dal loader, #avacy-config, debug, avacyFilters, argomento di init()): merge profondo di mergeConfigLayers, come descritto sopra.
  • remoteConfigUrl / remoteConfigName (vedi sotto): il file lo scarica il core e lo fonde piatto sotto la config che ha ricevuto: ogni chiave di primo livello scritta in pagina sostituisce quella remota per intero. Fanno eccezione core (fuso chiave per chiave) e ui, fuso un namespace alla volta (behavior, colors, font, layout, branding): dentro ogni namespace vince la pagina campo per campo, ma frameworks[0].tcf scritto in pagina, per esempio, rimpiazza tutto frameworks remoto.

Identità e versionamento​

ChiaveTipoDefaultDescrizione
publisherCountryCodestring (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.
policyVersionnumber1Versione della policy interna. Cambiandola si invalida automaticamente il consenso salvato (forza un re-consent al prossimo boot).
cmpVersionstringversione del pacchettoVersione del CMP scritta nei metadati del consenso. Il bundle la impone a ogni boot con la versione di @avacy/cmp-web (oggi '3.0.0', la stessa di window.Avacy.version): un valore scritto in config viene ignorato. Il '1.0.0' di DEFAULT_CONFIG vale solo per chi usa @avacy/core da solo.
consentExpiryDaysnumber180Scadenza del consenso in giorni (parità con cookie_expires_in_days del banner legacy). Un consenso più vecchio di tanto viene considerato non valido (consent.valid: false), il banner riappare. Un valore non numerico o ≤ 0 ricade su 180 con un warning. Governa anche la durata del cookie; quando il banner ricompare e il limite dei browser a 400 giorni: Durata del consenso.

Boot e auto-init​

core?: {
autoInit?: boolean; // solo loader Stencil `dist` di cmp-web
autoLoad?: boolean; // core
addonsTimeoutMs?: number; // core
}
ChiaveTipoDefaultDescrizione
core.autoInitbooleantrueLetta solo dal loader Stencil dist di @avacy/cmp-web (il pacchetto dietro un bundler), e solo dal blocco #avacy-config: con false quel loader non avvia il CMP e bisogna chiamare init(). Il loader v3 e cmpweb-web.auto.esm.js la ignorano e avviano comunque; cmpweb-web.esm.js non avvia mai da solo. Vedi Lifecycle › init e il boot programmatico nel Getting Started.
core.autoLoadbooleantrueFlag del solo @avacy/core, per chi chiama initCore direttamente. Se true, al termine di Core.init viene invocato triggerLoad() (emissione OnLoad listener chain). Se false, triggerLoad deve essere chiamato esplicitamente. Il bundle cmp-web lo forza a false e chiama triggerLoad() da sé: un valore nel #avacy-config viene ignorato.
core.addonsTimeoutMsnumber1500Quanto init() aspetta, in tutto, gli add-on pre che il loader ha annunciato, prima di proseguire senza. 0 = non aspettare. Un valore negativo o non numerico ricade su 1500 con un warning. Un add-on che arriva dopo parte comunque appena si registra.

Lingua​

ChiaveTipoDefaultDescrizione
languageLanguageCode (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.
autoLanguagebooleanfalseQuando 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.
customLabelsPartial<Record<LanguageCode, Partial<LanguageLabels>>>undefinedOverride partiali delle label per lingua. Precedenza: customLabels[lang] > remote labels > prebundled[lang] > prebundled fallback. Chiavi sconosciute vengono mergiate ma loggate come warning.

Lingue disponibili​

en, it e de sono compilate nel bundle. Per qualunque altra lingua il core scarica {assetPath}/languages/{lang}.json e lo fonde sopra l'inglese (LanguageProvider.loadLanguageData); se il file non c'è, resta l'inglese con un warning.

La release spedisce 32 file in assets/languages/ (sorgente: packages/core/public/assets/languages/):

ar, bg, bs, ca, cs, cy, da, el, es, eu, fi, fr, gl, he, hr, hu, id, ja, ko, lt, lv, mk, mt, nl, no, pl, pt, ro, ru, sl, uk, zh.

Ognuno ha tutte le label del banner e del CPC (59 su 61) più i nomi delle finalità GCM. Mancano in tutti solo IFRAME_BLOCKED_TEXT e IFRAME_BLOCKED_BTN, i testi del segnaposto dell'add-on preemptive-block, che in quelle lingue escono in inglese.

Con il loader v3 assetPath punta già agli asset della release, quindi non c'è niente da configurare. In inclusione manuale serve un assetPath corretto per ogni lingua diversa da en/it/de.

Nota a margine (limite noto): il core non imposta dir="rtl" né adatta il layout per lingue right-to-left, quindi ar e he hanno testo tradotto 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.

PlaceholderRisolve aReteDisponibile 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.NoNo
{{cookie_policy_url}}Come sopra, per COOKIE_POLICY_URL/LABEL_COOKIE_POLICY.NoNo

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;
}
ChiaveTipoDefaultDescrizione
store.typeStoreType'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.consentKeystring'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.


Add-on (addons)​

addons: (string | { [name: string]: Record<string, unknown> })[];
ChiaveTipoDefaultDescrizione
addonsAddonItem[][]Gli add-on attivi nel webspace, stessa forma di frameworks: il nome da solo ('preemptive-block') oppure un oggetto a una chiave con le impostazioni ({ "consent-archive": { "url": "…" } }). Il core normalizza tutto alla forma a oggetto e deduplica per nome: conta la prima posizione, le impostazioni delle voci successive si fondono sopra. Voci malformate (null, array, oggetti con più chiavi) vengono scartate con un warning.

Chi scarica gli add-on è il loader v3, e legge la lista solo da banner.json. Un addons scritto in pagina sostituisce la lista che il core avvia: può spegnere un add-on del webspace o cambiarne le impostazioni, non accenderne uno che il SaaS non ha attivato. Dettagli, impostazioni di ogni add-on e tempi di attesa (core.addonsTimeoutMs) in Add-on.

Archivio consensi​

Non è più una chiave di primo livello: è l'add-on consent-archive, acceso con una voce di addons[]. L'endpoint è il suo settaggio url, senza default: una voce senza url fa fallire l'add-on al setup, e il banner parte lo stesso.

{ "addons": [{ "consent-archive": { "url": "{API_URL}/{tenant}/v4/webspaces/{uuid}/consents" } }] }

Nella dashboard SaaS non è un campo che il cliente scrive a mano: la voce la scrive il SaaS dal toggle "Archiviazione dei consensi", con l'URL del proprio backend. Cosa invia, quando e dove tiene l'id di correlazione: vedi Add-on › consent-archive.


Asset path e remote config​

ChiaveTipoDefaultDescrizione
assetPathstring'/assets'Base path (o URL CDN) degli asset della release: file lingua ({assetPath}/languages/{lang}.json), immagini (shield, watermark), e i file indicati per nome con remoteConfigName, custom.customVendorsConfigName, acm.acmProvidersConfigName. Non governa la GVL TCF, che ha un suo URL (tcf.gvlUrl). Un path relativo viene completato con l'origine della pagina. Il loader v3 lo imposta da sé sugli asset della release.
remoteConfigNamestring—Filename di una config remota sotto assetPath, scaricata dal core (non dal loader v3). Nessun default: se mancano sia remoteConfigName sia remoteConfigUrl, il core non scarica niente. Merge piatto sotto le sorgenti in pagina, vedi Due merge diversi. Se il download fallisce il boot prosegue senza, con un warning.
remoteConfigUrlstring—URL assoluto della config remota, alternativo a remoteConfigName (ignora assetPath). Se sono presenti entrambi, remoteConfigUrl vince — stessa precedenza di customVendorsUrl/acmProvidersUrl sui rispettivi *ConfigName.
remoteGVLNamestring—Presente nel tipo ma non letto da nessuno: non deriva tcf.gvlUrl, non ha effetto.
vendorsCountnumberderivatoOverride 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: { … } }])​

ChiaveTipoDefaultDescrizione
cmpIdnumber297CMP ID assegnato da IAB Europe. Per Avacy: 297.
frameworkVersionnumber2Versione TCF (2 = TCF v2).
vendorsnumber[] | 'all''all'Lista vendor abilitati. 'all' = tutti i vendor del GVL attivo.
gvlUrlstring'https://demo.avacy-cdn.com/assets/v3/'Base URL della GVL (il GVL.baseUrl di @iabtechlabtcf/core). Non dipende da assetPath.
purposeOneTreatmentbooleanfalseFlag 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.
objectLegIntOnRejectbooleantrueSu RejectAll: se true, azzera anche hasLegitimateInterest. Se false, lascia LI al valore corrente e flippa solo hasConsent.
enableAdvertiserConsentModebooleantrue (se assente)Flag di Google enableAdvertiserConsentMode in ogni risposta TCData di __tcfapi (anche getInAppTCData): i tag Google ricavano Consent Mode dalla TC String. Non dipende da GCM, come nel banner legacy. Con false il campo non viene scritto. Senza fornitori IAB (vendors: []) il flag resta sempre spento, qualunque sia il valore: le finalità 1, 3, 4 e 7 da cui Google ricava i segnali dipenderebbero solo dai fornitori custom.
stacksnumber[](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.

⚠️ Eccezione: i fornitori custom contano anche loro. Se un fornitore custom dichiara un purpose TCF (CustomVendorConfig.purposes: [{framework: 'tcf', id}]) o una special feature (specialFeatures: [id], id IAB nudi), quella voce resta nel CPC anche se nessun vendor TCF superstite la dichiara, e il conteggio fornitori mostrato accanto somma le due fonti. Non è solo visibile: il toggle è attivabile, "accetta tutto" la accende e il consenso finisce nella TC String, come per una voce dichiarata da un vendor IAB. Special purpose e feature non hanno questa via: per loro il filtro dipende solo da vendors.

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:

  1. 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.
  2. Accenderla per un sottoinsieme (enableLegInt: { purposes: [...] } o { vendors: [...] }) restringe solo le altre combinazioni — non è "tutto o niente".
  3. Il legittimo interesse resta comunque vietato per i purpose 1, 3, 4, 5, 6 in TCF v2.2: accendere enableLegInt non 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 flag useNonStandardTexts nella TC String, oggi sempre false.
  • 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 segue ui.behavior.preferencesOrder: chi riordina le sezioni del CPC riordina anche la frase del banner.

GCM (frameworks: [{ gcm: { … } }]) — Google Consent Mode v2​

GCM si accende mettendolo in frameworks ('gcm' o { gcm: {…} }): non c'è un flag enabled. Da quel momento il SaaS scrive il flag gcm nel KeyValueStore della CDN, e la CDN serve la variante gcm del loader: questa chiama gtag('consent', 'default', …) con tutti e 7 i tipi a denied e wait_for_update: 500, in modo sincrono, prima dei tag Google. Il core chiama gtag('consent', 'update', …) quando legge un consenso salvato o ne scrive uno nuovo (crea dataLayer e gtag se la pagina non li ha). Con l'inclusione manuale del bundle il default va messo in pagina a mano. Gli stessi stati arrivano in avacy:consent-saved come detail.gcm.

I 7 purpose GCM, in ordine di id: 1 ad_storage, 2 ad_user_data, 3 ad_personalization, 4 analytics_storage, 5 functionality_storage, 6 personalization_storage, 7 security_storage.

ChiaveTipoDefaultDescrizione
remoteGVLNamestring—Presente nel tipo ma non letto da nessuno: nessun effetto.
mapToPurposeGcmMapToPurposeEntry[]—"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: { … } }])​

ChiaveTipoDefaultDescrizione
customVendorsUrlstring—URL assoluto del JSON con vendor/purpose custom. Mutualmente esclusivo con customVendorsConfigName.
customVendorsConfigNamestring—Filename del config custom sotto assetPath. Risolto come assetPath + '/' + customVendorsConfigName.
customVendorsConfigCustomVendorsConfig (inline)—Config inline (evita la fetch HTTP). Utile per test e siti statici.
customFetchtypeof fetchwindow.fetchOverride 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.
objectLegIntOnRejectbooleantrueVedi tcf.objectLegIntOnReject.
ChiaveTipoDefaultDescrizione
acmProvidersUrlstring—URL assoluto della lista ATP (Google Additional Tech Provider).
acmProvidersConfigNamestring—Filename ATP sotto assetPath.
acmProvidersConfigAcmProvidersConfig (inline)—Config inline.
acmFetchtypeof fetchwindow.fetchOverride fetch.
vendorsnumber[] | 'all''all'Sottoinsieme dei provider ATP da esporre. Con un array restano solo gli id elencati: consenso, CPC e stringa codificata si restringono a quelli. Speculare a tcf.vendors.

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.layout, ui.branding, ui.font e ui.colors sono documentati più sotto.

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.

ChiaveTipoDefaultDescrizione
ui.behavior.showRejectAllButtonbooleantrue nella build base, false esplicito per RAIBottone "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ì, la dashboard v3 scrive ui.behavior.showRejectAllButton. Vedi sotto per il vincolo con closeWithoutConsents.
ui.behavior.closeWithoutConsentsboolean | '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'. Disponibile da SaaS: sì.
ui.behavior.activateVendorsOnLegalScopeSelectionsbooleanfalseSe true, abilitare un purpose / special feature nel CPC abilita automaticamente i toggle dei vendor che lo supportano.
ui.behavior.hideIntroOnScrollbooleanfalseSe 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.closePreferencesOnBulkSelectbooleantrueSe 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.showPrivacyPolicyLinkbooleanfalseMostra 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.showCookiePolicyLinkbooleanfalseCome 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.showShieldTooltipbooleanfalseSe 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.closeWithoutSavingbooleanfalsePulsante "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ì, la dashboard v3 scrive ui.behavior.closeWithoutSaving.
ui.behavior.showConsentRetentionSectionbooleantrue nella build baseAggiunge 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ì, la dashboard v3 scrive ui.behavior.showConsentRetentionSection.
ui.behavior.showShieldbooleantrueShield persistente post-consenso (avacy-shield, l'icona che riapre il CPC). Con false non viene mai montato: utile quando il sito ha già un proprio link "Gestisci consenso" (showPreferenceCenter). Disponibile da SaaS: sì.
ui.behavior.preferencesOrderstring[]DEFAULT_PREFERENCES_ORDEROrdine delle voci di nav (e delle sezioni) del CPC. Ogni voce è un id ${framework}::${tipo} (es. 'tcf::purpose', 'tcf::vendor', 'custom::vendor') oppure le voci extra 'glossary' e 'retention'. Id senza voce a runtime vengono saltati; voci non elencate restano in coda nel loro ordine naturale. Lo stesso ordine governa {{basis_names}} nel primo layer.

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 (ConfigProvider.normalizeUiBehavior, packages/core/src/providers/config.ts).

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, condizione closeWithoutSaving === 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 (vedi Colori). Disponibile da SaaS: non come picker dedicato — i picker "Pulsanti" della dashboard v3 scrivono gli stessi valori su tutti i ruoli bottone, questo compreso.
  • Il testo del pulsante è la label PREFERENCES_CLOSE_BTN, tradotta in tutte le lingue disponibili (vedi Lingue disponibili).

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.

  1. I tre placeholder nel copy ({{storage_technology}}, {{item_name}}, {{expires_in_days}}, vedi sopra "Placeholder nel copy") — esistono da sempre, guidati dal testo di PREFERENCES_TEXT, non da un flag. Oggi li usa solo RAI.
  2. 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 "180 giorni"), quindi non è sovrascrivibile. Le etichette della sezione sono tradotte in tutte le lingue disponibili. 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.

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 labelDescrizione
PRIVACY_POLICY_URLURL della propria Privacy Policy. Vuota di default — va impostata dal cliente.
COOKIE_POLICY_URLURL della propria Cookie Policy. Vuota di default.
LABEL_PRIVACY_POLICYTesto del link. Default "Privacy Policy" (en/it), "Datenschutzerklärung" (de) — override solo se si vuole un testo diverso.
LABEL_COOKIE_POLICYTesto 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"
}
}
}

Layout (ui.layout)​

ChiaveTipoDefaultDescrizione
ui.layout.bannerPosition'bottom' | 'top' | 'center''bottom'Lato del viewport a cui è ancorato il banner. Disponibile da SaaS: sì.
ui.layout.bannerFloatingbooleantruetrue: card staccata dai bordi, con ombra e angoli arrotondati. false: edge-to-edge. Ignorata con bannerPosition: 'center', che è sempre floating.
ui.layout.bannerAnimationfalse | 'FadeIn' | 'SlideIn''FadeIn'Animazione d'ingresso. SlideIn scorre dal basso con bottom e dall'alto con top; con center ricade su FadeIn. prefers-reduced-motion vince sempre. Disponibile da SaaS: sì.

Le combinazioni valide sono cinque: bottom/top × floating/edge, più center. Quando il CMP gira in un iframe usa il layout compatto e questi tre campi non hanno effetto.

Per chi migra dal legacy: PositionBottom/PositionTop/PositionCenter → bottom/top/center; banner_animation: "Floating" non era un'animazione ma un layout, e corrisponde a bannerFloating: true con bannerAnimation: false.

Branding (ui.branding)​

ChiaveTipoDefaultDescrizione
ui.branding.enableBrandingfalse | '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.logoUrlstringassenteLogo 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.shieldIconUrlstringassenteIcona 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, senza distinzioni per tenant. Nella dashboard SaaS però non è un campo self-service: oggi l'unico tenant che riceve un valore è EasyConsulting, iniettato lato backend (EasyConsultingOverrides.php). Il colore dello shield invece lo scrive la dashboard v3 per tutti: il picker "Link e interazioni" valorizza ui.colors.shieldColor (insieme a link, tab, checkbox e notice). Chi scrive config direttamente non ha restrizioni: è una policy del SaaS, non un vincolo 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 */
}
VariabileDefaultDescrizione
--avacy-shield-offset-bottom1remDistanza dal bordo inferiore della pagina.
--avacy-shield-offset-side1remDistanza 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)​

ChiaveTipoDefaultDescrizione
ui.font.fontFamilystring'Arial, Helvetica, sans-serif'Font-family per corpo, titoli e label — una sola chiave per tutte e tre le famiglie. Un valore vuoto o di soli spazi non emette nessuna custom property e resta il default del design system. Disponibile da SaaS: sì — la dashboard v3 offre una tendina di font web-safe più un campo per un font custom, e scrive ui.font.fontFamily. Il CMP non scarica il webfont: un font non di sistema deve caricarlo il 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)​

64 campi, tutti opzionali: un campo assente prende il valore di DEFAULT_CONFIG.ui.colors, che li valorizza tutti (le custom property dei colori non hanno un fallback CSS proprio: a differenza del font, il valore arriva sempre dalla config). La dashboard v3 li scrive tutti, raggruppati in 10 picker che scrivono lo stesso valore su più campi. 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:

  1. I campi bottone sono nominati per ruolo business, non per stile. Non esistono primary/secondary/outline/text come 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.
  2. textColorPrimary e textColorSecondary sono invertiti rispetto al nome. Eredità del legacy: textColorPrimary è il testo secondario/muto (chiaro), textColorSecondary è il testo principale (scuro). Vedi il box sotto.
  3. 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.

RuoloDoveBackgroundBackground hoverTestoAltro
Accept (Accetta tutto)bannerbtnAcceptBackgroundbtnAcceptBackgroundHoverbtnAcceptTextColor—
Reject (Rifiuta tutto, PBI 19)bannerbtnRejectBackgroundbtnRejectBackgroundHoverbtnRejectTextColorDefault identico ad Accept — nessun colore "negativo" dedicato, decisione in attesa di review Design.
Customize (Personalizza → apre CPC)banner + shieldbtnCustomizeBackgroundbtnCustomizeBackgroundHoverbtnCustomizeTextColorStesso ruolo/colore in entrambi i punti, anche se rendono con forme diverse.
CloseWithoutConsent ("Continua senza accettare")bannerbtnCloseWithoutConsentBackgroundbtnCloseWithoutConsentBackgroundHoverbtnCloseWithoutConsentTextColor (+ 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)CPCbtnActivateAllBackgroundbtnActivateAllBackgroundHoverbtnActivateAllTextColor—
DeactivateAll (Disattiva tutto, CPC)CPCbtnDeactivateAllBackgroundbtnDeactivateAllBackgroundHoverbtnDeactivateAllTextColor—
Save (Salva e continua, CPC)CPCbtnSaveBackgroundbtnSaveBackgroundHoverbtnSaveTextColor—
CloseWithoutSaving ("Chiudi" del footer CPC, PBI 14)CPCbtnCloseWithoutSavingBackgroundbtnCloseWithoutSavingBackgroundHoverbtnCloseWithoutSavingTextColorDefault 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​

ChiaveCustom propertyDescrizione
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-bgSfondo principale di banner e CPC.
secondaryBackgroundColor--avacy-color-secondary-bgSfondo 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​

ChiaveCustom propertyDove/cosa
checkboxBorderColor--avacy-checkbox-border-colorBordo del checkbox non selezionato.
checkboxBackground--avacy-checkbox-bgSfondo del checkbox non selezionato.
checkboxBackgroundChecked--avacy-checkbox-bg-checkedSfondo del checkbox selezionato.
checkboxBorderChecked--avacy-checkbox-border-checkedBordo del checkbox selezionato — campo indipendente dal background.
checkboxCheckColor--avacy-checkbox-check-colorColore della spunta dentro il checkbox selezionato.
sliderBackground--avacy-toggle-track-bgTrack del toggle, stato spento.
sliderBackgroundChecked--avacy-toggle-track-bg-checkedTrack del toggle, stato acceso.
sliderBackgroundCircle--avacy-toggle-thumb-bgPallino/thumb del toggle.
tabDesktopTextColor--avacy-tab-desktop-colorTesto del tab desktop (sidebar) in hover/active — non confondere con tabTextColor.
tabIndicatorColor--avacy-tab-accent-colorIndicatore verticale del tab attivo (desktop).
tabColor--avacy-tab-colorTesto del tab desktop a riposo.
tabIndicatorColorInactive--avacy-tab-indicator-color-inactiveIndicatore verticale dei tab inattivi (desktop) — non confondere con tabIndicatorColor.
tabBackground--avacy-tab-fill-bgSfondo pieno del tab/pillola in hover/active, solo variante mobile. La variante desktop non riempie mai lo sfondo.
tabTextColor--avacy-tab-fill-colorTesto sopra tabBackground — stesso ambito, solo mobile.
linkColor--avacy-link-colorLink (CPC, glossario, shield).
linkColorHover--avacy-link-hover-colorLink in hover.
cpcBackground--avacy-cpc-bgSfondo del pannello CPC.
cpcTextColor--avacy-cpc-colorTesto principale del CPC.
cpcTextSecondaryColor--avacy-cpc-text-secondaryTesto secondario/muto del CPC.
cpcTitleColor--avacy-cpc-title-colorTitolo principale del CPC (es. "Privacy settings:"). Default #262628.
cpcBorderColor--avacy-cpc-border-colorDivisori tra le sezioni disclosure nella lista del CPC.
stackMembersBackground--avacy-cpc-stack-members-bgSfondo del box membri di uno stack IAB TCF (PBI 16) quando la card è espansa.
shieldColor--avacy-shield-primary-bgIcona persistente post-consenso (shield), solo quando non è un'icona custom con proprio fallback — vedi Branding sopra.
labelColor--avacy-label-colorLabel condivise (label del toggle, titolo accordion).
noticeBackground--avacy-notice-bgSfondo del componente notice (es. box di legittimo interesse).
noticeColor--avacy-notice-colorTesto e icona del notice (--avacy-notice-icon-color eredita in catena).
errorTextColor--avacy-color-error-textTesto di errore (es. caricamento fallito nella lista disclosure).
focusColor--avacy-color-focusOutline di :focus-visible, condiviso da tutti gli elementi interattivi, nessuna eccezione — un solo slot, non personalizzabile per singolo elemento. Default #282828. Il contrasto rispetto allo sfondo è responsabilità di chi sceglie il colore.
overlayBackground--avacy-overlay-bgOverlay scuro dietro banner e CPC. Accetta qualunque sintassi CSS color, incluso rgba con alpha.
scrollbarThumbColor--avacy-scrollbar-thumb-bgPallino/thumb della scrollbar custom (CPC).
scrollbarTrackColor--avacy-scrollbar-track-bgBinario della scrollbar custom (CPC).
disclosureSubtitleColor--avacy-disclosure-subtitle-colorSottotitolo nei pannelli disclosure (CPC).

Logger​

ChiaveTipoDefaultDescrizione
loggers('console' | 'event')[][] (silenzioso)Quali logger attivare. 'console' stampa info/warning/error su DevTools; 'event' emette ogni riga come evento DOM avacy:log ({ level, message, topic }). Combinabili. window.Avacy.setDebug(true) sostituisce l'intero array con ['console'] al prossimo boot (persiste in localStorage).

Filtri (advanced)​

ChiaveTipoDefaultDescrizione
filtersContextFilters—Pipeline dichiarativa di filtri applicati prima di scrivere un pezzo dello stato del CMP e di notificarlo (a getData(), agli eventi, alla UI). Una funzione per chiave dello stato, sync only. Dalla pagina si passa con window.avacyFilters.
consentFilter(choices: PrivacyChoice[], meta: ChangeMeta) => PrivacyChoice[]—Riscrive le scelte di un consenso prima che vengano codificate e salvate, così l'adattamento sopravvive al ricaricamento della pagina (un filtro filters.consent cambia solo lo stato in memoria). Sync e puro. meta porta il tipo risolto (type), quello richiesto (requestedType), lo screen e le scelte in vigore prima del salvataggio (currentChoices). Uso avanzato, pensato per le build custom.

Sono funzioni: non si possono scrivere in banner.json né nel blocco #avacy-config (JSON). filters arriva da window.avacyFilters o dall'argomento di init(config); consentFilter solo dall'argomento di init(config).

window.avacyFilters​

Tier 1. L'unico modo per passare filtri dalla pagina quando il CMP lo avvia il loader v3 (o cmpweb-web.auto.esm.js): il blocco #avacy-config è JSON e non può contenere funzioni, e l'argomento di init() lo usa solo chi avvia il CMP da sé. init() legge window.avacyFilters e lo usa come valore di filters.

window.avacyFilters = {
[K in keyof ContextData]?: (
next: ContextData[K], // il valore che sta per essere scritto
prev: ContextData[K] | undefined, // quello attuale
meta: ChangeMeta, // da dove viene la modifica
) => ContextData[K]; // il valore da scrivere davvero
};

type ChangeMeta = {
type?: string; // per un consenso: 'AcceptAll' | 'RejectAll' | 'Personalized' (il tipo salvato)
screen?: 'first' | 'second' | 'api';
source?: string; // 'listener' per una scrittura di consenso
};

meta è valorizzato quando il visitatore (o l'API) scrive un consenso; per il consenso riletto dallo storage al caricamento, e per le altre chiavi, è un oggetto vuoto.

Le chiavi sono quelle di getData(): consent, config, language, customization, glossary, stacks, standardTexts, storage, core… Regole:

  • Quando: va definito prima che init() parta, quindi in uno script sincrono prima del tag del loader. Una modifica successiva vale dal prossimo reload(), che lo rilegge.
  • Precedenza: sopra #avacy-config e sotto il flag di debug e l'argomento di init(config) (vedi Precedenza). Il merge è per chiave: un filters.consent passato a init(config) sostituisce solo quello di avacyFilters, gli altri restano.
  • Sync: la funzione deve restituire il valore, non una Promise.
  • Errori: se il filtro lancia un'eccezione, il CMP scrive un warning nei log e tiene il valore originale. Se restituisce null/undefined, vale il valore originale.
  • Solo in memoria: un filtro su consent cambia lo stato che vedono la pagina, gli eventi e la UI, ma non il consenso salvato nello storage né la TC String. Per cambiare quello che si salva serve consentFilter.
<script>
// Tiene sempre spento il fornitore custom d116 nello stato letto dalla pagina.
window.avacyFilters = {
consent(next) {
if (!next.ready || !next.valid) return next;
return {
...next,
choices: next.choices.map((c) =>
c.framework === 'custom' && c.type === 'vendor' && c.id === 'd116'
? { ...c, hasConsent: false }
: c,
),
};
},
};
</script>
<script src="https://<tenant>.avacy-cdn.com/v3/avacy-cmp-web.js?webspace=<uuid>"></script>

Esempio completo (TCF + custom + UI tweak)​

{
"publisherCountryCode": "IT",
"language": "it",
"policyVersion": 2,
"consentExpiryDays": 365,
"store": { "type": "cookie", "consentKey": "avacy_consent" },
"loggers": ["console"],
"assetPath": "https://cdn.example.com/avacy",
"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
  • Add-on — addons[] e le impostazioni di ogni add-on