Velocidad de carga: optimización completa de la carga del sitio web
Cómo separar los problemas de respuesta del servidor, carga, renderizado e interacción, y cómo validar las mejoras con datos de campo y de laboratorio.
La velocidad de carga es una de las inversiones que más impacto tienen a la vez en SEO y en conversión. Amazon calculó que cada 100 ms de latencia adicional le costaba el 1 % de las ventas. Google usa la velocidad como factor de posicionamiento en escritorio desde 2010 y en móviles desde 2018, y en 2021 introdujo Core Web Vitals como señal directa de Page Experience.
Qué es la velocidad de carga y cómo se mide
La velocidad de carga no es un número único, sino un conjunto de métricas que miden aspectos distintos de la experiencia de carga. Google PageSpeed Insights combina datos de laboratorio (Lighthouse) y datos de campo de usuarios reales (Chrome User Experience Report). La puntuación final, de 0 a 100, es una suma ponderada de varias métricas, así que no debe ser el único objetivo de optimización.
Para el SEO importan sobre todo los datos de campo (CrUX): Google usa el percentil 75 de los usuarios reales de Chrome al evaluar los Core Web Vitals. Lighthouse ayuda a diagnosticar problemas, pero no es una entrada directa del algoritmo de posicionamiento.
Métricas clave de velocidad
Cada métrica responde a un aspecto concreto de la experiencia del usuario. Entender sus diferencias es la base de un diagnóstico correcto.
| Métrica | Qué mide | Buen valor | Afecta al posicionamiento |
|---|---|---|---|
| TTFB (Time to First Byte) | Tiempo hasta el primer byte de HTML del servidor | < 800 ms | De forma indirecta (a través del LCP) |
| FCP (First Contentful Paint) | Primer píxel de contenido en pantalla | < 1,8 s | Lighthouse, no es un factor de CrUX |
| LCP (Largest Contentful Paint) | Contenido principal visible para el usuario | < 2,5 s | Sí (Core Web Vitals) |
| INP (Interaction to Next Paint) | Capacidad de respuesta ante la interacción del usuario | < 200 ms | Sí (Core Web Vitals, sustituyó a FID) |
| CLS (Cumulative Layout Shift) | Estabilidad del diseño: cuánto saltan los elementos | < 0,1 | Sí (Core Web Vitals) |
| TBT (Total Blocking Time) | Tiempo total de bloqueo del hilo principal por JS | < 200 ms | Aproximación de laboratorio para INP |
Abandonan en 3 s
Usuarios de móvil que abandonan una página que tarda más de 3 segundos en cargarse
Conversión por segundo
Cada segundo adicional de latencia reduce la conversión un 1–3 % de media
Percentil de CrUX
Google evalúa los Core Web Vitals en el percentil 75 de los usuarios reales
Ventana de CrUX
Periodo móvil durante el que se recogen los datos para evaluar el sitio
Diagnóstico: por dónde empezar la optimización
Optimizar a ciegas es tiempo perdido. El orden correcto: medir primero, identificar el cuello de botella, corregirlo y volver a medir.
- Abre PageSpeed Insights y prueba de 5 a 10 páginas clave: la home, las categorías, las fichas de producto y las landings. Fíjate en los datos de campo (Field Data), no solo en la puntuación de Lighthouse.
- En Google Search Console, ve a Core Web Vitals: muestra qué URL tienen valoraciones «Poor» o «Needs improvement» en LCP, INP o CLS, con datos reales de usuarios.
- Ejecuta WebPageTest para un análisis en profundidad: cascada de carga, filmstrip, TTFB e impacto del CDN. Elige la región de prueba más cercana a tu audiencia principal.
- Usa Chrome DevTools → Performance y graba una carga de página. El flame chart muestra qué script ocupa el hilo principal y bloquea el renderizado.
- Revisa Coverage (DevTools → Coverage): el CSS y el JS sin usar son candidatos directos a eliminarse o a cargarse de forma diferida.
PageSpeed Insights
Herramienta gratuita de Google. Muestra datos de laboratorio (Lighthouse) y de campo (CrUX). Ofrece una lista de recomendaciones concretas con el ahorro de tiempo estimado. Es el mejor punto de partida para una auditoría inicial.
WebPageTest
Cascada detallada, filmstrip, pruebas desde varias ubicaciones y comparación de versiones. Muestra el impacto del CDN, del DNS y del handshake SSL. Imprescindible para diagnosticar a fondo el TTFB.
Google Search Console
Datos reales de CrUX por grupos de URL. Muestra la evolución de las métricas en el tiempo: la mejor herramienta para seguir las mejoras tras desplegar las optimizaciones.
Chrome DevTools
Pestañas Performance Profiler y Coverage: sirven para encontrar el script o el CSS concreto que bloquea el renderizado. El flame chart muestra las tareas largas (más de 50 ms) en el hilo principal.
Optimización del servidor y del TTFB
El TTFB (Time to First Byte) es la base de toda la velocidad. Si el servidor responde despacio, cualquier otra optimización trabaja bajo un techo artificial. Objetivo: TTFB < 200 ms en entornos con CDN y < 400 ms en servidores dinámicos.
Alojamiento e infraestructura
- Elección de alojamiento
- El hosting compartido, con recursos repartidos entre miles de sitios, limita el TTFB de forma física. Un VPS o un servidor dedicado con Nginx/Caddy y una caché bien configurada da un TTFB de 20–80 ms para contenido estático.
- CDN (Content Delivery Network)
- Cloudflare, BunnyCDN o Fastly: responde el nodo edge más cercano en lugar de tu servidor de origen. Para contenido estático o en caché, el TTFB baja a 10–50 ms. Para contenido dinámico, depende de la configuración de la caché en el edge.
- HTTP/2 y HTTP/3 (QUIC)
- HTTP/2 elimina el head-of-line blocking y admite multiplexación. HTTP/3 sobre QUIC acelera además el establecimiento de la conexión (0-RTT) y resiste mejor la pérdida de paquetes en redes móviles.
- Geolocalización del servidor
- La distancia física entre el usuario y el servidor añade unos 1 ms por cada 100 km (ida y vuelta). Para una audiencia mayoritariamente europea, un servidor en Fráncfort o en Ámsterdam es bastante más rápido que uno en US-East.
Compresión y codificación
- Activa Brotli (br): ahorra entre el 15 y el 25 % frente a gzip, con una velocidad de descompresión similar. Lo admiten todos los navegadores modernos.
- Deja gzip como alternativa para clientes antiguos. Mínimo: nivel de compresión 6.
- Configura la compresión para HTML, CSS, JS, JSON, XML y SVG. Las imágenes y los archivos binarios ya están comprimidos, así que aplicarles gzip no sirve de nada.
- Usa la cabecera HTTP Vary: Accept-Encoding para que el CDN guarde versiones distintas para cada tipo de cliente.
Caché del servidor
Las páginas dinámicas (PHP, Node.js, Python) consultan la base de datos en cada petición. Una caché permite servir el HTML ya generado sin volver a calcularlo.
- Caché de página completa: Nginx FastCGI Cache, Varnish o Redis. Guardan el HTML ya generado y lo sirven sin tocar la aplicación.
- Caché de objetos: Redis o Memcached para guardar resultados de consultas a la base de datos, sesiones y datos calculados.
- Reglas de invalidación: la caché debe purgarse cuando cambia el contenido (webhook del CMS o caducidad por TTL).
- Stale-while-revalidate: sirve de inmediato la caché caducada y regenérala en segundo plano. Los usuarios no esperan a la regeneración.
Optimización de recursos: imágenes, fuentes y CSS
Imágenes
Las imágenes suelen ser la categoría que más peso aporta a la página. Una optimización correcta ahorra entre el 30 y el 70 % del tráfico y afecta directamente al LCP.
| Técnica | Ahorro | Prioridad |
|---|---|---|
| WebP en lugar de JPEG/PNG | 25–35 % | Alta |
| AVIF en lugar de JPEG/PNG | 40–55 % | Alta (soporte de más del 90 % de navegadores) |
| Compresión sin pérdida (PNG → oxipng) | 5–20 % | Media |
| Dimensionado correcto (srcset + sizes) | 50–80 % en móvil | Alta |
| Carga diferida (lazy loading) de imágenes fuera de pantalla | Ahorra peticiones en la carga | Alta |
| fetchpriority="high" para la imagen LCP | 0,5–1,5 s de LCP | Crítica |
Usa el elemento <picture> para servir el formato adecuado: AVIF para los navegadores que lo admiten, WebP como alternativa y JPEG/PNG para los navegadores antiguos. El componente Image de Next.js lo hace automáticamente.
Fuentes
- Aloja las fuentes tú mismo: sirve los .woff2 desde tu propio dominio. Así eliminas la resolución DNS, el handshake TCP y la dependencia del CDN de Google Fonts.
- Precarga las fuentes críticas: <link rel="preload" as="font" type="font/woff2" crossorigin> en <head>. El navegador empieza a cargarlas antes de analizar el CSS.
- font-display: swap: el navegador muestra la fuente del sistema mientras se carga la personalizada. Elimina el FOIT (texto invisible).
- Subconjuntos de fuentes: carga solo los glifos necesarios (latín y cirílico). Herramientas: glyphhanger o fonttools.
- Usa fuentes variables: un solo archivo en lugar de varios estilos (regular, bold, italic). Ahorran entre el 30 y el 50 % del tamaño total de las fuentes.
CSS
- CSS crítico insertado
- Los estilos de la zona visible sin desplazarse se incrustan directamente en <head>, dentro de una etiqueta <style>. El navegador renderiza la primera pantalla sin esperar a un archivo CSS externo. El resto del CSS se carga de forma asíncrona.
- Minificación
- Eliminar espacios y comentarios, y acortar propiedades. Cssnano o LightningCSS. Ahorro típico: entre el 10 y el 30 % del tamaño original.
- Eliminación de CSS no utilizado
- PurgeCSS, UnCSS o el mecanismo integrado del framework (purge de Tailwind). Es especialmente importante con Bootstrap o Material UI, porque arrastran miles de reglas sin usar.
- Evita @import en CSS
- @import crea peticiones en secuencia: el navegador carga el archivo, encuentra el @import y solo entonces empieza a cargar el siguiente. Para cargar en paralelo, usa etiquetas <link>.
JavaScript: bloqueo del renderizado y hilo principal
El JavaScript es el principal enemigo de la velocidad de carga en los sitios modernos. Bloquea el renderizado, ocupa el hilo principal y retrasa la interactividad. Objetivo: el mínimo de JS en la ruta crítica y el máximo uso de defer, async e import dinámico.
Estrategias de carga
| Atributo | Comportamiento | Cuándo usarlo |
|---|---|---|
| Sin atributo | Bloquea el análisis del HTML y se ejecuta de inmediato | Solo código inline crítico |
| async | Se carga en paralelo y se ejecuta cuando está listo (puede interrumpir el análisis) | Scripts independientes (analítica) |
| defer | Se carga en paralelo y se ejecuta después de analizar el HTML | La mayoría de scripts de la página |
| type="module" | Se difiere por defecto y admite ESM | Scripts ESM modernos |
Paquetes y división de código
- Code splitting: divide el JS en fragmentos y carga solo lo necesario para la página actual. En Next.js esto ocurre automáticamente por página.
- Import dinámico: import('module') para componentes que no hacen falta en la carga inicial (ventanas modales, pestañas, filtros).
- Tree shaking: incluye solo el código que realmente se usa. Webpack y Rollup lo hacen con paquetes ESM. Comprueba si hay dependencias CommonJS que rompan el tree shaking.
- Análisis del paquete: bundlephobia.com para revisar el peso de los paquetes npm y @next/bundle-analyzer para Next.js, que muestra exactamente qué ocupa espacio.
- Evita las bibliotecas monolíticas grandes: moment.js (67 KB) → day.js (2 KB), lodash → utilidades individuales, jQuery → JS nativo.
SPA y renderizado en servidor
Las SPA del lado del cliente (React sin SSR, Angular, Vue con CSR) devuelven HTML vacío y generan el contenido en el navegador. Esto provoca un LCP alto y un Time to Interactive deficiente.
- SSR (Server-Side Rendering)
- El HTML completo se genera en el servidor. El navegador recibe el contenido listo de inmediato. El LCP, el FCP y la puntuación de Lighthouse mejoran mucho. Requiere hidratación en el cliente, así que ten en cuenta el TTI (Time to Interactive).
- SSG (Static Site Generation)
- El HTML se genera en el momento de la compilación. TTFB y LCP, máximamente rápidos. Indicado para contenido que cambia poco: blog, documentación, landings.
- PPR (Partial Prerendering)
- Novedad de Next.js 15: un envoltorio estático de la página con partes dinámicas en streaming. El envoltorio estático se sirve al instante desde el CDN, mientras los datos dinámicos llegan en streaming a medida que están listos.
Caché: navegador y CDN
Una caché bien configurada es la optimización más barata y la de mayor impacto para los visitantes que vuelven. Objetivo: todos los recursos estáticos en caché durante 1 año; el HTML, con poca caché o sin ella.
| Tipo de recurso | Cache-Control | Estrategia de invalidación |
|---|---|---|
| JS/CSS con hash (bundle.abc123.js) | max-age=31536000, immutable | El hash cambia cuando cambia el archivo |
| Imágenes | max-age=2592000 (30 días) | URL con versión o content hash |
| Páginas HTML | no-cache o max-age=0, must-revalidate | Siempre se revalida con el servidor |
| Fuentes | max-age=31536000, immutable | Hash en la URL o versionado |
| Respuestas de API | Cache-Control: private, max-age=60 | Depende de la frecuencia de cambio de los datos |
- Hash basado en el contenido (fingerprinting): Webpack, Vite y Next.js añaden automáticamente un hash del contenido al nombre del archivo. Si cambia el código, cambia el hash y no se usa la caché anterior.
- ETag y Last-Modified: si el cliente ya tiene el recurso, el servidor responde 304 Not Modified sin cuerpo. Ahorra tráfico, pero sigue habiendo un viaje de ida y vuelta por la red.
- Service Worker: una caché programable en el navegador. Permite estrategias complejas (Cache-First, Network-First, Stale-While-Revalidate) para PWA y para el uso sin conexión.
- CDN Cache-Control: usa s-maxage para controlar la caché del CDN de forma independiente del max-age del navegador. El CDN guarda más tiempo y el navegador, menos.
Scripts de terceros: el gran culpable oculto
Los scripts de terceros (analítica, chats, píxeles, pruebas A/B, widgets) suelen ser la causa principal de un TBT y un INP malos. La página comercial media carga entre 15 y 30 scripts de terceros.
Auditoría de scripts de terceros
En WebPageTest, la pestaña «Third-party Summary» muestra qué script bloquea el hilo principal y durante cuántos milisegundos. Los infractores habituales: Intercom, Hotjar y las versiones antiguas de Google Analytics (gtag sin async).
Carga diferida
Carga los scripts no críticos con retraso: setTimeout(loadScript, 3000) después del evento load. El usuario puede interactuar con la página antes de que se cargue la analítica.
DNS prefetch y preconnect
<link rel="preconnect"> para los dominios con los que seguro vas a conectar. <link rel="dns-prefetch"> para los probables. Ahorro: entre 100 y 300 ms por resolución DNS y handshake TCP con cada dominio de terceros.
Sustituir o eliminar
La mejor optimización de scripts de terceros es eliminarlos. ¿Para qué un chat de pago en todas las páginas? ¿Para qué cinco píxeles de redes sociales? Auditar los scripts que realmente se usan suele revelar entre un 30 y un 50 % innecesarios.
Preguntas frecuentes
¿Qué importa más para el SEO: la puntuación de Lighthouse o los Core Web Vitals?
¿Con qué rapidez afectan las mejoras de velocidad a los posicionamientos?
¿Qué hacer si Lighthouse da una puntuación alta pero el sitio se nota lento?
¿Merece la pena usar AMP para ganar velocidad?
¿Influye la velocidad más en el posicionamiento móvil que en el de escritorio?
Check it with SpiderHead
Free and local: run the audit on your own machine.



