Estábamos revisando el informe de un rastreo de 20.000 URLs de un medio de comunicación y algo no
cuadraba. ASSET-IMG-HEAVY, la regla que avisa de imágenes por encima de 200 KB, daba cero
hallazgos.
Un periódico digital. Quince años publicando artículos con foto. Cero imágenes pesadas.
Miramos la base de datos directamente:
SELECT COUNT(*) FROM images;
-- 0
Ni una fila. En el mismo rastreo, 20.000 URLs y 18.000 páginas HTML, y la tabla de imágenes vacía.
Qué estaba pasando
El sitio usa LiteSpeed Cache, uno de los plugins de optimización más extendidos de WordPress. Entre otras cosas, hace carga diferida de imágenes, y para eso reescribe el HTML así:
<img data-lazyloaded="1"
src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDgwMCI+PC9zdmc+"
data-src="https://ejemplo.com/wp-content/uploads/2026/07/foto.jpg"
alt="Pie de foto del artículo">
El atributo src, que es donde todo el mundo mira, contiene un SVG transparente codificado en
base64. La URL de verdad está en data-src, y el navegador la mueve al src cuando la imagen se
acerca al viewport.
Nuestro parser leía el src, encontraba una URI data:, la descartaba por no ser una URL
rastreable, y seguía adelante. Correctamente, además: una URI data: no es una imagen que se pueda
pedir al servidor. El problema es que tampoco miraba si había una URL real al lado.
Lo que se pierde
Todo lo que dependa de conocer la imagen:
- Peso. No sabes que estás sirviendo un JPEG de 1,9 MB en la portada.
- Estado. Una imagen que devuelve 404 no aparece por ningún lado.
- Formato. No puedes decir cuántas siguen en JPEG pudiendo estar en WebP.
- Recuento. El informe dice que el sitio tiene cero imágenes.
Y lo que más nos molestó: el alt sí lo leíamos, porque ese atributo el plugin lo deja donde
estaba. Así que reportábamos correctamente imágenes sin texto alternativo, en un sitio del que
creíamos que no tenía imágenes. El informe se contradecía a sí mismo y nadie lo había notado.
El arreglo
Cuando el src es una URI data:, buscar la URL real en los atributos que usan los plugins de
carga diferida. Por orden de uso:
data-src— LiteSpeed Cache, lazysizes, a3 Lazy Load, Smush, EWWWdata-lazy-src— WP Rocket, Jetpack Lazy Imagesdata-original— el jQuery lazyload clásico, todavía vivo en sitios antiguos- El primer candidato de
data-srcset
No nos fiamos de la lista y fuimos a comprobarlo: descargamos la portada y un artículo del sitio
real. LiteSpeed emitía data-lazyloaded="1" con data-src y data-srcset en 45 de las 51
imágenes de la portada.
También decidimos no leer el <noscript>. Muchos plugins dejan ahí una copia del <img>
original como alternativa para navegadores sin JavaScript, y parecía la fuente más fiable. Dos
razones para descartarlo: en las páginas que medimos no había ninguno, y en los sitios que sí lo
emiten leerlo duplicaría cada imagen, obligando a deduplicar después.
El resultado
El mismo sitio, un rastreo de 300 URLs con el arreglo puesto:
SELECT COUNT(*) FROM images;
-- 5945
Y en un rastreo completo, las reglas que llevaban meses calladas:
high ASSET-IMG-BROKEN 2,193
medium ASSET-IMG-HEAVY 43,980
Cuarenta y tres mil imágenes por encima del umbral, y dos mil que devuelven error. En un medio de comunicación eso es probablemente el hallazgo con más impacto de toda la auditoría, y llevaba desde el principio siendo invisible.
Un ejemplo de las que aparecieron:
https://ejemplo.com/wp-content/uploads/2026/07/segunda-rfef-grupo-v.png
1.927.124 bytes · límite 204.800 · usada en 1 página
Casi dos megas en un PNG que podría ser un WebP de 150 KB.
Qué hacer si tus imágenes pesan
Encontrarlas es la mitad. La otra mitad es que el informe te diga por dónde empezar, y ahí el recuento de páginas que usan cada imagen importa más que el peso:
crawlforge report crawl.sqlite --rule ASSET-IMG-HEAVY
Una imagen de 1,9 MB usada en una sola entrada de hace tres años no es urgente. La misma imagen en
la cabecera de la plantilla, servida en cada página, es lo primero que hay que tocar. Nuestro
detalle incluye used_by_pages justo por eso.
El orden que seguimos nosotros: primero las de plantilla, después las de portada y categorías, y por último el archivo, que casi nunca compensa salvo que tengas un proceso automático.
Cómo saber si te está pasando
Da igual la herramienta que uses. Rastrea un sitio tuyo con carga diferida y mira el recuento de imágenes. Si sale sospechosamente bajo, o cero, tienes el mismo problema.
La comprobación rápida en tu propio HTML:
curl -s https://tusitio.com/ | grep -c 'data-src='
Si eso devuelve un número alto y tu auditoría dice que el sitio tiene pocas imágenes, ya sabes por dónde va.
Lo que nos llevamos
Este fallo no lo habría encontrado ningún test unitario, y de hecho no lo encontró: teníamos 810
pasando en verde. Los fixtures de imágenes que habíamos escrito usaban <img src="/foto.jpg">,
como los ejemplos de los libros.
El HTML real no se parece a los ejemplos de los libros. Lleva plugins encima.
Hay una segunda parte que descubrimos después, y es cara: al empezar a leer las imágenes, la tabla pasó de cero a 4,4 millones de filas, y eso destapó un índice que faltaba en el motor. La pasada final de un rastreo grande se fue a más de ocho horas. Pero eso da para otro artículo.