Hace un tiempo, para cumplir con el RGPD y la ePrivacy, desarrollamos internamente un CMP (herramienta de gestión del consentimiento) ligero para uso propio. Normalmente se recurre a un SaaS, pero queremos explicar por qué lo creamos y cómo lo hicimos.
En primer lugar, el consentimiento de cookies se ha vuelto inevitable para los sitios que prestan servicios a nivel internacional. El RGPD de la UE es el ejemplo más destacado, pero en Estados Unidos también aumentan año tras año las leyes de privacidad estatales, de modo que activar etiquetas de medición o publicidad sin obtener consentimiento ya no es una práctica aceptable.
En la UE, el RGPD y la Directiva ePrivacy establecen que no se pueden colocar cookies no esenciales, como las de GA4 o Google Ads, ni enviar datos de navegación a terceros antes de obtener el consentimiento. Tampoco es válido tratar el cierre del aviso como consentimiento, ni hacer que retirar el consentimiento sea más complicado que otorgarlo.
Esta normativa también se aplica a empresas fuera de la UE si ofrecen servicios a personas que se encuentran en la UE o si monitorizan su comportamiento. Sitios japoneses que publican una versión en inglés y prestan servicios internacionales, o que ejecutan campañas de remarketing, pueden estar sujetos a ella aunque no tengan presencia en la UE.
A esto se suman los requisitos de Google. Para usar las funciones de Google Ads con visitantes de la UE es obligatorio implementar Consent Mode v2, y si no se transmite correctamente el estado del consentimiento a Google, la medición y el remarketing dejan de funcionar. En Japón, la reforma de 2023 de la Ley de Telecomunicaciones introdujo las "normas de transmisión externa", que exigen publicar qué información se envía a qué servicios.
En resumen, se necesita un sistema que cumpla simultáneamente con las siguientes tres condiciones.
- Determinar la región del visitante y no activar ninguna etiqueta en la UE y otras regiones similares hasta que se otorgue el consentimiento
- Transmitir correctamente el estado del consentimiento a Google Consent Mode y ofrecer una vía para retirarlo en cualquier momento
- Publicar una lista de destinatarios externos y cookies (política) y mantenerla siempre alineada con las transmisiones reales

