# Instalar FlowConsent en React

Instalar FlowConsent en React (Vite, Create React App, React Router): pegar el fragmento de código al inicio del <head> de index.html y activar el modo SPA.

> Canonical: https://www.flowconsent.com/es/doc/install-react
> Last updated: 2026-10-01
En una aplicación React, el fragmento de código de FlowConsent se pega al principio del `<head>` del archivo HTML de la aplicación: `index.html` en la raíz del proyecto con Vite, `public/index.html` con Create React App, o el componente `Layout` de `app/root.tsx` con React Router en modo framework. Bastan dos pasos, y el segundo es obligatorio: activar el **modo SPA**, porque una aplicación React navega sin recargar la página. La trampa principal es cargar el script desde un componente React o un `useEffect`: llega demasiado tarde.

## Antes de empezar

- Una cuenta en [app.flowconsent.com](https://app.flowconsent.com) (plan Free gratuito, sin tarjeta de crédito, hasta 25 000 sesiones al mes).
- Un banner creado y desplegado. En el plan Free, el despliegue se hace con la propia cuenta de Cloudflare ([guía de Cloudflare](/es/doc/cloudflare-deployment)); en Pro y Enterprise, con un clic.
- ¿Se trata de Next.js? En ese caso, conviene seguir la [guía de Next.js y SPA con React](/es/doc/nextjs-integration).

## Paso 1: pegar el fragmento de código en el HTML de la aplicación

Copiar el fragmento de código desde **Builder → Despliegue → Integración**, pestaña **HTML / No-code**. Después, abrir el archivo HTML que actúa como punto de entrada:

- **Vite**: `index.html`, en la raíz del proyecto (no en `public/`). Vite lo trata como el punto de entrada de la aplicación.
- **Create React App**: `public/index.html`. Create React App está obsoleto para proyectos nuevos desde febrero de 2025, pero las aplicaciones existentes funcionan igual.

El fragmento de código va **justo después de la apertura de `<head>`**, antes de cualquier otro script:

```html title="index.html (Vite) o public/index.html (Create React App)"
<!doctype html>
<html lang="es">
  <head>
    <script>
    // FlowConsent Loader - COLOCAR ANTES de cualquier otro script en el <head>
    window.dataLayer=window.dataLayer||[];
    function gtag(){dataLayer.push(arguments);}
    gtag('consent','default',{
      'ad_storage':'denied',
      'analytics_storage':'denied',
      'ad_user_data':'denied',
      'ad_personalization':'denied',
      'wait_for_update':500
    });
    gtag('set','url_passthrough',true);
    gtag('set','ads_data_redaction',true);
    </script>
    <!-- FlowConsent CMP -->
    <script src="https://SU-CODIGO-LICENCIA.consent.flowconsent.com/cookie-manager.js?code=SU_CODIGO_LICENCIA"></script>

    <meta charset="UTF-8" />
    <title>Mi aplicación</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>
```

No hay que añadir `type="module"` a las dos etiquetas de FlowConsent: un script de módulo se ejecuta de forma diferida, y estos scripts deben ejecutarse de inmediato. Después, reconstruir y volver a desplegar la aplicación.

### React Router en modo framework

En modo framework (React Router v7), el documento HTML lo genera el componente `Layout` de `app/root.tsx`. El fragmento de código va en primer lugar dentro de su `<head>`, con el stub a través de `dangerouslySetInnerHTML`:

```tsx title="app/root.tsx"
export function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="es">
      <head>
        <script
          dangerouslySetInnerHTML={{
            __html: `window.dataLayer=window.dataLayer||[];
function gtag(){dataLayer.push(arguments);}
gtag('consent','default',{'ad_storage':'denied','analytics_storage':'denied','ad_user_data':'denied','ad_personalization':'denied','wait_for_update':500});
gtag('set','url_passthrough',true);
gtag('set','ads_data_redaction',true);`,
          }}
        />
        {/* FlowConsent CMP */}
        <script src="https://SU-CODIGO-LICENCIA.consent.flowconsent.com/cookie-manager.js?code=SU_CODIGO_LICENCIA" />
        <meta charSet="utf-8" />
        <Meta />
        <Links />
      </head>
      <body>
        {children}
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  )
}
```

En modo declarativo o data (con Vite), React Router no tiene `root.tsx`: se usa `index.html` como arriba.

## Paso 2: activar el modo SPA (obligatorio)

Una aplicación React cambia de página con `history.pushState`, sin recarga. Sin el modo SPA, el banner no vuelve a comprobar el consentimiento en las navegaciones siguientes. En el Builder, abrir la pestaña **Ajustes**, activar el **modo SPA** y volver a desplegar el banner. FlowConsent intercepta entonces `pushState`, `replaceState` y `popstate` en cada navegación del lado del cliente.

## La trampa: cargar FlowConsent desde un componente

> [!WARNING]
> No conviene inyectar el script de FlowConsent desde un componente React, un `useEffect` o una librería de gestión del `<head>`. Ese código solo se ejecuta después de descargar el bundle y montar la aplicación: para entonces, los scripts presentes en `index.html` ya se habrán disparado y el bloqueo previo deja de funcionar. El fragmento de código debe estar escrito directamente en el HTML, al principio del `<head>`.

Del mismo modo, Google Analytics o Meta Pixel no deben cargarse desde los componentes: se declaran en **Builder → Servicios** para que el banner los inyecte solo tras el consentimiento. Para reaccionar a la elección del visitante en el código, basta con escuchar el evento `flowconsent:consent` (ejemplo en la [guía de Next.js y SPA con React](/es/doc/nextjs-integration)). Con Google Tag Manager, el fragmento de código va **por encima** del contenedor de GTM, nunca dentro ([guía de Google Consent Mode](/es/doc/google-consent-mode)).

## Verificar la instalación

1. Abrir la aplicación publicada en una ventana privada: el banner aparece.
2. En la pestaña **Red**, ninguna petición de terceros sale antes de **Aceptar**, ni siquiera tras varios cambios de ruta.
3. Lanzar el [asistente de instalación](/es/doc/setup-wizard) (Builder → Integración): comprueba que el cargador está presente con el código de licencia correcto y que el stub de Consent Mode precede a cada etiqueta de Google.
4. Terminar con un escaneo de rechazo desde la pestaña **Conformidad** ([verificación de conformidad](/es/doc/compliance-verification)).

## Hacerlo desde un agente de IA (MCP)

FlowConsent dispone de un servidor MCP oficial, `https://mcp.flowconsent.com`, utilizable desde Claude, ChatGPT o cualquier cliente MCP, con conexión OAuth 2.0 a la cuenta de FlowConsent (sin clave de API). El agente obtiene el fragmento de código y las instrucciones de colocación (`get_banner_snippet`, `get_setup_instructions`), verifica la instalación con un escaneo real (`verify_consent_compliance`) y puede programar una vigilancia periódica (`monitor_compliance`). La modificación de `index.html` sigue en manos del equipo o de su agente de código.

> Necesito el fragmento de código de mi banner para mi aplicación React (Vite), dónde colocarlo y, después, comprobar que está bien instalado en https://misitio.es

Más información: [servidor MCP](/es/doc/mcp-server) y [FlowConsent para agentes de IA](/es/mcp).

## Preguntas frecuentes

### ¿Hace falta instalar un paquete npm para React?

No: el banner es un script autónomo que va en el HTML. Un paquete importado en el bundle se ejecutaría demasiado tarde para el bloqueo previo.

### ¿El modo SPA es realmente obligatorio?

Sí, en cuanto la aplicación usa un enrutador del lado del cliente (React Router, TanStack Router…). Sin él, los scripts inyectados después de la primera página no se vuelven a bloquear en las navegaciones siguientes.

### La aplicación está alojada en Vercel o Netlify. ¿Dónde va el fragmento?

Igualmente en `index.html` (o `app/root.tsx`). El alojamiento no cambia nada. Ver [Vercel](/es/doc/install-vercel) y [Netlify](/es/doc/install-netlify).

### El banner aparece, pero Google Analytics se dispara antes de la elección. ¿Por qué?

Probablemente se carga un script de GA por encima del fragmento de código o desde un componente. Hay que retirarlo y declarar Google Analytics en **Builder → Servicios**.
