Passa al contenuto principale

Add-on

Un add-on è un pezzo del banner che non sta nel bundle: un file a parte, scaricato solo dai webspace che lo usano. Oggi sono tre:

Add-onFaseCosa fa
preemptive-blockpreSblocca gli script e gli iframe marcati nell'HTML quando c'è il consenso che chiedono
consent-archivepostInvia ogni scelta del visitatore all'archivio consensi del webspace
tcf-stubpreInstalla subito lo stub IAB __tcfapi sui webspace con TCF

Sorgenti: packages/addons/<nome>/.


Come si accendono​

Un add-on è acceso quando compare in addons[] della config, con la stessa forma di frameworks[]:

{
"addons": [
"preemptive-block",
{ "consent-archive": { "url": "https://…/consents" } }
]
}

Il nome da solo usa le impostazioni di default dell'add-on; la forma a oggetto passa le impostazioni. Il core deduplica per nome. Dettaglio della chiave: Config › Add-on.

Chi scrive addons[]: il SaaS, nel banner.json del webspace. Il cliente non lo compila a mano:

  • consent-archive dal toggle di archiviazione automatica dei consensi, con l'URL generato dal SaaS;
  • preemptive-block quando almeno un fornitore custom del webspace ha URL di blocco preventivo;
  • tcf-stub non sta in addons[] del SaaS: lo aggiunge il loader quando frameworks contiene tcf (vedi sotto).

Chi li scarica: il loader v3, e solo lui. Legge addons[] da banner.json, scarica da /v3/addons/<nome>/<versione>/index.js quelli che fanno parte della release (il manifest è dentro il loader) e consegna ciascuno al core. Un nome che la release non conosce viene ignorato con un warning in console ([avacy-loader] '<nome>' is not part of this release; ignored.). Nell'inclusione manuale il loader non c'è e nessun add-on viene scaricato.

pre e post​

FaseQuando si scaricaIl boot lo aspetta?
preSubito, in parallelo con il bundleSì: init() aspetta i pre annunciati dal loader fino a core.addonsTimeoutMs (default 1500 ms, in tutto)
postDopo il primo avacy:readyNo

Un add-on che arriva tardi (un pre oltre il timeout, ogni post) parte comunque appena si registra, e recupera gli eventi che si è perso: il core gli passa la storia del boot. Un add-on che non si scarica viene segnalato in console dal loader ([avacy-loader] add-on '<nome>' failed to load); uno che fallisce il setup viene saltato e segnalato nei log del CMP (visibili con loggers). In entrambi i casi il banner va avanti senza.

Override dalla pagina​

Un addons scritto nel blocco #avacy-config sostituisce la lista che il core avvia (gli array non si fondono). Quindi dalla pagina si può:

  • spegnere un add-on del webspace, lasciandolo fuori dalla lista;
  • cambiarne le impostazioni, riscrivendo la sua voce.

Non si può accenderne uno che il SaaS non ha attivato: la lista dei file da scaricare il loader la prende solo da banner.json, e un add-on mai scaricato non c'è.

<!-- spegne consent-archive su questa pagina, tiene preemptive-block -->
<script type="application/json" id="avacy-config">
{ "addons": ["preemptive-block"] }
</script>

Attenzione: la lista in pagina prende il posto di quella di banner.json per intero, tcf-stub compreso. Su un webspace TCF va ripetuto: { "addons": ["preemptive-block", "tcf-stub"] }.


preemptive-block​

Fase pre. Il blocco vero lo fa il markup: uno script con un type che il browser non esegue, un iframe senza src. L'add-on fa solo il contrario: quando c'è un consenso valido che soddisfa i requisiti dell'elemento, lo rimette com'era. Senza l'add-on acceso, gli elementi marcati restano bloccati per sempre.

Impostazioni:

ChiaveTipoDefaultDescrizione
placeholderbooleanfalseDisegna un segnaposto dentro ogni iframe ancora bloccato, con un testo e un bottone che apre le preferenze. Vedi Segnaposto.

Marcare uno script​

<!-- script esterno -->
<script type="text/avacy-blocked"
data-avacy-src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"
data-avacy-requires="gcm:purpose:4"></script>

<!-- script inline -->
<script type="text/avacy-blocked"
data-avacy-requires="gcm:purpose:4">
window.dataLayer = window.dataLayer || [];
function gtag(){ dataLayer.push(arguments); }
gtag('js', new Date());
gtag('config', 'G-XXXX');
</script>