Por qué no adoptamos una herramienta de gestión del consentimiento ya hecha
Hay tres razones.
- Conflictos de etiquetas.
Queríamos evitar que un script externo de gestión del consentimiento entrara en conflicto con GTM, las etiquetas publicitarias y las transiciones de SPA, provocando la pérdida de conversiones incluso de usuarios que ya habían dado su consentimiento - Los objetivos de control son fijos.
Nuestras mediciones y publicidad son casi todas de Google (GTM / GA4 / Google Ads). Sabemos exactamente qué etiquetas controlar, así que no necesitamos la complejidad de una herramienta genérica - Encaja con nuestras fortalezas.
La implementación de frontend y la accesibilidad son nuestra especialidad. Crear nosotros mismos un mecanismo ligero y auditable nos permite tener solo las funciones necesarias
Política básica: en Japón, notificación; en el extranjero, rechazo inicial
Así definimos el comportamiento por región.
Visitante | Estado inicial | Pantalla | Etiqueta de Google |
|---|---|---|---|
Desde Japón | Permitir | Sin banner | Se inicia como de costumbre |
Desde fuera de Japón | Rechazar | Banner en la parte inferior de la pantalla (Aceptar todo / Rechazar todo / Configuración detallada). Tras la selección, aparece un botón flotante de configuración | Solo se inicia después del consentimiento |
Indeterminable | Rechazar | Igual que en el extranjero | Solo se inicia después del consentimiento |
Señal GPC detectada | Rechazar solo publicidad | Mostrar el motivo por el que se rechaza la publicidad | Suspender el uso publicitario |
En Japón, de acuerdo con la normativa sobre «transmisión externa de información», la práctica básica es notificar y publicar la información, sin mostrar banners. En el extranjero, tanto la UE como EE. UU. se configuran en conjunto con el rechazo como estado inicial. Muchas leyes estatales de EE. UU. se basan en el modelo de exclusión voluntaria (opt-out), por lo que este enfoque puede resultar algo estricto, pero he unificado la configuración por el lado seguro para simplificar la operación.
Tratar como rechazo los casos en los que no es posible determinar el estado sigue la misma lógica. En caso de duda, la decisión es no activar las etiquetas. Este es el principio de diseño que atraviesa todo el sistema, y el comportamiento ante fallos de carga que aparece más adelante también responde a esta misma orientación.
Retirar el consentimiento debe ser tan sencillo como darlo
El RGPD exige que retirar el consentimiento sea tan fácil como otorgarlo. Si el usuario puede aceptar con dos clics en el banner, pero solo puede retirarlo desde el fondo de la página de política, el equilibrio no se mantiene.
El botón «Configuración de cookies», que abre el cuadro de configuración, se ubica en la sección «Cómo cambiar o retirar el consentimiento» de la página de política, sin importar la región. En el modo extranjero, además, tras elegir una opción en el banner, se muestra de forma permanente un botón flotante de configuración en la parte inferior izquierda de la pantalla, para poder modificar o retirar el consentimiento desde cualquier página. En el modo para Japón, como no se muestra banner, tampoco aparece el botón flotante y solo está disponible el botón de la página de política. Según el proyecto, es posible cambiar entre mostrarlo o no en Japón.
Si retira el consentimiento, se eliminarán las cookies de Google incluidas en el registro y se dejarán de enviar nuevos datos.
Estructura: 3 componentes
[Edge] Cloudflare Worker が request.cf.country を見て
<html data-lcmp-region="jp|overseas"> を HTML に注入
[HTML] <head> 先頭の同期スクリプト(loader.js)が
地域・保存済みの選択・GPC から gtag('consent','default') を確定
→ 日本 or 有効な同意あり → GTM を読む
→ それ以外 → GTM を読まず、バナー UI を遅延読み込み
[UI] 選択 → 検証・保存 → gtag('consent','update') → GTM を読み込む(何度呼ばれても挿入は1回だけ)
[GTM] 各タグ側の「追加の同意チェック」で最終ガード
- Detección de región ― Determina el país en Edge y añade una marca al HTML
- Script de consentimiento ― A partir de la marca y la selección guardada, decide si se muestra el banner y si se activa GTM
- Registro ― Lista de los servicios externos y cookies utilizados. Es la tabla de la política y los datos de origen de lo que se elimina al retirar el consentimiento
① La detección de región marca el HTML en Edge
La detección del país se puede resolver con request.cf.country de Cloudflare, pero dónde usarlo fue el punto clave del diseño.
Si se llama a una API de detección desde el navegador (un enfoque habitual en las grandes herramientas extranjeras), el región no se conoce hasta recibir la respuesta, y los visitantes de Japón también aparecen brevemente en estado de "rechazo". Por eso optamos por reescribir el HTML en Edge e insertar el atributo de región en <html>. Como HTMLRewriter solo añade data-lcmp-region="jp", el script puede leer la región de forma síncrona.
// dist/_worker.js/index.js(サイト側の post-build で生成)
import inner from './astro-entry.js';
import { wrapWorker } from './lg-region-wrap.js';
export default wrapWorker(inner);
Nuestro sitio usa Astro + @astrojs/cloudflare, y tuvimos algunos obstáculos. Con la configuración en la que el adaptador genera _worker.js, el directorio functions/ se ignora, y además las páginas prerenderizadas no pasan por el middleware de Astro. Al final, inyectamos el código envolviendo el punto de entrada del Worker generado tras la compilación.
No se determina por el idioma
También consideramos determinarlo mediante <html lang>Accept-Language o navigator.language, pero si una persona residente en la UE abre una página en japonés y se detecta erróneamente como jp, la etiqueta se activaría sin consentimiento, lo que supone un error en el lado de mayor riesgo.
Para proyectos en los que no es posible intercalar una verificación en el lado del servidor (por ejemplo, en AWS o en servidores de alquiler, cuando el DNS no puede apuntar a Cloudflare), hemos preparado un método que consulta nuestro endpoint de verificación mediante la dirección IP. Es el mismo enfoque de «API de verificación del proveedor» que usan las herramientas habituales de gestión del consentimiento. Solo se usa para la verificación: no se almacenan la IP ni el código de país, y la respuesta es únicamente uno de dos valores: jp o overseas. Como último recurso, si tampoco es posible usar esto, existe un modo que estima el país a partir de la zona horaria del dispositivo (si es Asia/Tokyo, se considera Japón).
El método de verificación se elige según la configuración de cada sitio. Sin embargo, el script siempre consulta primero la información que puede obtenerse de forma síncrona, independientemente de esa configuración.
- Atributo de región incrustado en el HTML (si hay detección en el Edge, siempre se usa este)
- Región indicada en la cookie (en configuraciones donde no se puede reescribir el HTML y el servidor pasa el resultado de la verificación mediante una cookie)
- Solo cuando no existen ni el 1 ni el 2, se verifica con el método elegido en la configuración (API de verificación por IP o zona horaria)
- Si aun así no se obtiene el dato, se trata como **extranjero** (**lado seguro**).
Si damos siempre prioridad al atributo y a la cookie es para que, al migrar más adelante a la detección en el Edge, baste con cambiar la configuración. Si la API de verificación por IP agota el tiempo de espera, el usuario simplemente se trata como extranjero, y las etiquetas nunca se activan sin consentimiento.
② Antes del consentimiento, no «bloquear», sino «no cargar»
Consent Mode de Google ofrece dos variantes: Advanced, que carga GTM primero y envía solo la señal de «denegado», y Basic, que no carga el propio GTM hasta que hay consentimiento. En este caso usamos Basic. Si antes del consentimiento solo se carga el script de consentimiento y nada más, la estructura se simplifica en muchos aspectos.
- Si la carga del script falla, las etiquetas no esenciales no se activan, ya que no hay nadie que lea GTM.
- No escribimos el fragmento de GTM directamente en el HTML. Tampoco lo distribuimos como etiqueta HTML personalizada de GTM, ya que eso implicaría leer GTM antes del consentimiento.
- En GTM, cada etiqueta también tiene configurada la opción "no se activa sin consentimiento de análisis/publicidad", para protegerlo por partida doble.
Verificamos mediante pruebas E2E a nivel de red que "antes del consentimiento, 0 solicitudes y 0 cookies".
const FORBIDDEN_BEFORE_CONSENT = [
'**googletagmanager.com/**', '**google-analytics.com/**',
'**googleadservices.com/**', '**doubleclick.net/**', // …
];
test('T02: overseas first visit sends nothing', async ({ page }) => {
const hits: string[] = [];
await page.route('**/*', route => {
if (FORBIDDEN_BEFORE_CONSENT.some(p => matchGlob(p, route.request().url()))) hits.push(route.request().url());
return route.continue();
});
await page.goto('/');
await expect(page.getByRole('region', { name: /cookie/i })).toBeVisible();
expect(hits).toEqual([]); // 通信 0 件
expect(await page.context().cookies()).toEqual([]); // Cookie 0 件
});
Al retirar el consentimiento, solo eliminamos las cookies conocidas que figuran en el registro. No utilizamos comodines para borrarlas. Como se trata de "eliminar lo que sabemos que existe", si el Domain o el Path del registro no coinciden con la realidad, la eliminación fallará. Hacer que las pruebas fallen cuando el registro es incorrecto es lo que nos permite mantener la coherencia entre la tabla de políticas y las comunicaciones reales.
③ Incrustaciones fuera de GTM (YouTube, mapas y fuentes web)
Detener GTM no era suficiente. Los iframes de YouTube y Google Maps, así como las fuentes web que no pueden alojarse en nuestro propio servidor, se cargan directamente desde la página sin pasar por GTM, y colocan cookies antes del consentimiento.
Para solucionarlo, optamos por modificar un atributo en un único punto del HTML.
<iframe data-lcmp-src="<https://www.youtube-nocookie.com/embed/ID>" data-lcmp-service="youtube" width="560" height="315"></iframe>
Antes del consentimiento, mostramos un marcador de posición generado a partir de los valores del registro ("Este contenido se carga desde YouTube y su dirección IP y datos de navegación se envían al proveedor" + botones "Mostrar solo esta vez / Mostrar siempre"), y el contenido real se carga tras la autorización.
No adoptamos el "bloqueo automático", que supervisa el DOM y reescribe las cargas antes de que ocurran. Esto provoca cargas omitidas y problemas de visualización inevitables, y además es una función de la que los productos extranjeros no garantizan su funcionamiento. Aunque requiere modificar un atributo del iframe en un único punto, funciona de forma fiable.
También puede bloquear las fuentes web con el mismo mecanismo. Basta con cambiar el <link rel="stylesheet">href de por data-lcmp-href: antes del consentimiento no se lee el CSS de las fuentes y se carga tras la autorización. El cargador se ejecuta de forma <head>síncrona y procesa de inmediato los elementos añadidos, así que, si el consentimiento ya se otorgó, el <link>href se restaura justo después de que el parser inserte , y el momento de carga de las fuentes es prácticamente el mismo que antes.
<link rel="stylesheet" data-lcmp-href="<https://fonts.googleapis.com/css2?family=…>" data-lcmp-service="google-fonts">
Sin embargo, con un sistema basado en consentimiento, en las primeras visitas desde el extranjero las fuentes no se cargan y se muestran las fuentes del sistema. Si eso no es aceptable, la opción correcta es alojar los archivos de fuentes en su propio servidor (autoalojamiento): así se elimina el envío a terceros y el problema desaparece.
Basta con pegar 1 línea, 8 KB
Como requisito previo, las mediciones y las etiquetas de publicidad deben funcionar a través de GTM. Los sitios que no usan GTM no pueden implementarse tal cual (primero hay que migrar las etiquetas a GTM).
Del lado de la implementación, solo hay que colocar un script de sincronización al <head>inicio.
<script src="<https://cdn.liberogic.jp/lcmp/><siteId>/loader.js"></script>
El tamaño de loader.js es de unos 8 KB comprimido con gzip. La interfaz de los banners y diálogos está en un fragmento aparte que solo se carga de forma diferida cuando se necesita.
Además, la inserción de gtm.js de GTM incluye la opción «después de LCP + unos segundos». Con ella, los visitantes que abandonen antes de la inserción no serán medidos, como compensación, pero el impacto en la puntuación de Lighthouse se reduce.
Publicación por sitio y panel de administración
La configuración (registro, ID de GTM, textos y tema) se incorpora en el paquete en el momento de la publicación y se distribuye desde el CDN. No se obtiene el JSON de configuración en tiempo de ejecución. Esto permite cumplir a la vez «la inicialización es síncrona y sin comunicación de red» y «se prohíbe inyectar configuración arbitraria desde el exterior»; por tanto, cambiar la configuración = volver a publicar y redistribuir. Cada publicación conserva su versión, así que si surge un problema se puede volver a la versión anterior.
El resultado incluye loader.js y ui.js, además de un fragmento listo para pegar, la guía de implementación y una plantilla de contenedor de GTM con la verificación de consentimiento ya configurada (JSON para importar). Así se reduce el riesgo de que queden en GTM etiquetas «sin comprobación de consentimiento».
Hicimos que este proceso de publicación esté al alcance de quienes no son desarrolladores: eso es el panel de administración. Estas son sus principales funciones.
- Borradores y publicación, separados.
El registro es una declaración legal sobre el envío de datos a terceros desde cada sitio, así que no se aplica de inmediato al editarlo. Antes de publicar, se muestra una lista de cambios en japonés con las diferencias respecto a la configuración publicada, y si el registro cambió pero la fecha de revisión de la política no, se muestra una advertencia. Desde el historial de publicaciones se puede volver a la versión anterior con una sola acción. - Catálogo de servicios habituales.
Puede añadir al registro servicios frecuentes en sitios de Japón, como GA4, Google Ads, Clarity, YouTube y reCAPTCHA, con su nombre, proveedor, finalidad e información estándar de cookies. Las categorías son valores sugeridos; la decisión final la toma una persona. - Escaneo automático de cookies.
Las páginas objetivo se abren en un navegador real en dos estados, "antes del consentimiento" y "aceptar todo", y las cookies y destinos de comunicación encontrados se contrastan con el registro. Lo que se activa antes del consentimiento se marca como "crítico", y lo que no aparece en el registro como "precaución". Los hallazgos pueden añadirse al registro con un solo botón. - Renderizado automático de la tabla de políticas.
Basta con colocar en la página de políticas. La tabla se genera a partir del registro integrado por loader.js, por lo que la tabla de políticas y los controles reales nunca se desincronizan. - Edición de temas.
Puede cambiar los colores de banners, diálogos y botones flotantes mientras ve una vista previa real. El sistema calcula en el momento la relación de contraste: 4.5:1 para el texto y 3:1 para elementos no textuales como los bordes de botones, y muestra una advertencia si no se cumple.
Conclusión
La gestión del consentimiento no se resuelve con "mostrar un banner y listo". Solo funciona cuando cuatro elementos encajan entre sí: detección de región, control de etiquetas, publicación de la política y vías para retirar el consentimiento. En esta versión, todo se concentra en un script externo y un único registro. Al modificar el registro, cambian a la vez la descripción del banner, la tabla de políticas y los elementos que se eliminan al retirar el consentimiento, así que no hay lugares donde puedan producirse desajustes.
Los sitios que obtienen ingresos mostrando anuncios (como con AdSense) no están dentro de este alcance, ya que si se publican anuncios para la UE es obligatorio un CMP certificado por Google. Aun así, para un sitio general es una solución suficiente. Para sitios que tienen definidas las etiquetas que usan y quieren poder auditar por sí mismos la gestión del consentimiento, creo que es una opción más transparente que instalar una herramienta prefabricada.
Pasó del DTP al mundo web y, sin darse cuenta, domina el maquetado, el frontend, la dirección de proyectos y la accesibilidad: un auténtico "maestro de todas las técnicas". Desde los inicios de Liberogic ha desempeñado múltiples funciones y hoy es una auténtica enciclopedia viviente dentro de la empresa. Últimamente se ha obsesionado con la optimización mediante prompts, preguntándose: «¿No podríamos apoyarnos más en la IA para la accesibilidad?». Su tecnología y su forma de pensar siguen evolucionando.
Ayumu Futamata
Especialista en Accesibilidad Web certificado por IAAP (WAS) / Ingeniero de marcado / Ingeniero frontend / Director web