SEO & Performance

Que tu sitio web sea increíble no sirve de nada si nadie lo encuentra. SEO (Search Engine Optimization) es el conjunto de técnicas que hacen que Google y otros buscadores entiendan, indexen y muestren tu página en los resultados de búsqueda. Pero SEO no es solo meter palabras clave: es tener un sitio rápido, accesible, bien estructurado y con contenido de calidad. Y aquí es donde entra la performance: un sitio rápido no solo rankea mejor en Google, sino que retiene a los usuarios, mejora la conversión y reduce el costo de anuncios. Esta sección te enseña las bases de SEO técnico y las métricas de performance que realmente importan.

Meta Tags Esenciales

Los meta tags son fragmentos de información en el <head> de tu HTML que le dicen a los buscadores y a las redes sociales de qué trata tu página. No son visibles directamente para el usuario que navega el sitio, pero son lo primero que lee Google cuando visita tu página. Los meta tags correctos pueden marcar la diferencia entre aparecer en la primera posición de Google o quedar enterrado en la página 5. No son "magia" para rankear, son la base mínima que todo sitio necesita para ser interpretado correctamente.

HTML
<head>
    <!-- Obligatorios: encoding y viewport -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- SEO básico -->
    <title>Título de la página — Nombre del sitio</title>
    <meta name="description" content="Descripción de 150-160 caracteres que aparece en Google.">
    <meta name="robots" content="index, follow">

    <!-- Autor y keywords (keywords ya no son un factor de ranking, pero no dañan) -->
    <meta name="author" content="Tu nombre">
    <meta name="keywords" content="desarrollo web, html, css, javascript">

    <!-- Color de la barra del navegador en mobile -->
    <meta name="theme-color" content="#0d1117">

    <!-- Canonical: evita contenido duplicado -->
    <link rel="canonical" href="https://ejemplo.com/pagina">

    <!-- Favicon -->
    <link rel="icon" type="image/svg+xml" href="/favicon.svg">
    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
</head>

El <title> es el meta tag más importante de todos. Es lo que aparece como título azul clickeable en los resultados de Google, lo que se muestra en la pestaña del navegador, y lo que se comparte por defecto en redes sociales. Debería tener entre 50-60 caracteres, incluir la palabra clave principal al principio, y describir claramente el contenido de la página. La description es el texto que aparece debajo del título en Google: no afecta directamente el ranking, pero afecta el CTR (Click-Through Rate), que sí es una señal de calidad para Google. Mantenéla entre 150-160 caracteres y hacéla atractiva para que la gente quiera hacer click.

Meta tag robots

El meta tag robots le dice a los crawlers de Google qué pueden y qué no pueden hacer con tu página. Los valores más comunes son index (permite indexar la página), noindex (no la indexa pero sigue los links), follow (sigue los links de la página para descubrir más contenido), y nofollow (no sigue los links). El valor por defecto es index, follow, así que normalmente no necesitás incluirlo explícitamente. Lo usás cuando querés evitar que Google indexe una página (como páginas de admin, resultados de búsqueda interna, o contenido duplicado), o cuando no querés que pase link juice a otras páginas.

HTML — Valores de robots
<!-- No indexar esta página (pero seguir sus links) -->
<meta name="robots" content="noindex, follow">

<!-- Indexar pero no seguir los links -->
<meta name="robots" content="index, nofollow">

<!-- No indexar ni seguir links (páginas privadas) -->
<meta name="robots" content="noindex, nofollow">

<!-- No mostrar el snippet en los resultados de búsqueda -->
<meta name="robots" content="nosnippet">

<!-- No guardar caché de la página -->
<meta name="robots" content="noarchive">

El tag canonical evita contenido duplicado

Si tenés una página accesible desde múltiples URLs (por ejemplo /producto?id=1 y /producto/zapatillas), el tag rel="canonical" le dice a Google cuál es la URL "oficial". Sin él, Google podría considerarlas como páginas duplicadas y dividir el ranking entre ambas. Si usás parámetros de URL para filtros, ordenamiento o tracking, siempre agregá un canonical a la URL limpia.

Open Graph & Social Cards

Cuando alguien comparte tu página en Twitter, Facebook, LinkedIn o WhatsApp, las redes sociales leen los meta tags de Open Graph (og:*) para generar una tarjeta visual con título, descripción e imagen. Sin estos tags, las redes sociales intentan adivinar el contenido (y generalmente lo hacen mal: toman un texto aleatorio como descripción o no muestran imagen). Con Open Graph, controlás exactamente cómo se ve tu página cuando se comparte, lo que aumenta drásticamente el CTR de los links compartidos.

