# consent — CMP / IAB TCF / data brokers Operar banners de consentimiento (Consent Management Platforms) y el ecosistema IAB TCF: detectar qué CMP usa un sitio, leer cuántos *vendors* (data brokers) declara, aceptar el banner cuando hace falta y cruzar los IDs de vendor contra la Global Vendor List de IAB para nominar a cada broker y describir qué datos personales recopila. Nació de la investigación `projects/databrokers/` (data brokers de la prensa española). ## Funciones del grupo | ID | Firma corta | Qué hace | |---|---|---| | `extract_cmp_tcf_py_browser` | `extract_cmp_tcf(url, *, port=9222, accept_first=False, llm_fallback=False, ...) -> dict` | Navega a `url` por CDP, detecta el CMP (Didomi/OneTrust/Sourcepoint/Quantcast/otro_tcf), lee `window.__tcfapi` y devuelve nº de vendors, propósitos, muro "pago o consientes" y `vendor_ids`. Con `accept_first` acepta el banner antes de leer; con `llm_fallback` recurre a `find_consent_controls_llm` si el clic por selector falla. | | `find_consent_controls_llm_py_browser` | `find_consent_controls_llm(*, port=9222, max_candidates=40, model="claude-haiku-4-5-20251001") -> dict` | Recolecta los controles clicables del banner (los marca con `data-fnllm="N"`) y pregunta a un LLM (haiku) cuál es Aceptar / Rechazar / Ver socios. Devuelve los selectores. Resuelve CMP con clases dinámicas/texto no estándar sin selectores hardcodeados. | | `fetch_iab_gvl_py_cybersecurity` | `fetch_iab_gvl(out_path="", url="", lang="") -> dict` | Descarga y parsea la Global Vendor List de IAB (catálogo maestro de vendors: nombre, propósitos, `dataDeclaration`, retención, política). Endpoint v3 con fallback v2. | ## Ejemplo canónico (end-to-end) Escanear un medio, contar sus brokers y nombrarlos cruzando con la GVL: ```python import sys; sys.path.insert(0, "python/functions") from browser.extract_cmp_tcf import extract_cmp_tcf from cybersecurity.fetch_iab_gvl import fetch_iab_gvl # 1. Catálogo maestro de vendors (una vez). gvl = fetch_iab_gvl(out_path="/tmp/gvl.json") # {status, vendors:{id:{name,purposes,...}}, ...} # 2. Escanear un sitio (Chrome con CDP en el puerto indicado; perfil limpio para que salga el banner). # accept_first acepta el banner; llm_fallback usa haiku si el botón no encaja con selectores fijos. scan = extract_cmp_tcf("https://www.lavanguardia.com", port=9335, accept_first=True, llm_fallback=True) # scan -> {status, cmp:'didomi', n_vendors:1092, vendor_ids:[...], paywall_consent:True, ...} # 3. Nominar los brokers de ese medio. nombres = [gvl["vendors"].get(str(v), {}).get("name", f"(vendor {v})") for v in scan["vendor_ids"]] ``` Orquestador completo sobre un censo de dominios: `projects/databrokers/scanner/scan_all.py` (itera → `extract_cmp_tcf` → persiste → cruza con la GVL → Excel). ## Prerrequisitos - Un Chrome/Chromium con remote debugging (CDP) en el puerto usado. Lánzalo aislado del navegador diario (no 9222) con su propio `user_data_dir`. **Perfil limpio**: una vez aceptado el banner, la cookie de consent persiste en el perfil y los re-escaneos ya no muestran banner. - `ask_llm` (grupo `claude-direct`) requiere el token OAuth de Claude Max en `~/.claude/.credentials.json`. ## Fronteras (lo que el grupo NO cubre) - No extrae la lista de vendors de CMP cuyo `getTCData` no rellena `vendor.consents`/`legitimateInterests` por la vía estándar, ni de banners alojados en iframe (Sourcepoint): el clic desde el documento principal no alcanza el iframe. - No interpreta el `tcString` (qué propósitos consintió el usuario en concreto); solo el universo de vendors declarado. Para decodificar el TCString haría falta una pieza aparte. - No es un bloqueador ni un gestor de consentimiento propio: solo observa y mide.