<!-- modulo ES -->
<script type="text/avacy-blocked"
data-avacy-type="module"
data-avacy-src="https://example.com/widget.mjs"
data-avacy-requires="custom:vendor:d116"></script>
AttributoObbligatorioDescrizione
type="text/avacy-blocked"sì (in pratica)Impedisce al browser di eseguire lo script. L'add-on non legge questo valore: qualunque type non eseguibile funziona, ma text/avacy-blocked è la convenzione.
data-avacy-requiressìI requisiti di consenso, vedi sotto. È l'attributo che marca l'elemento: senza, l'add-on non lo vede.
data-avacy-srcper gli script esterniL'URL vero. Assente o vuoto = script inline (il contenuto del tag).
data-avacy-typenoIl type da rimettere allo sblocco, es. module. Assente = script classico.

Allo sblocco lo script viene sostituito da un nodo nuovo (un type cambiato su un nodo già in pagina non lo farebbe partire), con gli stessi attributi tranne quelli di blocco.

Marcare un iframe​

<iframe data-avacy-src="https://www.youtube.com/embed/XXXX"
data-avacy-requires="custom:vendor:d42"
width="560" height="315"></iframe>

L'iframe si scrive senza src; l'add-on lo rimette da data-avacy-src allo sblocco.

Sintassi di data-avacy-requires​

data-avacy-requires="custom:vendor:d116;tcf:purpose:1,8,9"
  • Un requisito è framework:asse:id, esattamente tre pezzi separati da :.
  • ; separa i requisiti. Tutti devono essere soddisfatti (AND).
  • Più id separati da , nello stesso requisito sono anch'essi in AND: tcf:purpose:1,8,9 vuol dire 1 e 8 e 9.
AsseCosa controllaEsempio
vendorconsenso al fornitoretcf:vendor:755, custom:vendor:d116, acm:vendor:89
purposeconsenso alla finalità (per custom legge le finalità custom)tcf:purpose:1, gcm:purpose:4, custom:purpose:3
customPurposeconsenso a una finalità custom (stesso effetto di custom:purpose)custom:customPurpose:3
specialFeatureconsenso a una special feature TCFtcf:specialFeature:1
legintlegittimo interesse (non consenso) sulla finalitàtcf:legint:2

framework è il nome di un framework della config: tcf, gcm, custom, acm. Gli id sono quelli del framework: numeri per TCF/GCM/ACM, id testuali per i fornitori custom (d116). I purpose GCM vanno da 1 a 7 (4 = analytics_storage; elenco completo in Config › GCM).

Regole di valutazione:

  1. Serve un consenso valido. Prima della scelta del visitatore non si sblocca niente.
  2. Un id che non compare tra le scelte non è concesso: un fornitore tolto dalla lista non apre nulla.
  3. Framework non configurato. Un requisito su un framework che il webspace non ha (es. tcf:purpose:1 senza TCF in frameworks) ripiega sul fornitore custom della stessa marcatura: è soddisfatto se i requisiti custom:vendor:… dell'elemento sono concessi. Senza un fornitore custom nella marcatura, l'elemento resta bloccato.
  4. Marcatura illeggibile ⇒ bloccato. Un asse sconosciuto, un requisito senza id, più di tre pezzi (: scritto al posto di ;): l'elemento resta bloccato, con una riga di log (unreadable marking, left blocked). Mai sbloccato per errore.
  5. Attributo vuoto (data-avacy-requires=""): nessun requisito, l'elemento si sblocca al primo consenso valido, qualunque sia, anche un rifiuto totale.

Non esiste una forma "tutte le finalità": se servono tutte, si elencano.

Ordine e ritiro del consenso​

  • Gli elementi si sbloccano nell'ordine del documento. Gli script esterni scaricano in parallelo ma si eseguono in ordine; uno script inline aspetta che gli esterni sopra di lui siano caricati (max 5 secondi l'uno), così gtag('config', …) trova gtag.js già pronto.
  • Ogni nuovo consenso rivaluta gli elementi ancora bloccati: un consenso più ampio sblocca quello che ora è concesso.
  • Non ri-blocca mai: uno script già partito non si può fermare. Se il visitatore ritira un consenso, l'effetto si vede al caricamento di pagina successivo.

Segnaposto degli iframe​

Con placeholder: true, ogni iframe ancora bloccato mostra un piccolo documento (via srcdoc) con il testo IFRAME_BLOCKED_TEXT e un bottone IFRAME_BLOCKED_BTN che apre il pannello preferenze. Il segnaposto c'è anche prima di qualunque scelta, e sparisce allo sblocco (un eventuale sandbox dell'iframe viene sospeso durante il segnaposto e rimesso prima di caricare il contenuto vero).

I colori vengono dal tema del webspace (ui.colors.backgroundColor, textColorSecondary, btnCustomizeBackground, btnCustomizeTextColor, ui.font.fontFamily). Il CSS del sito può sovrascriverli su :root:

:root {
--avacy-placeholder-bg: #f5f5f5;
--avacy-placeholder-fg: #222;
--avacy-placeholder-radius: 8px;
--avacy-placeholder-font: Inter, sans-serif;
--avacy-placeholder-accent: #0060e6;
--avacy-placeholder-accent-fg: #fff;
}