HTML — Open Graph completo
<head>
    <!-- Open Graph (Facebook, LinkedIn, WhatsApp, etc.) -->
    <meta property="og:type" content="website">
    <meta property="og:url" content="https://ejemplo.com/pagina">
    <meta property="og:title" content="Título atractivo para compartir">
    <meta property="og:description" content="Descripción corta y tentadora para redes sociales.">
    <meta property="og:image" content="https://ejemplo.com/og-image.png">
    <meta property="og:image:width" content="1200">
    <meta property="og:image:height" content="630">
    <meta property="og:locale" content="es_AR">
    <meta property="og:site_name" content="Nombre de tu sitio">

    <!-- Twitter Card (X) -->
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:title" content="Título para Twitter">
    <meta name="twitter:description" content="Descripción para Twitter.">
    <meta name="twitter:image" content="https://ejemplo.com/og-image.png">
    <meta name="twitter:creator" content="@tu_usuario">
</head>

La imagen OG es el elemento más importante de Open Graph. Debería ser de 1200x630 píxeles (la proporción 1.91:1 que usan Facebook y LinkedIn). Si la imagen es más chica, las redes sociales la recortan y se ve mal. Si es más grande, la comprimen. Un buen OG image tiene: texto grande y legible, colores que contrasten con el fondo de la red social, y un logo o marca identificativa. No pongás texto demasiado pequeño porque en mobile se vuelve ilegible. Herramientas como og-image.vercel.app te generan imágenes OG dinámicamente a partir de un template.

Valores de og:type y twitter:card
| Valor                    | Cuándo usarlo                                    |
|--------------------------|------------------------------------------------------|
| og:type=website          | Páginas principales, landing pages               |
| og:type=article          | Posts de blog, noticias, artículos              |
| og:type=profile          | Perfil de persona                                     |
| og:type=video.other      | Páginas con video principal                       |
| twitter:card=summary     | Card pequeño con imagen cuadrada (144x144)     |
| twitter:card=summary_large_image | Card grande con imagen rectangular (igual que OG) |

Probar tus Open Graph tags

Facebook tiene un herramienta llamada Sharing Debugger (developers.facebook.com/tools/debug/) donde pegás tu URL y te muestra exactamente cómo se ve tu link al compartirlo. Twitter tiene algo similar en Card Validator (cards-dev.twitter.com/validator). Usálas después de agregar los tags OG para verificar que todo se vea bien. Si cambiás la imagen OG, puede que las redes sociales tarden horas en actualizar su caché — forzá el refresco con estas herramientas.

HTML Semántico y su Impacto en SEO

Google no "ve" tu página como un humano: lee el HTML y lo interpreta. Cuando usás etiquetas semánticas como <header>, <nav>, <main>, <article>, <section> y <footer>, le estás dando información sobre la estructura y el significado de tu contenido, no solo sobre cómo se ve. Un <h1> le dice a Google "este es el título principal", un <article> le dice "esto es un contenido independiente que podría aparecer en un feed", y un <nav> le dice "esto es navegación, no contenido principal". Todo esto ayuda a Google a entender mejor tu página y, en consecuencia, a rankearla mejor.

HTML — Estructura semántica SEO-friendly
<body>
    <header>
        <nav aria-label="Navegacion principal">
            <!-- Logo y links principales -->
        </nav>
    </header>

    <main>
        <!-- Un SOLO h1 por página -->
        <h1>Título principal de la página</h1>

        <article>
            <h2>Título del artículo</h2>
            <p>Contenido del artículo...</p>

            <section>
                <h3>Subsección dentro del artículo</h3>
                <p>Más contenido...</p>
            </section>
        </article>

        <aside>
            <!-- Contenido complementario (sidebar, Related posts, etc.) -->
        </aside>
    </main>

    <footer>
        <!-- Copyright, links secundarios, sitemap -->
    </footer>
</body>

Jerarquía de headings

Los headings (<h1> a <h6>) son uno de los factores de SEO on-page más importantes. Google usa la jerarquía de headings para entender la estructura de tu contenido, igual que un índice de un libro. Las reglas son simples pero estrictas: un solo <h1> por página (es el título principal), los <h2> son las secciones principales, los <h3> son subsecciones dentro de un <h2>, y así sucesivamente. Nunca saltees niveles (no vayas de <h2> a <h4>), y no uses headings solo por el tamaño visual (para eso está CSS). Incluir palabras clave relevantes en los headings ayuda, pero no los fuerces: el contenido primero.

Errores comunes que matan tu SEO

No tener <title> o dejarlo vacío. Usar múltiples <h1> en la misma página. Tener la misma meta description en todas las páginas. Imágenes sin atributo alt (Google no puede "ver" imágenes). Contenido oculto con display: none o texto del mismo color que el fondo (Google penaliza esto). Links rotos (404) que generan una mala experiencia de rastreo. JavaScript que renderiza contenido crítico que Googlebot no puede ejecutar.

