Lighthouse: Auditoría de Rendimiento Web e Integración CI/CD
Guía técnica profunda que cubre Core Web Vitals, metodología de scoring de rendimiento, auditoría de accesibilidad, chequeos SEO, integración CI/CD, API programática Node.js, presupuestos de rendimiento, flujos de usuario, modo timespan, Chrome DevTools y API de PageSpeed Insights.
Índice de Contenidos
- Core Web Vitals (LCP, INP, CLS)
- Metodología de Scoring de Rendimiento
- Auditoría de Accesibilidad (WCAG AA/AAA, axe-core)
- Auditoría SEO (Meta, Datos Estructurados, Robots, Canonical)
- Mejores Prácticas (HTTPS, CSP, SRI)
- Lighthouse CI (@lhci/cli, GitHub Actions, GitLab CI)
- Uso Programático (API Node.js)
- Presupuestos de Rendimiento (Tamaño y Tiempos)
- Flujos de Usuario y Modo Timespan
- Chrome DevTools Lighthouse
- API de PageSpeed Insights
- Lighthouse 13: Auditorías Basadas en Insights (2025-2026)
1. Core Web Vitals (LCP, INP, CLS)
Largest Contentful Paint (LCP)
LCP mide el rendimiento de carga: el tiempo hasta que el elemento de contenido visible más grande (imagen, título, póster de video) se renderiza. Umbrales: bueno < 2.5s, necesita mejora 2.5-4.0s, pobre > 4.0s. Optimizaciones clave: precargar recursos críticos, optimizar imágenes (WebP/AVIF), renderizado del lado del servidor y caching CDN.
<!-- Preload LCP image -->
<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">
<!-- Responsive images with modern formats -->
<picture>
<source srcset="/hero.avif" type="image/avif">
<source srcset="/hero.webp" type="image/webp">
<img src="/hero.jpg" alt="Hero" width="1200" height="600"
loading="eager" fetchpriority="high" decoding="async">
</picture>
<!-- Inline critical CSS to avoid render-blocking -->
<style>
/* Critical above-the-fold CSS inlined here */
body { font-family: system-ui; margin: 0; }
.hero { min-height: 60vh; }
</style>
<!-- Defer non-critical CSS -->
<link rel="preload" href="/styles.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
Interaction to Next Paint (INP)
INP reemplazó a FID en marzo 2024 como la métrica de responsividad. Mide la latencia de todas las interacciones (clicks, taps, pulsaciones de teclas) durante todo el ciclo de vida de la página, reportando la peor interacción. Umbrales: bueno < 200ms, necesita mejora 200-500ms, pobre > 500ms.
// Break up long tasks to improve INP
function processLargeDataset(items) {
const CHUNK_SIZE = 50;
let index = 0;
function processChunk() {
const end = Math.min(index + CHUNK_SIZE, items.length);
for (let i = index; i < end; i++) {
renderItem(items[i]);
}
index = end;
if (index < items.length) {
// Yield to main thread between chunks
requestAnimationFrame(() => {
setTimeout(processChunk, 0);
});
}
}
processChunk();
}
// Use scheduler.yield() (when available) for better INP
async function handleClick(event) {
// Step 1: immediate visual feedback
button.classList.add('loading');
// Yield to let the browser paint
if ('scheduler' in globalThis) {
await scheduler.yield();
}
// Step 2: expensive computation
const result = await computeExpensiveResult();
updateUI(result);
}
// Monitor INP in production with web-vitals
import { onINP } from 'web-vitals';
onINP((metric) => {
analytics.send('inp', {
value: metric.value,
element: metric.attribution?.interactionTarget,
type: metric.attribution?.interactionType,
});
});
Cumulative Layout Shift (CLS)
CLS mide la estabilidad visual: cuánto se desplaza inesperadamente el contenido visible durante la carga de la página. Umbrales: bueno < 0.1, necesita mejora 0.1-0.25, pobre > 0.25. Causas principales: imágenes sin dimensiones, inyección de contenido dinámico, web fonts causando FOIT/FOUT.
<!-- Always set dimensions on images/videos -->
<img src="/photo.webp" width="800" height="600" alt="Photo">
<!-- Use aspect-ratio for responsive containers -->
<style>
.video-embed {
aspect-ratio: 16 / 9;
width: 100%;
background: #111;
}
/* Reserve space for dynamic ad slots */
.ad-slot {
min-height: 250px;
contain: layout;
}
/* Font swap strategy to minimize CLS from web fonts */
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: optional; /* or swap for important fonts */
size-adjust: 100.5%; /* match fallback metrics */
ascent-override: 95%;
descent-override: 22%;
line-gap-override: 0%;
}
</style>
<!-- Preload critical fonts -->
<link rel="preload" href="/fonts/custom.woff2" as="font"
type="font/woff2" crossorigin>
2. Metodología de Scoring de Rendimiento
Cómo Funcionan los Scores de Lighthouse
El score de rendimiento de Lighthouse es un promedio ponderado de 5 métricas: FCP (10%), SI (10%), LCP (25%), TBT (30% - proxy de laboratorio para INP) y CLS (25%). Cada métrica se mapea a un score mediante una curva de distribución log-normal derivada de datos reales del HTTP Archive. Scores 90-100 son verdes (bueno), 50-89 son naranjas (necesita mejora) y 0-49 son rojos (pobre).
// Lighthouse scoring weights (v12+)
const SCORING_WEIGHTS = {
'first-contentful-paint': 0.10, // FCP - time to first content
'speed-index': 0.10, // SI - visual loading speed
'largest-contentful-paint': 0.25, // LCP - main content loaded
'total-blocking-time': 0.30, // TBT - lab proxy for INP
'cumulative-layout-shift': 0.25, // CLS - visual stability
};
// Total: 1.00
// Score thresholds (green/orange/red)
const THRESHOLDS = {
performance: { green: 90, orange: 50 },
accessibility: { green: 90, orange: 50 },
'best-practices': { green: 90, orange: 50 },
seo: { green: 90, orange: 50 },
};
// Metric targets for a score of 90+
// FCP: < 1.8s (First Contentful Paint)
// SI: < 3.4s (Speed Index)
// LCP: < 2.5s (Largest Contentful Paint)
// TBT: < 200ms (Total Blocking Time)
// CLS: < 0.1 (Cumulative Layout Shift)
// Log-normal scoring formula:
// score = POISSON_CDF(ln(metricValue / median) / ln(p10 / median))
// where median and p10 are derived from HTTP Archive data
3. Auditoría de Accesibilidad (WCAG AA/AAA, axe-core)
Motor axe-core
Lighthouse usa el motor axe-core (de Deque Systems) para ejecutar sus auditorías de accesibilidad. axe-core verifica ~80 reglas cubriendo criterios WCAG 2.1 Nivel A y AA. Detecta problemas como alt text faltante, contraste de color insuficiente, labels de formularios ausentes, uso indebido de ARIA y trampas de teclado.
// Run axe-core standalone for deeper analysis
import AxeBuilder from '@axe-core/playwright';
import { chromium } from 'playwright';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://josenobile.co/');
const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21aa', 'best-practice'])
.analyze();
console.log(`Violations: ${results.violations.length}`);
results.violations.forEach(v => {
console.log(`[${v.impact}] ${v.id}: ${v.description}`);
console.log(` Affected: ${v.nodes.length} elements`);
console.log(` Fix: ${v.help}`);
});
await browser.close();
// axe-core rule tags mapped to WCAG levels:
// 'wcag2a' - WCAG 2.0 Level A
// 'wcag2aa' - WCAG 2.0 Level AA
// 'wcag21a' - WCAG 2.1 Level A
// 'wcag21aa' - WCAG 2.1 Level AA
// 'wcag22aa' - WCAG 2.2 Level AA
// 'best-practice' - Not WCAG but recommended
Auditorías Clave de Accesibilidad
Lighthouse verifica ~60 auditorías de accesibilidad basadas en criterios WCAG 2.1 AA. Testea ratios de contraste de color, atributos ARIA, navegación por teclado, jerarquía de headings, alt text de imágenes, labels de formularios y gestión de foco. Para cumplimiento WCAG AAA, se necesitan verificaciones manuales adicionales: contraste mejorado (7:1 para texto normal, 4.5:1 para grande), sin dependencias de tiempo y lenguaje de señas para multimedia.
<!-- Skip navigation link -->
<a class="skip-link" href="#main-content">Skip to content</a>
<!-- Proper heading hierarchy -->
<h1>Page Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>
<!-- Color contrast: WCAG AA requires 4.5:1 for normal text, 3:1 for large -->
<!-- WCAG AAA requires 7:1 for normal text, 4.5:1 for large text -->
<style>
:root {
--text: #e2e8f0; /* on dark bg #0b0f1a = contrast 12.5:1 (AAA) */
--muted: #94a3b8; /* on dark bg = contrast 7.1:1 (AAA for large) */
}
</style>
<!-- Accessible form with proper labeling -->
<form>
<label for="email">Email address</label>
<input type="email" id="email" name="email"
autocomplete="email"
aria-describedby="email-help"
required>
<span id="email-help">We'll never share your email.</span>
<!-- Accessible custom select -->
<label for="lang">Language</label>
<select id="lang" aria-label="Language">
<option value="en-US">English</option>
<option value="es-CO">Español</option>
</select>
</form>
<!-- ARIA live region for dynamic updates -->
<div aria-live="polite" aria-atomic="true" id="status"></div>
<script>
function updateStatus(message) {
document.getElementById('status').textContent = message;
}
</script>
4. Auditoría SEO (Meta, Datos Estructurados, Robots, Canonical)
Meta Tags y Datos Estructurados
Las auditorías SEO de Lighthouse verifican meta descriptions, URLs canónicas, directivas robots, hreflang para sitios multilingües, datos estructurados (JSON-LD) y adaptabilidad móvil. Cada auditoría contribuye al score SEO.
<!-- Essential SEO meta tags -->
<title>Lighthouse Guide — Jose Nobile</title>
<meta name="description" content="Deep technical guide to Lighthouse:
Core Web Vitals, performance scoring, accessibility auditing...">
<link rel="canonical" href="https://josenobile.co/guides/lighthouse/">
<meta name="robots" content="index,follow,max-snippet:-1">
<!-- Hreflang for bilingual content -->
<link rel="alternate" hreflang="en-US"
href="https://josenobile.co/guides/lighthouse/">
<link rel="alternate" hreflang="es-CO"
href="https://josenobile.co/guides/lighthouse/">
<!-- Open Graph for social sharing -->
<meta property="og:type" content="article">
<meta property="og:title" content="Lighthouse Guide">
<meta property="og:description" content="Core Web Vitals, CI/CD...">
<meta property="og:url" content="https://josenobile.co/guides/lighthouse/">
<meta name="twitter:card" content="summary_large_image">
Robots, Canonical y Rastreabilidad
Lighthouse verifica que las páginas no estén bloqueadas de la indexación, que las URLs canónicas sean válidas y autorreferentes, que robots.txt no bloquee accidentalmente recursos críticos, y que la página sea rastreable. También verifica que el texto de los enlaces sea descriptivo y que los tap targets tengan tamaño adecuado para móvil.
# robots.txt
User-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Sitemap: https://josenobile.co/sitemap.xml
# Lighthouse SEO checks include:
# [x] Page has a meta description
# [x] Document has a title element
# [x] Page has a valid canonical URL
# [x] Page is not blocked from indexing (no noindex)
# [x] robots.txt is valid and accessible
# [x] Links have descriptive text (not "click here")
# [x] Hreflang tags are valid
# [x] Document has a valid lang attribute
# [x] Tap targets are sized appropriately (>= 48x48px)
# [x] Font size is legible (>= 12px)
<!-- JSON-LD structured data (TechArticle) -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TechArticle",
"headline": "Lighthouse: Web Performance Auditing",
"author": {
"@type": "Person",
"name": "Jose Nobile",
"url": "https://josenobile.co/"
},
"publisher": {"@type": "Person", "name": "Jose Nobile"},
"datePublished": "2026-03-17",
"dateModified": "2026-04-24",
"url": "https://josenobile.co/guides/lighthouse/",
"about": ["Lighthouse", "Core Web Vitals", "Web Performance"]
}
</script>
5. Mejores Prácticas (HTTPS, CSP, SRI)
Seguridad y Estándares Web Modernos
La categoría de Mejores Prácticas verifica uso de HTTPS, Content Security Policy (CSP), Subresource Integrity (SRI), headers de seguridad, errores JavaScript, APIs deprecadas, aspect ratios correctos de imágenes y cumplimiento de estándares web modernos.
# Security headers (_headers file for Cloudflare Pages)
/*
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.josenobile.co; frame-ancestors 'none'; base-uri 'self'; form-action 'self'
Subresource Integrity (SRI)
SRI asegura que los recursos de terceros (scripts, hojas de estilo) no hayan sido alterados. Lighthouse verifica que los scripts externos incluyan atributos integrity. Los hashes SRI verifican que el contenido del archivo coincida con lo esperado al momento del build, protegiendo contra compromisos de CDN y ataques a la cadena de suministro.
<!-- SRI for third-party scripts -->
<script
src="https://cdn.example.com/[email protected]/lib.min.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
crossorigin="anonymous">
</script>
<!-- SRI for stylesheets -->
<link
rel="stylesheet"
href="https://cdn.example.com/[email protected]/main.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
# Generate SRI hash:
# openssl dgst -sha384 -binary lib.min.js | openssl base64 -A
# Or: shasum -b -a 384 lib.min.js | awk '{print $1}' | xxd -r -p | base64
# Lighthouse best practices checklist:
# [x] HTTPS with valid certificate
# [x] No mixed content (HTTP resources on HTTPS page)
# [x] No console errors in JavaScript
# [x] No deprecated APIs (document.write, etc.)
# [x] Images have correct aspect ratios
# [x] Charset declared early in <head>
# [x] No vulnerable JavaScript libraries
# [x] CSP prevents XSS attacks
# [x] SRI on external resources
# [x] Correct doctype declaration
6. Lighthouse CI (@lhci/cli, GitHub Actions, GitLab CI)
Configuración de Lighthouse CI
Lighthouse CI (LHCI) usa @lhci/cli para ejecutar auditorías automáticamente en tu pipeline CI/CD, rastrear scores en el tiempo y hacer fallar builds cuando los scores caen por debajo de los umbrales. Soporta assertions para aplicar presupuestos de rendimiento y puede subir resultados a almacenamiento temporal o a un servidor LHCI propio.
// lighthouserc.js - @lhci/cli configuration
module.exports = {
ci: {
collect: {
url: [
'http://localhost:8080/',
'http://localhost:8080/health/',
'http://localhost:8080/guides/lighthouse/',
],
numberOfRuns: 3, // Run 3 times for median
settings: {
preset: 'desktop',
chromeFlags: '--no-sandbox --headless',
onlyCategories: ['performance', 'accessibility', 'best-practices', 'seo'],
},
},
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.9 }],
'categories:accessibility': ['error', { minScore: 0.9 }],
'categories:best-practices': ['error', { minScore: 0.9 }],
'categories:seo': ['error', { minScore: 0.9 }],
'largest-contentful-paint': ['warn', { maxNumericValue: 2500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
'total-blocking-time': ['warn', { maxNumericValue: 200 }],
'first-contentful-paint': ['warn', { maxNumericValue: 1800 }],
},
},
upload: {
target: 'temporary-public-storage',
// Or self-hosted: target: 'lhci', serverBaseUrl: 'https://lhci.example.com'
},
},
};
Integración con GitHub Actions
Ejecuta Lighthouse CI en GitHub Actions con reporte de scores como comentarios en PRs. El pipeline sirve el sitio localmente, corre auditorías y publica resultados.
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Serve site
run: npx serve -s . -l 8080 &
- name: Wait for server
run: npx wait-on http://localhost:8080
- name: Run Lighthouse CI
run: |
npm install -g @lhci/[email protected]
lhci autorun
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
- name: Upload Lighthouse results
uses: actions/upload-artifact@v4
if: always()
with:
name: lighthouse-results
path: .lighthouseci/
Integración con GitLab CI
Para GitLab, Lighthouse CI corre en un contenedor Docker con Chrome. Los resultados se guardan como artifacts y pueden mostrarse en widgets de merge requests.
# .gitlab-ci.yml
lighthouse:
stage: test
image: node:20-slim
before_script:
- apt-get update && apt-get install -y chromium
- npm install -g @lhci/[email protected] serve wait-on
- export CHROME_PATH=$(which chromium)
script:
- serve -s . -l 8080 &
- wait-on http://localhost:8080
- lhci autorun --config=lighthouserc.js
artifacts:
paths:
- .lighthouseci/
reports:
performance: .lighthouseci/lhr-*.json
only:
- merge_requests
- main
7. Uso Programático (API Node.js)
Automatización Custom de Lighthouse
La API Node.js de Lighthouse permite construir herramientas de auditoría custom, dashboards y sistemas de monitoreo. Controlas el lanzamiento de Chrome, configuración de auditoría y procesamiento de resultados programáticamente.
import lighthouse from 'lighthouse';
import * as chromeLauncher from 'chrome-launcher';
import { writeFileSync } from 'fs';
async function auditPage(url) {
const chrome = await chromeLauncher.launch({
chromeFlags: ['--headless', '--no-sandbox'],
});
const result = await lighthouse(url, {
port: chrome.port,
output: ['json', 'html'],
onlyCategories: ['performance', 'accessibility', 'best-practices', 'seo'],
settings: {
formFactor: 'desktop',
screenEmulation: { disabled: true },
throttling: {
rttMs: 40,
throughputKbps: 10240,
cpuSlowdownMultiplier: 1,
},
},
});
await chrome.kill();
const scores = {
url,
timestamp: new Date().toISOString(),
performance: result.lhr.categories.performance.score * 100,
accessibility: result.lhr.categories.accessibility.score * 100,
bestPractices: result.lhr.categories['best-practices'].score * 100,
seo: result.lhr.categories.seo.score * 100,
metrics: {
fcp: result.lhr.audits['first-contentful-paint'].numericValue,
lcp: result.lhr.audits['largest-contentful-paint'].numericValue,
tbt: result.lhr.audits['total-blocking-time'].numericValue,
cls: result.lhr.audits['cumulative-layout-shift'].numericValue,
si: result.lhr.audits['speed-index'].numericValue,
},
};
writeFileSync(`report-${Date.now()}.html`, result.report[1]);
return scores;
}
// Audit multiple pages
const urls = [
'https://josenobile.co/',
'https://josenobile.co/health/',
'https://josenobile.co/contact/',
];
const results = await Promise.all(urls.map(auditPage));
console.table(results.map(r => ({
url: r.url,
perf: r.performance,
a11y: r.accessibility,
bp: r.bestPractices,
seo: r.seo,
})));
8. Presupuestos de Rendimiento (Tamaño y Tiempos)
Definir y Aplicar Presupuestos
Los presupuestos de rendimiento establecen límites en peso de página (presupuestos de tamaño), conteos de recursos y valores de métricas (presupuestos de tiempos). Lighthouse CI aplica estos presupuestos en CI/CD, haciendo fallar builds que excedan los límites. Los presupuestos previenen regresiones de rendimiento a medida que se agregan funcionalidades.
// budget.json - Lighthouse performance budget
[
{
"path": "/*",
"timings": [
{ "metric": "interactive", "budget": 3000 },
{ "metric": "first-contentful-paint", "budget": 1500 },
{ "metric": "largest-contentful-paint", "budget": 2500 }
],
"resourceSizes": [
{ "resourceType": "total", "budget": 300 },
{ "resourceType": "script", "budget": 100 },
{ "resourceType": "stylesheet", "budget": 30 },
{ "resourceType": "image", "budget": 150 },
{ "resourceType": "font", "budget": 50 },
{ "resourceType": "document", "budget": 30 }
],
"resourceCounts": [
{ "resourceType": "total", "budget": 30 },
{ "resourceType": "script", "budget": 5 },
{ "resourceType": "stylesheet", "budget": 2 },
{ "resourceType": "image", "budget": 15 },
{ "resourceType": "font", "budget": 3 }
]
}
]
// lighthouserc.js with budget enforcement
module.exports = {
ci: {
collect: { /* ... */ },
assert: {
budgetsFile: 'budget.json',
assertions: {
'resource-summary:script:size': ['error', { maxNumericValue: 102400 }],
'resource-summary:total:size': ['warn', { maxNumericValue: 307200 }],
},
},
},
};
Dashboard de Monitoreo Continuo
Rastrea scores de Lighthouse en el tiempo con un dashboard de monitoreo. Almacena resultados en una base de datos o usa Lighthouse CI Server para rastreo histórico y comparación integrados.
#!/bin/bash
# proof.sh - Lighthouse audit script with score tracking
set -euo pipefail
URLS=("/" "/health/" "/contact/")
BASE="http://localhost:8080"
REPORT_DIR="./lighthouse-reports"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p "$REPORT_DIR"
for path in "${URLS[@]}"; do
slug=$(echo "$path" | tr '/' '-' | sed 's/^-//;s/-$//')
[ -z "$slug" ] && slug="home"
echo "Auditing ${BASE}${path}..."
lighthouse "${BASE}${path}" \
--output=json,html \
--output-path="$REPORT_DIR/${slug}_${TIMESTAMP}" \
--chrome-flags="--headless --no-sandbox" \
--preset=desktop \
--quiet
# Extract scores
PERF=$(jq '.categories.performance.score * 100' "$REPORT_DIR/${slug}_${TIMESTAMP}.report.json")
A11Y=$(jq '.categories.accessibility.score * 100' "$REPORT_DIR/${slug}_${TIMESTAMP}.report.json")
BP=$(jq '.categories["best-practices"].score * 100' "$REPORT_DIR/${slug}_${TIMESTAMP}.report.json")
SEO=$(jq '.categories.seo.score * 100' "$REPORT_DIR/${slug}_${TIMESTAMP}.report.json")
echo " Perf: $PERF | A11y: $A11Y | BP: $BP | SEO: $SEO"
# Fail if any score below 90
for score in $PERF $A11Y $BP $SEO; do
if (( $(echo "$score < 90" | bc -l) )); then
echo "FAIL: Score $score below threshold 90"
exit 1
fi
done
done
echo "All audits passed."
9. Flujos de Usuario y Modo Timespan
Modos de Navegación, Timespan y Snapshot
Los flujos de usuario de Lighthouse capturan rendimiento a lo largo de interacciones multi-paso, no solo cargas de página en frío. Hay tres modos: Navigation (carga en frío por defecto), Timespan (mide un rango de tiempo de interacción del usuario) y Snapshot (audita la página en su estado actual sin navegación). Juntos, estos modos cubren el recorrido completo del usuario.
import { startFlow } from 'lighthouse';
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
// Start a Lighthouse user flow
const flow = await startFlow(page, { name: 'Checkout Flow' });
// Step 1: Navigation mode (cold load)
await flow.navigate('https://shop.example.com/');
// Step 2: Timespan mode (measure interactions over time)
await flow.startTimespan({ stepName: 'Browse products' });
await page.click('.product-card:first-child');
await page.waitForSelector('.product-detail');
await page.click('#add-to-cart');
await page.waitForSelector('.cart-badge');
await flow.endTimespan();
// Step 3: Another navigation
await flow.navigate('https://shop.example.com/cart', {
stepName: 'Navigate to cart',
});
// Step 4: Snapshot mode (audit current DOM state)
await flow.snapshot({ stepName: 'Cart page state' });
// Step 5: Timespan for checkout interaction
await flow.startTimespan({ stepName: 'Complete checkout' });
await page.click('#checkout-btn');
await page.waitForSelector('#payment-form');
await page.type('#card-number', '4242424242424242');
await page.type('#card-expiry', '12/28');
await page.type('#card-cvc', '123');
await page.click('#submit-payment');
await page.waitForSelector('.confirmation');
await flow.endTimespan();
// Generate the flow report
const report = await flow.generateReport();
writeFileSync('flow-report.html', report);
// Access individual step results
const flowResult = await flow.createFlowResult();
for (const step of flowResult.steps) {
console.log(`${step.name}: ${step.lhr.categories.performance.score * 100}`);
}
await browser.close();
Profundización en Modo Timespan
El modo Timespan mide CLS e INP durante interacciones reales del usuario, algo que el modo de navegación en frío no puede capturar. Es ideal para aplicaciones de página única donde los cambios de ruta ocurren del lado del cliente, comportamiento de scroll infinito e interacciones que disparan actualizaciones pesadas del DOM. El modo Timespan recopila métricas TBT, CLS e INP del período medido.
import { startFlow } from 'lighthouse';
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://josenobile.co/');
const flow = await startFlow(page, { name: 'SPA Interactions' });
// Measure CLS and INP during SPA navigation
await flow.startTimespan({ stepName: 'Language switch interaction' });
// Simulate user switching language
await page.select('#lang', 'es-CO');
await page.waitForTimeout(500);
// Simulate scrolling (can cause CLS)
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
await page.waitForTimeout(1000);
await flow.endTimespan();
// Timespan results include:
// - CLS accumulated during the timespan
// - TBT (Total Blocking Time) during the timespan
// - INP (if interactions occurred)
// - Layout shift events with affected elements
const result = await flow.createFlowResult();
const timespanStep = result.steps[0];
const cls = timespanStep.lhr.audits['cumulative-layout-shift'];
const tbt = timespanStep.lhr.audits['total-blocking-time'];
console.log(`CLS during interaction: ${cls.numericValue}`);
console.log(`TBT during interaction: ${tbt.numericValue}ms`);
await browser.close();
10. Chrome DevTools Lighthouse
Ejecutar Lighthouse en DevTools
Chrome DevTools incluye un panel Lighthouse integrado para ejecutar auditorías directamente en el navegador. Abre DevTools (F12), navega a la pestaña Lighthouse, selecciona categorías y tipo de dispositivo, y haz clic en "Analyze page load." Los resultados aparecen inline con detalles de auditoría expandibles, capturas de filmstrip y visualizaciones treemap. DevTools Lighthouse usa el mismo motor que el CLI pero corre dentro del proceso del navegador.
# Running Lighthouse from Chrome DevTools:
#
# 1. Open Chrome DevTools (F12 or Cmd+Opt+I)
# 2. Navigate to the "Lighthouse" tab
# 3. Select categories: Performance, Accessibility, Best Practices, SEO
# 4. Choose device: Mobile or Desktop
# 5. Click "Analyze page load"
#
# DevTools Lighthouse features:
# - View Treemap: visualize JavaScript bundle sizes
# - View Trace: open in Performance panel for detailed waterfall
# - Filmstrip: screenshot timeline of page load
# - Expandable audits with affected elements highlighted
# - "View Original Trace" button opens Performance panel
#
# Tips for accurate DevTools results:
# - Use Incognito mode (no extensions interfering)
# - Close other tabs (reduces CPU contention)
# - Disable browser extensions
# - Use a consistent network (or enable throttling)
# - Run multiple times and compare (results vary 5-10%)
#
# DevTools also provides real-time CWV overlay:
# 1. Open DevTools > Performance panel
# 2. Check "Web Vitals" in the timeline
# 3. Interact with the page to see INP measurements
# 4. Layout shifts appear as red markers in the timeline
#
# Lighthouse flags available in DevTools:
# --throttling-method=devtools (uses DevTools throttling)
# --screenEmulation.disabled (use actual viewport)
# --formFactor=desktop (desktop scoring)
11. API de PageSpeed Insights
Usando la API de PageSpeed Insights
La API de PageSpeed Insights (PSI) combina datos de laboratorio de Lighthouse con datos de campo del Chrome User Experience Report (CrUX). Provee tanto scores de laboratorio (lo que Lighthouse mide en un entorno controlado) como datos de campo (rendimiento real de usuarios reales de Chrome). La API es gratuita, requiere una clave API y retorna resultados JSON para cualquier URL pública.
// PageSpeed Insights API - fetch lab + field data
const API_KEY = process.env.PSI_API_KEY;
async function fetchPSI(url, strategy = 'desktop') {
const endpoint = 'https://www.googleapis.com/pagespeedonline/v5/runPagespeed';
const params = new URLSearchParams({
url,
key: API_KEY,
strategy, // 'mobile' or 'desktop'
category: ['performance', 'accessibility', 'best-practices', 'seo'],
});
const res = await fetch(`${endpoint}?${params}`);
const data = await res.json();
// Lab data (Lighthouse)
const lab = data.lighthouseResult;
console.log('Lab scores:');
console.log(` Performance: ${lab.categories.performance.score * 100}`);
console.log(` Accessibility: ${lab.categories.accessibility.score * 100}`);
console.log(` Best Practices: ${lab.categories['best-practices'].score * 100}`);
console.log(` SEO: ${lab.categories.seo.score * 100}`);
// Field data (CrUX) - real user metrics
const field = data.loadingExperience;
if (field && field.metrics) {
console.log('\nField data (CrUX):');
const lcp = field.metrics.LARGEST_CONTENTFUL_PAINT_MS;
const inp = field.metrics.INTERACTION_TO_NEXT_PAINT;
const cls = field.metrics.CUMULATIVE_LAYOUT_SHIFT_SCORE;
if (lcp) console.log(` LCP p75: ${lcp.percentile}ms (${lcp.category})`);
if (inp) console.log(` INP p75: ${inp.percentile}ms (${inp.category})`);
if (cls) console.log(` CLS p75: ${cls.percentile / 100} (${cls.category})`);
} else {
console.log('\nNo field data available (not enough CrUX traffic).');
}
return data;
}
// Monitor multiple pages
const pages = [
'https://josenobile.co/',
'https://josenobile.co/health/',
];
for (const url of pages) {
console.log(`\n--- ${url} ---`);
await fetchPSI(url, 'desktop');
await fetchPSI(url, 'mobile');
}
API PSI en Monitoreo CI/CD
Integra la API de PageSpeed Insights en jobs CI/CD programados para monitorear el rendimiento de producción sin correr tu propia infraestructura de Lighthouse. PSI testea la URL de producción en vivo, proveyendo tanto datos de laboratorio como de campo de usuarios reales. Esto complementa Lighthouse CI local al detectar problemas que solo aparecen en producción (configuración de CDN, impacto de scripts de terceros, latencia geográfica).
# .github/workflows/psi-monitor.yml
name: PageSpeed Insights Monitor
on:
schedule:
- cron: '0 6 * * 1' # Weekly on Monday at 6 AM UTC
workflow_dispatch:
jobs:
psi-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run PSI checks
run: |
for url in "https://josenobile.co/" "https://josenobile.co/health/"; do
echo "Checking $url..."
RESULT=$(curl -s "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=$url&strategy=desktop&key=${{ secrets.PSI_API_KEY }}")
PERF=$(echo "$RESULT" | jq '.lighthouseResult.categories.performance.score * 100')
echo " Performance: $PERF"
if (( $(echo "$PERF < 90" | bc -l) )); then
echo "::error::Performance score $PERF below 90 for $url"
exit 1
fi
done
- name: Store results
if: always()
run: |
mkdir -p psi-results
date +%Y-%m-%d > psi-results/timestamp.txt
12. Lighthouse 13: Auditorías Basadas en Insights (2025-2026)
Lighthouse 13.4 y la Categoría de Navegación Agéntica
Lighthouse 13.4.1 (julio de 2026) viene incluido en Chrome 152 DevTools. Lighthouse 13 migró hacia auditorías basadas en insights: muchas auditorías no-scored fueron consolidadas en insights unificados -- por ejemplo, las auditorías layout-shifts, non-composited-animations y unsized-images ahora están combinadas en una sola auditoría cls-culprits-insight. La línea 13.x sigue agregando superficies de auditoría: 13.1 introdujo una auditoría de compatibilidad Baseline, y 13.2-13.3 agregaron una nueva categoría de navegación agéntica a la configuración por defecto con auditorías WebMCP (webmcp-registered-tools, webmcp-schema-validity, webmcp-form-coverage) y una validación de llms.txt para agentes AI. Los scores de rendimiento no cambian -- estas actualizaciones apuntan a la estructura de auditorías no-scored, por lo que los usuarios de API deben esperar diferencias estructurales en los outputs de reportes ya que los nombres de auditorías antiguos se retiran.
INP como Core Web Vital
Interaction to Next Paint (INP) ha reemplazado completamente a First Input Delay (FID) como el Core Web Vital de responsividad. INP mide la latencia de todas las interacciones del usuario durante el ciclo de vida de la página, no solo la primera. El umbral es menos de 200ms para un score "bueno". Lighthouse mide INP en modo Timespan durante interacciones reales del usuario. Optimizar INP requiere reducir el tiempo de bloqueo del hilo principal, dividir tareas largas y ceder al navegador entre manejadores de eventos. Usa scheduler.yield() o setTimeout(0) para dividir tareas largas.
Pesos de Scoring de Rendimiento: Estables Desde Lighthouse 10
Los pesos de scoring de rendimiento de Lighthouse han sido estables desde Lighthouse 10 (febrero de 2023) y permanecen sin cambios en Lighthouse 13. Los pesos actuales son: Total Blocking Time (TBT) al 30% (proxy de laboratorio para INP), Largest Contentful Paint (LCP) al 25%, Cumulative Layout Shift (CLS) al 25%, First Contentful Paint (FCP) al 10%, y Speed Index (SI) al 10%. El último cambio de pesos llegó en Lighthouse 10, que eliminó la auditoría obsoleta Time to Interactive (TTI) y trasladó su peso a CLS (subiendo CLS del 15% al 25%). Los cambios de Lighthouse 13 son estructurales — auditorías basadas en insights y nuevas categorías no puntuadas — no ajustes a estos pesos.
Para alineación con medición de campo, los equipos deberían adoptar web-vitals v4+, que provee la API onINP() para medición directa de Interaction to Next Paint en producción. La librería también agrega builds de attribution que identifican el elemento exacto y evento responsable de scores INP pobres. Combinar datos de campo de web-vitals v4 con scores de laboratorio de Lighthouse da la imagen más completa del rendimiento real del usuario -- los scores de lab detectan regresiones en CI, los datos de campo validan que las optimizaciones se traduzcan en mejoras reales.