I due testi sono tradotti in en, it e de; nelle altre lingue escono in inglese (si possono impostare con customLabels).

Marcatura legacy (data-managed="as-oil")​

L'add-on legge anche la marcatura del banner legacy, quella che scrivono i siti col plugin WordPress precedente o i temi marcati a mano. Gli attributi si traducono per nome:

LegacyEquivale a
data-managed="as-oil"data-avacy-requires (marca l'elemento)
data-srcdata-avacy-src
data-typedata-avacy-type
data-custom-vendor="d116"custom:vendor:d116
data-iab-vendor="755"tcf:vendor:755
data-purposes="1,2,4"tcf:purpose:1,2,4
data-legints="2"tcf:legint:2
data-special-features="1"tcf:specialFeature:1

Stesse regole del formato nuovo: tutto in AND, attributo assente = nessun requisito su quell'asse, attributo presente ma vuoto (data-purposes="") = elemento lasciato bloccato. → Migrazione dal banner legacy.


Fase post. Invia ogni scelta del visitatore sul banner all'archivio consensi del webspace (la "prova del consenso"). È il sostituto di sendConsent del banner legacy.

ChiaveTipoDefaultDescrizione
urlstring— (obbligatoria)Endpoint dell'archivio, <api>/<tenant>/v4/webspaces/<uuid>/consents. Lo scrive il SaaS. Senza url l'add-on fallisce al setup e viene saltato; il banner parte lo stesso.

Cosa invia, e quando​

Una POST JSON per ogni decisione presa con un bottone del banner o del pannello preferenze:

{ "consent_type": "banner", "optin": "consent-all", "uuid": "…" }
optinBottone
consent-all"Accetta tutto" (banner o pannello)
reject-all"Rifiuta tutto" (banner o pannello)
close-banner"Continua senza accettare" / la X del banner
save-preferences"Salva" nel pannello, anche quando le scelte risultano un accetta/rifiuta tutto

Niente TC String né scelte di dettaglio: IP, dominio e versioni delle policy li aggiunge il backend. Le scritture via API (window.Avacy.acceptAll(), updateConsent(), triggerConsent()…) non vengono archiviate: non corrispondono a un bottone premuto.

Essendo post, l'add-on arriva dopo avacy:ready: una scelta fatta prima del suo arrivo viene recuperata dalla storia del boot e inviata con l'ora del click. Le richieste partono una alla volta, in ordine.

Id di correlazione​

La prima risposta dell'archivio contiene un uuid; l'add-on lo salva e lo manda in tutte le richieste successive, così le decisioni dello stesso visitatore restano legate.

  • Dove: dentro il record del consenso, avacy_consent.meta.consentId. L'add-on non scrive lo storage: chiede al core di aggiornare il record (host.consent), che parte come avacy:consent-updated, non come una nuova scelta. Una scelta successiva si porta dietro l'id. Se lo store non tiene il record, l'id resta solo in memoria per la pagina.
  • Release precedenti: la chiave a sé ${store.consentKey}_id (avacy_consent_id con la config di default) viene migrata nel record al boot e poi cancellata.
  • Azzeramento: se all'avvio non c'è un consenso valido (prima visita, consenso scaduto, policyVersion alzata), l'id viene cancellato e la catena riparte.

In caso di errore​

Best effort: timeout 15 s, keepalive, nessun cookie inviato (credentials: 'omit'), nessun retry. Un archivio lento o giù non blocca mai il salvataggio del consenso né il banner; l'errore finisce nei log del CMP come warning.


tcf-stub​

Fase pre. Installa lo stub ufficiale IAB (@iabtechlabtcf/stub): un window.__tcfapi minimo che risponde a ping con cmpStatus: 'stub' e mette in coda gli altri comandi finché il CMP vero non prende il controllo. Senza, un fornitore che chiama __tcfapi prima del banner riceve un errore e spesso rinuncia per tutta la pagina.

  • Acceso dal loader, non dal SaaS: se frameworks di banner.json contiene tcf, il loader lo aggiunge sia ai download sia ad addons[]. Un webspace senza TCF non ha __tcfapi.
  • Si fa da parte se trova già una funzione window.__tcfapi (lo stub incluso a mano, il CMP già partito, un altro CMP): non la sovrascrive.
  • Arriva tardi per i primissimi istanti: parte dentro init(), dopo banner.json, il bundle e il proprio file. Un fornitore che chiama __tcfapi prima può ancora non trovarlo.

Un sito che non può permettersi quella finestra, e chi fa l'inclusione manuale, include lo stub come script sincrono nell'<head>, prima di qualunque script che chiami __tcfapi:

<script src="https://<tenant>.avacy-cdn.com/v3/web/<versione>/tcf-stub.js"></script>

Con lo stub già in pagina, l'add-on vede __tcfapi e non fa nulla.