Structured Data (JSON-LD)

Structured data (datos estructurados) es una forma de agregar información explícita sobre tu página en un formato estándar que los buscadores pueden leer directamente. Es como darle a Google una "ficha técnica" de tu contenido en vez de que tenga que adivinarla. Cuando agregás structured data, tu página puede aparecer con rich snippets en los resultados de búsqueda: estrellas de reseñas, precios de productos, fechas de eventos, preguntas frecuentes expandibles, y más. Estos rich snippets hacen que tu resultado destaque visualmente y aumentan el CTR significativamente.

El formato más usado y recomendado hoy es JSON-LD (JavaScript Object Notation for Linked Data). Se agrega como un bloque <script type="application/ld+json"> dentro del <head> y es fácil de leer, escribir y generar dinámicamente. Los tipos de datos se definen en schema.org, un vocabulario compartido por Google, Bing, Yahoo y Yandex.

JSON-LD — Artículo (BlogPost)
{
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "headline": "Guía completa de Flexbox en CSS",
    "description": "Aprendé a usar Flexbox desde cero con ejemplos prácticos.",
    "image": "https://ejemplo.com/images/flexbox-guide.png",
    "author": {
        "@type": "Person",
        "name": "María García",
        "url": "https://ejemplo.com/autor/maria"
    },
    "publisher": {
        "@type": "Organization",
        "name": "WebForge",
        "logo": {
            "@type": "ImageObject",
            "url": "https://ejemplo.com/logo.png"
        }
    },
    "datePublished": "2026-06-10",
    "dateModified": "2026-06-11"
}
JSON-LD — FAQ (Preguntas Frecuentes)
{
    "@context": "https://schema.org",
    "@type": "FAQPage",
    "mainEntity": [
        {
            "@type": "Question",
            "name": "¿Qué es CSS Flexbox?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Flexbox es un módulo de CSS que permite alinear y distribuir elementos dentro de un contenedor de manera flexible y eficiente."
            }
        },
        {
            "@type": "Question",
            "name": "¿Cuál es la diferencia entre justify-content y align-items?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "justify-content controla la alineación en el eje principal (horizontal por defecto), mientras que align-items controla la alineación en el eje transversal (vertical por defecto)."
            }
        }
    ]
}

Google ofrece una herramienta llamada Rich Results Test (search.google.com/test/rich-results) donde pegás la URL de tu página o el código JSON-LD y te dice si es válido, si es elegible para rich snippets, y si hay errores. También podés ver todos los rich snippets disponibles en Google Search Gallery (developers.google.com/search/docs/appearance/structured-data/search-gallery). Los tipos más útiles para sitios comunes son: Article / BlogPosting (para blogs), FAQPage (para preguntas frecuentes), BreadcrumbList (para breadcrumbs en los resultados), HowTo (para tutoriales paso a paso), y Organization (para datos de la empresa en la página principal).

Core Web Vitals

Los Core Web Vitals son un conjunto de métricas de Google que miden la experiencia real del usuario en tu sitio web. Desde 2021, Google las usa como factor de ranking: dos sitios con contenido similar, el más rápido y estable va a rankear mejor. No son las únicas métricas que importan, pero son las que Google considera "core" (fundamentales). Hay tres métricas principales: LCP (velocidad de carga), INP (responsividad interactiva, antes llamado FID), y CLS (estabilidad visual). Entender qué miden y cómo optimizarlas es esencial para cualquier desarrollador web.

LCP (Largest Contentful Paint)

LCP mide cuánto tarda en renderizarse el elemento más grande visible en el viewport. "Elemento más grande" puede ser una imagen hero, un bloque de texto grande, un video o un fondo degradado. Es la métrica que mide "¿cuánto tarda en cargar lo que el usuario ve?". Un LCP bueno es menor a 2.5 segundos, aceptable entre 2.5s y 4s, y malo si supera los 4s. Para mejorarlo, necesitás que el servidor responda rápido, que los recursos críticos se carguen pronto, y que las imágenes grandes estén optimizadas.

INP (Interaction to Next Paint)

INP mide cuánto tarda tu página en responder a una interacción del usuario (un click, un tap, una tecla). Es el reemplazo de FID (First Input Delay) desde marzo de 2024. Mientras que FID solo medía el retraso inicial, INP mide la latencia de todas las interacciones durante toda la visita a la página y toma el peor caso (o el percentil 98). Un INP bueno es menor a 200ms. Si tu página se "congela" cuando el usuario hace click en un botón o scrollea, tu INP va a ser malo. Las causas típicas son: JavaScript pesado que bloquea el hilo principal, handlers de eventos que hacen mucho trabajo sincrónico, o layouts complejos que se recalculan en cada interacción.

