# Monitorización de usuarios reales

> Activa la medición de las Core Web Vitals sin tocar código, elige el muestreo, excluye rutas, permítela en tu CSP y lee el informe.

La monitorización de usuarios reales (RUM) mide las [Core Web Vitals](https://developers.openwaf.dev/es/analytics/core-web-vitals/) en los navegadores de tus visitantes reales. No cambias nada en tu sitio: el borde añade un script pequeño a tus páginas HTML y el navegador envía los datos a tu propio dominio. El RUM viene **desactivado por defecto** y se puede ajustar por zona y por nombre.

## Cómo funciona

1. El borde añade `<script defer src="/__waf/rum.js?v=…">` antes del `</head>` de las páginas HTML. El script ocupa unos 5 KB comprimido y lo sirve el propio borde.
2. El navegador mide LCP, INP, CLS, FCP y TTFB mientras la página está abierta.
3. Cuando la página se oculta (se cambia de pestaña, se cierra o se navega a otra), envía una baliza a `/__waf/rum` en tu dominio. Los envíos posteriores de la misma vista solo llevan lo que cambió, normalmente INP y CLS.
4. El borde valida la baliza, añade el tipo de dispositivo y el país, descarta la dirección IP y el User-Agent, y la reenvía. Los datos aparecen en el informe alrededor de un minuto después.


El script solo se añade a las respuestas `200` a peticiones `GET` con un `Content-Type` HTML, fuera de las rutas excluidas, nunca a las páginas que genera el borde (retos, páginas de bloqueo, puerta de acceso) y según el muestreo. Se añade al servir la página, así que también llega a las páginas servidas desde la [caché del borde](https://developers.openwaf.dev/es/cache/), y las copias en caché nunca lo contienen. Las páginas comprimidas se descomprimen, se inyectan y se vuelven a comprimir.

## Actívalo

**Panel**

Ve a **Analítica › Rendimiento real**, elige el **Muestreo** y pulsa **Activar**. Después, en los **Ajustes** de la página puedes cambiar el muestreo y las **Rutas excluidas**, o **Desactivar** la medición.

**CLI**

```sh
openwaf-cloud ctl zones set example.com rum.enabled=true rum.sample_rate=0.25 rum.exclude_paths=/wp-admin/,/wp-login.php --reason "medir web vitals"
```

`rum.sample_rate` se lee como número y `rum.exclude_paths` como lista separada por comas (`rum.exclude_paths=` la deja vacía).

**API**

```sh
curl -s -X PATCH https://dash.openwaf.dev/v1/orgs/$ORG/zones/$ZONE/edge \
  -H "Authorization: Bearer $OPENWAF_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Change-Reason: medir web vitals" \
  -d '{"rum": {"enabled": true, "sample_rate": 0.25, "exclude_paths": ["/wp-admin/"]}}'
```

**MCP**

`update_settings` con `{"zone": "example.com", "settings": {"rum": {"enabled": true}}, "reason": "medir web vitals"}`, primero con `confirm=false` y después con `confirm=true` y `expected_version`.


Como todo ajuste del borde, cada cambio crea una versión de la zona, queda en la auditoría y se puede revertir.

## Ajustes

| Clave | Valores | Por defecto |
|---|---|---|
| `rum.enabled` | `true`, `false` | `false` |
| `rum.sample_rate` | Mayor que `0` y como mucho `1`: la parte de las vistas de página que reciben el script (`0.25` = una de cada cuatro). | `1` |
| `rum.exclude_paths` | Prefijos de ruta que nunca reciben el script. | `[]` |

Los valores se validan aunque el RUM esté desactivado: un `sample_rate` de `0` o mayor que `1`, una ruta relativa o un campo desconocido se rechazan con un `422`.

### Rutas excluidas

Hasta 50 prefijos. Cada uno empieza por `/`, tiene como mucho 256 bytes, no lleva `?` ni `#` y no se repite; se recortan los espacios y se descartan las líneas vacías. Excluye las páginas que no quieras medir, por ejemplo `/admin` o `/checkout`.

### Por nombre

Cada campo fijado para un nombre sustituye al de la zona para ese nombre:

```sh
openwaf-cloud ctl zones set example.com --host shop.example.com rum.sample_rate=1 --reason "medir toda la tienda"
openwaf-cloud ctl zones set example.com --host admin.example.com rum.enabled=false --reason "sin RUM en el admin"
openwaf-cloud ctl zones set example.com --host admin.example.com --unset rum --reason "hereda de la zona"
```

En la API: `{"hosts": {"admin.example.com": {"rum": {"enabled": false}}}}`; `{"rum": null}` dentro del nombre vuelve a heredar la zona.

## Content-Security-Policy

Si tu origen envía una `Content-Security-Policy`, debe permitir que el script se cargue y envíe datos a tu propio origen:

- permite `'self'` en `script-src` y `connect-src`, **o bien**
- envía un `nonce` en `script-src`: el borde lo reutiliza para su script.

Si la política bloquearía el script, el borde no lo inyecta y el informe avisa de cuántas vistas de página no se midieron por culpa de la CSP.

## Lee el informe

**Panel**

**Analítica › Rendimiento real** sigue la organización de los datos de campo de PageSpeed Insights:

- pestañas de dispositivo **Móvil** (por defecto), **Escritorio**, **Tableta** (solo si hay visitas) y **Todos**;
- **Esta página** o **Todo el sitio**;
- la **Evaluación de las Métricas web principales** y un recuadro por métrica con su p75 y el porcentaje de vistas buenas, mejorables y malas (**Ampliar vista** añade umbrales, tendencia y tamaño de la muestra);
- **Diagnostica problemas de rendimiento**: desglose del LCP, elemento LCP, interacciones y scripts detrás del INP, saltos de diseño y desgloses por página, país, nodo del borde, conexión y en el tiempo.

Los filtros (periodo de 24 h, 7 o 30 días; país; nodo del borde; página) viven en la dirección, así que puedes compartir una vista.

**CLI**

```sh
openwaf-cloud ctl rum report example.com                                  # últimos 7 días
openwaf-cloud ctl rum report example.com --since 24h --device mobile --country ES
openwaf-cloud ctl rum report example.com --since 30d --by country --json
```

Opciones: `--since`/`--until` (una duración como `24h` o `7d`, o RFC 3339), `--host`, `--path`, `--country`, `--node`, `--device`, `--connection`, `--nav-type` y `--by path|country|node|device|connection`. Imprime el p75 de cada métrica con su valoración, el reparto, la comparación con el periodo anterior, el desglose del LCP, el desglose elegido y los peores elementos; `--json` imprime la respuesta de la API.

**API**

```sh
curl -s "https://dash.openwaf.dev/v1/orgs/$ORG/zones/$ZONE/rum/report?since=2026-10-20T00:00:00Z&device=mobile" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```

Todas las rutas y parámetros están en la [referencia de la API de RUM](https://developers.openwaf.dev/es/analytics/rum-api/).

**MCP**

`rum_report` es de solo lectura. Pregunta, por ejemplo, «¿Cómo va el LCP en móvil en España esta semana?»; el asistente llama a:

```json
{"zone": "example.com", "period": "7d", "device": "mobile", "country": "ES"}
```

`period` es `24h`, `7d` (por defecto) o `30d`; los filtros `device`, `country`, `node`, `path`, `host`, `connection`, `nav_type` y `by` funcionan como en la API.


## Relacionado

- [Privacidad del RUM](https://developers.openwaf.dev/es/analytics/rum-privacy/)
- [Solución de problemas](https://developers.openwaf.dev/es/analytics/troubleshooting/#no-rum-data)