CLS (Cumulative Layout Shift)

CLS mide cuánto se mueve el contenido visualmente de forma inesperada mientras la página carga. Es la métrica que mide la estabilidad visual. ¿Alguna vez intentaste hacer click en un botón y justo antes de tocarlo la página se movió y terminaste clickeando en un anuncio? Eso es un CLS alto, y es una de las experiencias más frustrantes para los usuarios. Un CLS bueno es menor a 0.1. Las causas más comunes son: imágenes y iframes sin dimensiones explícitas (ancho y alto), contenido que se inyecta dinámicamente arriba del contenido existente, y fuentes web que causan FOIT (Flash of Invisible Text) o FOUT (Flash of Unstyled Text).

Resumen de Core Web Vitals
| Métrica | Qué mide                          | Bueno  | Malo   |
|-----------|--------------------------------------|--------|--------|
| LCP       | Velocidad de carga del contenido    | < 2.5s | > 4.0s |
| INP       | Responsividad a interacciones       | < 200ms| > 500ms|
| CLS       | Estabilidad visual (layout shifts)  | < 0.1  | > 0.25 |
HTML — Prevenir CLS en imágenes
<!-- MAL: sin dimensiones, el navegador no reserva espacio -->
<img src="hero.jpg" alt="Hero">

<!-- BIEN: width y height reservan el espacio antes de cargar -->
<img src="hero.jpg" alt="Hero" width="1200" height="600" loading="lazy">

<!-- MEJOR: aspect-ratio CSS + width 100% (responsive sin CLS) -->
<img src="hero.jpg" alt="Hero"
     style="width: 100%; aspect-ratio: 2/1; object-fit: cover;"
     loading="lazy">

<!-- Para iframes (YouTube, mapas): siempre envolver en un container con aspect-ratio -->
<div style="aspect-ratio: 16/9; width: 100%;">
    <iframe src="https://www.youtube.com/embed/..." style="width:100%;height:100%;"></iframe>
</div>

¿Dónde veo mis Core Web Vitals reales?

La herramienta definitiva es Google Search Console (search.google.com/search-console) → "Experience del usuario" → "Core Web Vitals". Te muestra las métricas reales de los usuarios de tu sitio (no datos de laboratorio). Para medir en tiempo real durante el desarrollo, usá Chrome DevTools → panel Performance → medir LCP y CLS. Para datos de campo de cualquier página, usá PageSpeed Insights (pagespeed.web.dev).

Lazy Loading

Lazy loading (carga diferida) es la técnica de no cargar un recurso hasta que el usuario realmente lo necesita. La aplicación más común son las imágenes: si tenés una página con 30 imágenes, no tiene sentido cargar las 30 de una vez si el usuario solo ve las primeras 3 en su pantalla. Con lazy loading, las imágenes fuera del viewport se cargan cuando el usuario hace scroll hacia ellas. Esto reduce el tiempo de carga inicial, ahorra ancho de banda, y mejora el LCP porque el navegador se concentra en cargar solo lo que es visible.

loading="lazy" (nativo)

Los navegadores modernos soportan el atributo loading="lazy" en imágenes e iframes. Es la forma más simple de lazy loading: no necesitás JavaScript, no necesitás una librería, y el navegador se encarga de todo. Cuando el usuario se acerca al elemento (antes de que entre al viewport, con un margen de seguridad), el navegador lo carga automáticamente. Soporte: Chrome, Edge, Firefox y Safari 15.4+. Para navegadores más viejos, el atributo se ignora y la imagen se carga normalmente (graceful degradation).

HTML — Lazy loading nativo
<!-- Lazy loading nativo: la forma más simple -->
<img src="foto-abajo.jpg"
     alt="Foto de la galeria"
     width="800"
     height="600"
     loading="lazy"
     decoding="async">

<!-- Imagen hero (arriba del fold): NO uses lazy loading -->
<img src="hero.jpg"
     alt="Imagen principal"
     width="1200"
     height="600"
     fetchpriority="high"
     decoding="async">

<!-- Iframe de YouTube con lazy loading -->
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
        loading="lazy"
        width="800"
        height="450"
        allowfullscreen></iframe>

Dos detalles importantes: primero, no apliqués lazy loading a imágenes que están arriba del fold (en la primera pantalla visible), porque eso retrasaría su carga y empeoraría el LCP. Esas imágenes deberían cargarse inmediatamente, idealmente con fetchpriority="high" para indicarle al navegador que son prioritarias. Segundo, decoding="async" le dice al navegador que puede decodificar la imagen de forma asíncrona sin bloquear el renderizado del resto de la página. Es un atributo poco conocido pero que puede mejorar la percepción de velocidad.

Intersection Observer (lazy loading con JavaScript)

Para escenarios más avanzados (como cargar componentes enteros, ejecutar animaciones, o lazy loading de imágenes con fallback para navegadores viejos), usás la API Intersection Observer. Esta API te permite detectar cuando un elemento entra o sale del viewport de forma eficiente (mucho mejor que escuchar el evento scroll, que es costoso en performance). El navegador te avisa cuando el elemento se vuelve visible y recién ahí ejecutás la acción (cargar la imagen, inicializar el componente, etc.).

JavaScript — Lazy loading con Intersection Observer
// === Lazy loading de imágenes con Intersection Observer ===
// El HTML usa data-src en vez de src:
// <img data-src="foto.jpg" alt="Foto" class="lazy">

const lazyImages = document.querySelectorAll("img.lazy");

const imageObserver = new IntersectionObserver((entries, observer) => {
    entries.forEach((entry) => {
        if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;

            // Si usás srcset, también lo movemos
            if (img.dataset.srcset) {
                img.srcset = img.dataset.srcset;
            }

            img.classList.remove("lazy");
            img.classList.add("loaded");
            observer.unobserve(img); // dejar de observar una vez cargada
        }
    });
}, {
    // rootMargin: "200px" empieza a cargar 200px antes de que sea visible
    rootMargin: "200px",
    threshold: 0.01
});

lazyImages.forEach((img) => imageObserver.observe(img));

// === Lazy loading genérico para cualquier componente ===
function createLazyLoader(selector, loadCallback) {
    const elements = document.querySelectorAll(selector);

    const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
            if (entry.isIntersecting) {
                loadCallback(entry.target);
                observer.unobserve(entry.target);
            }
        });
    }, { rootMargin: "100px" });

    elements.forEach((el) => observer.observe(el));
}

// Uso: cargar un widget pesado solo cuando es visible
createLazyLoader(".heavy-widget", (widget) => {
    widget.innerHTML = "<div>Widget cargado!</div>";
});

Optimización de Imágenes

Las imágenes representan habitualmente entre el 50% y el 65% del peso total de una página web. Optimizarlas es, por lejos, la acción individual que más impacto tiene en la velocidad de carga. No se trata de usar imágenes de baja calidad: se trata de usar el formato correcto, el tamaño correcto para cada dispositivo, y servir solo lo que el usuario necesita. Una foto de fondo que se ve a 400px de ancho en mobile no debería descargar una versión de 2000px.

Formatos modernos: WebP y AVIF

WebP es un formato de imagen desarrollado por Google que ofrece una compresión entre un 25% y un 35% mejor que JPEG para fotos, y un 26% mejor que PNG para gráficos con transparencia. Casi todos los navegadores modernos lo soportan (Chrome, Edge, Firefox, Safari 14+). AVIF es el formato siguiente, basado en el códec de video AV1, y ofrece una compresión aún mejor (hasta un 50% más pequeño que JPEG con calidad similar). Soporte: Chrome, Firefox, Safari 16.4+. La estrategia recomendada es: servir AVIF con fallback a WebP con fallback a JPEG/PNG, usando el elemento <picture>.

HTML — <picture> con múltiples formatos
<!-- El navegador usa la primera <source> que soporte -->
<picture>
    <!-- Navegadores que soportan AVIF -->
    <source type="image/avif" srcset="hero.avif">

    <!-- Navegadores que soportan WebP -->
    <source type="image/webp" srcset="hero.webp">

    <!-- Fallback: JPEG para navegadores viejos -->
    <img src="hero.jpg"
         alt="Descripcion de la imagen"
         width="1200"
         height="600"
         decoding="async">
</picture>

srcset y sizes (imágenes responsivas)

Con srcset y sizes, le decimos al navegador: "tenés estas versiones de la imagen en distintos tamaños, y la imagen se va a mostrar a este ancho en la pantalla". El navegador elige automáticamente la versión óptima según el tamaño de la pantalla del dispositivo, su densidad de píxeles (1x, 2x, 3x), y la velocidad de conexión actual. Esto evita descargar una imagen de 2000px en un celular que solo la muestra a 400px, ahorrando una cantidad enorme de ancho de banda.

HTML — srcset y sizes
<!-- srcset con descriptor "w" (ancho en píxeles) + sizes -->
<img src="foto-800.jpg"
     srcset="foto-400.jpg 400w,
             foto-800.jpg 800w,
             foto-1200.jpg 1200w,
             foto-1600.jpg 1600w"
     sizes="(max-width: 768px) 100vw,
            (max-width: 1024px) 50vw,
            33vw"
     alt="Foto responsiva"
     width="800"
     height="600"
     loading="lazy">

<!-- srcset con descriptor "x" (densidad de píxeles) -->
<img src="[email protected]"
     srcset="[email protected] 1x,
             [email protected] 2x,
             [email protected] 3x"
     alt="Logo">

El atributo sizes es clave y suele confundirse. No define el tamaño de la imagen, sino cuánto ancho va a ocupar la imagen en la pantalla según el viewport. 100vw significa "el 100% del ancho de la pantalla" (full-width), 50vw es la mitad, y 33vw es un tercio. Con esta información, el navegador calcula qué versión del srcset necesita descargar. Si no incluís sizes, el navegador asume 100vw y podría descargar una versión más grande de la necesaria. Acordate: sizes siempre va con srcset que usa descriptores w, no es necesario con descriptores x.

Guía rápida de formatos de imagen
| Formato | Fotos | Gráficos | Transparencia | Animación | Compresion  |
|---------|-------|-------------|----------------|--------------|-------------|
| JPEG    | Excelente | Malo      | No             | No           | Lossy       |
| PNG     | Malo  | Excelente   | Si             | No           | Lossless    |
| WebP    | Excelente | Bueno     | Si             | Si           | Ambos       |
| AVIF    | Excelente | Bueno     | Si             | Si           | Ambos       |
| SVG     | No    | Excelente   | Si             | Si (CSS/SMIL)| Vectorial   |

Regla general:
- Fotos → AVIF > WebP > JPEG
- Iconos/logos → SVG (siempre)
- Capturas de pantalla → PNG o WebP lossless

Herramientas para optimizar imágenes

squoosh.app (de Google): comprime imágenes en el navegador, convierte entre formatos, y ajusta la calidad visualmente. sharp (npm): librería de Node.js para optimizar imágenes en batch. ImageOptim (Mac) / FileOptimizer (Windows): apps de escritorio para comprimir sin perder calidad visible. Para proyectos grandes, usá un CDN de imágenes como Cloudinary o Imgix que optimiza y transforma imágenes on-the-fly con parámetros en la URL.

Lighthouse

Lighthouse es una herramienta de Google (integrada en Chrome DevTools y disponible como CLI o extensión) que audita tu página en cinco categorías: Performance, Accessibility, Best Practices, SEO y PWA. Genera un reporte con puntuaciones de 0 a 100 para cada categoría, junto con sugerencias específicas y priorizadas para mejorar. Es la herramienta más rápida y accesible para auditar la calidad general de tu sitio, y es el punto de partida de cualquier optimización de performance o SEO.

Cómo usar Lighthouse

La forma más fácil es desde Chrome DevTools: abrís las DevTools (F12), vas a la pestaña "Lighthouse", seleccionás las categorías que querés auditar (Performance, Accessibility, SEO, etc.), elegís el dispositivo (Mobile o Desktop), y hacés click en "Analyze page load". En 30-60 segundos tenés un reporte completo. También podés usar PageSpeed Insights (pagespeed.web.dev) para medir cualquier URL sin instalar nada, o el CLI de Lighthouse para automatizar auditorías en tu pipeline de CI/CD.

Categorías y qué miden
| Categoría       | Qué evalúa                                              |
|-----------------|---------------------------------------------------------|
| Performance     | LCP, INP, CLS, tiempos de carga, tamaño de recursos   |
| Accessibility   | Contraste, ARIA, navegación por teclado, alt en imgs   |
| Best Practices  | HTTPS, console errors, APIs obsoletas                 |
| SEO             | Meta tags, robots.txt, canonical, structured data      |
| PWA             | Service worker, manifest, offline support             |

Cómo interpretar el reporte

El reporte de Lighthouse se divide en tres secciones principales: las puntuaciones (los círculos de colores), las métricas (Core Web Vitals y otras), y las oportunidades/diagnósticos. Las oportunidades son sugerencias concretas de optimización que incluyen el ahorro estimado en segundos o kilobytes (por ejemplo: "Comprimir imágenes: ahorra 150 KB"). Los diagnósticos son información sobre tu página que no necesariamente es un problema pero vale la pena revisar. Las auditorías aprobadas son las cosas que ya están bien.

Una puntuación de 90+ es verde (buena), 50-89 es naranja (necesita mejoras), y menor a 50 es roja (mala). Pero no te obsesiones con llegar a 100: es más importante priorizar las oportunidades que más impacto tienen. Si "Comprimir imágenes" te ahorra 2 segundos, priorizá eso antes que "Eliminar JavaScript no utilizado" que te ahorra 0.1s. Lighthouse te muestra el ahorro estimado para que puedas priorizar por impacto, no por número de auditorías.

Bash — Lighthouse CLI
# Instalar Lighthouse CLI
npm install -g lighthouse

# Auditar una página (genera un HTML con el reporte)
lighthouse https://ejemplo.com --output html --output-path ./reporte.html

# Solo performance, modo mobile
lighthouse https://ejemplo.com --only-categories=performance --emulated-form-factor=mobile

# Solo SEO
lighthouse https://ejemplo.com --only-categories=seo --output json --output-path ./seo.json

# Modo headless (sin abrir navegador)
lighthouse https://ejemplo.com --chrome-flags="--headless" --output html

Datos de laboratorio vs datos de campo

Lighthouse te da datos de laboratorio: miden tu sitio en un entorno controlado (tu computadora, con tu conexión, sin caché). Son útiles para desarrollo, pero no reflejan la experiencia real de los usuarios. Los datos de campo (Core Web Vitals reales de Google Search Console) miden la experiencia real de miles de usuarios con distintos dispositivos, conexiones y ubicaciones. Siempre validá tus optimizaciones de laboratorio con datos de campo antes de declarar victoria.

Sitemap.xml y robots.txt

Si tu sitio fuera una ciudad, los links internos serían las calles y el sitemap.xml sería el mapa que le entregás al navegador GPS de Google. Es un archivo XML que lista todas las URLs públicas de tu sitio junto con metadatos como la fecha de última modificación, la frecuencia de actualización y la prioridad relativa de cada página. Google (y Bing, y Yandex) lo leen para descubrir páginas que quizás no encontrarían solo siguiendo links internos, especialmente en sitios grandes o con contenido nuevo que aún no fue linkeado desde ninguna parte. No es un factor de ranking directo, pero acelera la indexación y asegura que Google conozca todas tus páginas.

El robots.txt, en cambio, es el archivo que le dice a los crawlers qué NO deben rastrear. Va en la raíz de tu sitio (tusitio.com/robots.txt) y usa una sintaxis simple para permitir o bloquear el acceso a ciertas rutas. Ambos archivos trabajan en conjunto: el robots.txt controla el acceso al rastreo, y el sitemap.xml dice "estas son las páginas que sí quiero que indexéis". Un error común es bloquear en robots.txt una página que está en el sitemap, lo cual envía una señal contradictoria a Google.

XML — sitemap.xml básico
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

    <url>
        <loc>https://ejemplo.com/</loc>
        <lastmod>2026-06-11</lastmod>
        <changefreq>weekly</changefreq>
        <priority>1.0</priority>
    </url>

    <url>
        <loc>https://ejemplo.com/blog/flexbox-guide</loc>
        <lastmod>2026-06-10</lastmod>
        <changefreq>monthly</changefreq>
        <priority>0.8</priority>
    </url>

    <url>
        <loc>https://ejemplo.com/contacto</loc>
        <lastmod>2026-01-15</lastmod>
        <changefreq>yearly</changefreq>
        <priority>0.5</priority>
    </url>

</urlset>

Estructura del sitemap explicada

Cada entrada <url> dentro del <urlset> representa una página de tu sitio. El tag <loc> es obligatorio y debe contener la URL completa y absoluta (con https://). El <lastmod> indica la fecha de la última modificación en formato YYYY-MM-DD y es una señal para Google de que el contenido se actualizó y debería volver a rastrearlo. El <changefreq> sugiere la frecuencia de actualización (always, hourly, daily, weekly, monthly, yearly, never), aunque hoy en día Google lo usa más como una sugerencia que como una regla estricta. El <priority> va de 0.0 a 1.0 y le indica a Google qué páginas son más importantes relativas a otras de tu sitio: la homepage suele ser 1.0, las páginas de sección 0.8, y las páginas de contenido individual 0.6-0.7. Este valor no afecta el ranking entre tu sitio y el de tus competidores, solo ayuda a Google a priorizar el rastreo dentro de tu propio sitio.

Sitemaps para imágenes y vídeos

Además del sitemap estándar de páginas, existían sitemaps específicos para imágenes (<image:image>) y vídeos (<video:video>) que permitían dar información extra como el título de una imagen, la descripción de un video, o la duración. Sin embargo, desde 2023 Google recomienda usar structured data (JSON-LD) en vez de extensiones de sitemap para imágenes y videos. Para sitios pequeños y medianos (menos de 50.000 URLs), un único sitemap.xml con todas tus páginas es suficiente. Para sitios más grandes, podés dividirlo en múltiples sitemaps y crear un sitemap index que los agrupe.

Texto — robots.txt
# robots.txt - va en la raíz: tusitio.com/robots.txt

# Permitir a todos los crawlers rastrear todo el sitio
User-agent: *
Allow: /

# Bloquear rastreo de carpetas que no queremos indexar
Disallow: /admin/
Disallow: /api/
Disallow: /tmp/
Disallow: /*?utm_*          # Bloquear URLs con parámetros UTM
Disallow: /*?sort=*         # Bloquear URLs con parámetros de orden

# Sitemap - le dice a Google dónde encontrar el sitemap
Sitemap: https://ejemplo.com/sitemap.xml

# Para un CMS específico (ejemplo: WordPress)
# User-agent: *
# Disallow: /wp-admin/
# Disallow: /wp-includes/
# Allow: /wp-admin/admin-ajax.php
# Sitemap: https://ejemplo.com/wp-sitemap.xml

Reglas clave de robots.txt

El User-agent especifica a qué crawler se aplica la regla. Con * aplicás a todos los crawlers, pero podés apuntar a uno específico como Googlebot o Bingbot. Allow y Disallow definen las rutas que se pueden o no rastrear. Las rutas son prefijos: Disallow: /admin/ bloquea todo lo que empiece con /admin/. La directiva Sitemap no es parte del estándar original pero es soportada por todos los buscadores importantes. Un detalle crítico: si bloqueás una página con Disallow, Google no la rastrea pero aún puede indexarla si encuentra un link hacia ella desde otro sitio. Si realmente no querés que una página aparezca en Google, usá noindex en el meta tag robots de esa página.

¿Dónde se envía el sitemap?

Una vez creado tu sitemap.xml, lo enviás a Google Search Console (search.google.com/search-console) en la sección "Sitemaps". Pegás la URL (por ejemplo https://ejemplo.com/sitemap.xml) y Google empieza a rastrearlo. También podés (y deberías) agregar la línea Sitemap: ... en tu robots.txt como ruta de respaldo. Para sitios en GitHub Pages, el sitemap es un archivo XML estático que subís a la raíz del repo. Para sitios dinámicos (WordPress, Next.js, etc.), existen plugins y herramientas que lo generan automáticamente.

No incluís páginas con noindex en el sitemap

Si una página tiene <meta name="robots" content="noindex">, no la pongas en el sitemap. Es contradictorio decirle a Google "esta página existe, indexala" (vía sitemap) y "no indexes esta página" (vía meta tag). Google puede ignorar ambas instrucciones si se contradicen, o puede mostrar un error en Search Console. Lo mismo aplica para páginas bloqueadas con Disallow en robots.txt: si no querés que se rastree, tampoco la pongas en el sitemap.

Checklist SEO Rápido

Esta checklist resume las acciones más importantes de SEO técnico y performance que deberías aplicar a cada página de tu sitio. No es exhaustiva, pero cubre el 80% del impacto con el 20% del esfuerzo. Si hacés todo lo que está en esta lista, tu sitio va a estar en mejor posición que el 90% de los sitios web en términos de SEO técnico. Para la referencia completa y rápida, consultá el SEO Cheatsheet.

SEO Checklist
CADA PÁGINA debe tener:
 [ ] <title> único (50-60 caracteres, keyword al inicio)
 [ ] <meta name="description"> único (150-160 caracteres, atractivo)
 [ ] <meta name="viewport"> con width=device-width
 [ ] Un solo <h1> con la keyword principal
 [ ] Jerarquía de headings correcta (h1 > h2 > h3, sin saltar)
 [ ] <link rel="canonical"> para evitar contenido duplicado
 [ ] Imágenes con alt descriptivo (no "imagen1.jpg")
 [ ] Open Graph tags (og:title, og:description, og:image)
 [ ] Estructura HTML semántica (main, nav, article, footer)
 [ ] URLs limpias y legibles (/blog/flexbox-guide, no /page?id=123)

PERFORMANCE:
 [ ] Imágenes en WebP/AVIF (no JPEG/PNG sin optimizar)
 [ ] Imágenes con width/height (previene CLS)
 [ ] loading="lazy" en imágenes fuera del fold
 [ ] fetchpriority="high" en imágenes hero
 [ ] CSS crítico inline o preload
 [ ] JavaScript defer/async (no bloqueante)
 [ ] Lighthouse Performance > 90 (mobile)
 [ ] LCP < 2.5s, INP < 200ms, CLS < 0.1

EXTRAS:
 [ ] sitemap.xml generado y enviado a Google Search Console
 [ ] robots.txt configurado correctamente
 [ ] HTTPS activo (certificado SSL)
 [ ] JSON-LD structured data para rich snippets
 [ ] 404 page personalizada
 [ ] Redirecciones 301 para páginas movidas