Integrations

unlighthouse-ci: Bulk Lighthouse CI for Entire Sites

Run unlighthouse-ci in your pipeline

The unlighthouse-ci binary runs Lighthouse on every page of your site and fails your CI build if any score drops below a budget:

npm install -g @unlighthouse/cli puppeteer
unlighthouse-ci --site https://staging.example.com --budget 80

Exit code 1 = budget failed. Exit code 0 = all pages passed. That's the entire contract. Wire this single command into GitHub Actions, GitLab CI, CircleCI, or any pipeline that runs bash.

Why Unlighthouse CI?

Google LHCIUnlighthouse CI
SetupComplex config, URL manifestOne command
PagesManual listAuto-discovers entire site
BudgetsPer-page configSingle threshold for all pages
ReportsJSON/HTMLInteractive dashboard, JSON, CSV

Basic Usage

# Scan site, fail if any page < 75
unlighthouse-ci --site example.com --budget 75

# Generate static HTML report
unlighthouse-ci --site example.com --build-static

# Both: budget check + report
unlighthouse-ci --site example.com --budget 75 --build-static

Already Using LHCI Server?

Keep your existing infrastructure—Unlighthouse uploads to LHCI servers:

unlighthouse-ci --site example.com \
  --reporter lighthouseServer \
  --lhci-host https://lhci.yourcompany.com \
  --lhci-build-token $LHCI_TOKEN

Installation for CI

CI environments need Chrome. Install puppeteer alongside the CLI:

npm install -g @unlighthouse/cli puppeteer

Puppeteer downloads a compatible Chromium binary automatically.

Performance Budgets

Simple: One Number

# Fail if ANY category on ANY page < 75
unlighthouse-ci --site example.com --budget 75

Per-Category Budgets

More control in your config:

// unlighthouse.config.ts
export default defineUnlighthouseConfig({
  site: 'https://example.com',
  ci: {
    budget: {
      'performance': 70, // Performance can be lower
      'accessibility': 95, // Accessibility must be high
      'best-practices': 80,
      'seo': 90,
    },
  },
})

Run with just:

unlighthouse-ci

Report Formats

FormatUse CaseFlag
jsonSimple scores for CI parsing--reporter json
jsonExpandedFull metrics breakdown--reporter jsonExpanded
csvSpreadsheet analysis--reporter csv
csvExpandedFull data in CSV--reporter csvExpanded
lighthouseServerUpload to LHCI server--reporter lighthouseServer
# Generate CSV for stakeholders
unlighthouse-ci --site example.com --reporter csvExpanded

Static Reports

Generate a shareable HTML dashboard:

unlighthouse-ci --site example.com --build-static

Output goes to .unlighthouse/. Upload that folder to any static host.

Live examples:

Configuration

Configuring the CLI can be done either through the CI arguments or through a config file.

CI Options

Options
-v, --versionDisplay version number.
--site <url>Host URL to scan.
--root <path>Define the project root. Useful for changing where the config is read from or setting up sampling.
--config-file <path>Path to config file.
--output-path <path>Path to save the contents of the client and reports to.
--budget <budget>Budget (1-100), the minimum score which can pass.
--reporter <reporter>The report to generate from results. Options: csv, csvExpanded, json, jsonExpanded, lighthouseServer or false. Default: jsonSimple.
--lhci-host <lhci-host>URL of your LHCI server.
--lhci-build-token <lhci-build-token>LHCI build token, used to add data.
--lhci-auth <lhci-auth>Basic auth for your LHCI server.
--build-staticBuild a static website for the reports which can be uploaded.
--cacheEnable the caching.
--no-cacheDisable the caching.
--desktopSimulate device as desktop.
--mobileSimulate device as mobile.
--user-agent <user-agent>Specify a top-level user agent all requests will use.
--router-prefix <path>The URL path prefix for the client and API to run from.
--throttleEnable the throttling.
--samples <samples>Specify the amount of samples to run.
--sitemaps <sitemaps>Comma separated list of sitemaps to use for scanning. Providing these will override any in robots.txt.
--urls <urls>Specify explicit relative paths to scan as a comma-separated list, disabling the link crawler.
--exclude-urls <urls>Relative paths (string or regex) to exclude as a comma-separated list.
--include-urls <urls>Relative paths (string or regex) to include as a comma-separated list.
--enable-javascriptWhen inspecting the HTML wait for the javascript to execute. Useful for SPAs.
--disable-javascriptWhen inspecting the HTML, don't wait for the javascript to execute.
--enable-i18n-pagesEnable scanning pages which use x-default.
--disable-i18n-pagesDisable scanning pages which use x-default.
--disable-robots-txtDisables the robots.txt crawling.
--disable-sitemapDisables the sitemap.xml crawling.
--disable-dynamic-samplingDisables the sampling of paths.
--extra-headers <headers>Extra headers to send with the request. Example: --extra-headers foo=bar,bar=foo
--cookies <cookies>Cookies to send with the request. Example: --cookies foo=bar;bar=foo
--auth <auth>Basic auth to send with the request. Example: --auth username:password
--default-query-params <params>Default query params to send with the request. Example: --default-query-params foo=bar,bar=foo
-d, --debugDebug. Enable debugging in the logger.
-h, --helpDisplay available CLI options

Config File

If you want to configure Unlighthouse, you can create a unlighthouse.config.ts file in your cwd.

import { defineUnlighthouseConfig } from 'unlighthouse/config'

export default defineUnlighthouseConfig({
  site: 'example.com',
  debug: true,
  scanner: {
    device: 'desktop',
  },
})

See the Configuration section for more details and the guides.

GitHub Actions & Netlify Example

This example is for GitHub Actions and deploys a static client build to Netlify.

name: Assertions and static report

on:
  workflow_dispatch:

jobs:
  demo:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Install Dependencies
        run: npm install -g @unlighthouse/cli puppeteer netlify-cli

      - name: Unlighthouse assertions and client
        run: unlighthouse-ci --site <your-site> --budget 75 --build-static

      - name: Deploy
        run: netlify deploy --dir=.unlighthouse --prod --message="New Release Deploy from GitHub Actions"
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

GitLab CI Example

# .gitlab-ci.yml
lighthouse-audit:
  image: node:20
  script:
    - npm install -g @unlighthouse/cli puppeteer
    - unlighthouse-ci --site $SITE_URL --budget 75
  artifacts:
    paths:
      - .unlighthouse/
    expire_in: 1 week

CircleCI Example

# .circleci/config.yml
version: 2.1
jobs:
  lighthouse:
    docker:
      - image: cimg/node:20.0-browsers
    steps:
      - checkout
      - run: npm install -g @unlighthouse/cli
      - run: unlighthouse-ci --site $SITE_URL --budget 75 --build-static
      - store_artifacts:
          path: .unlighthouse
Did this page help you?
Anything that could be done better? :)
Help us improve this page. You can edit this page on GitHub or provide anonymous feedback below.
block first paint. Large CSS files - Browser must parse all CSS before rendering any content. Web font loading - Text may be invisible until fonts download if using font-display: block. Too many redirects - Each redirect adds network round-trips before content can load.",{"id":3260,"title":3261,"titles":3262,"content":3263,"level":1756},"/glossary/fcp#how-to-measure-fcp","How to Measure FCP",[3231],"Use Unlighthouse to measure FCP across your entire site. For individual pages: Chrome DevTools Performance panelLighthouse in ChromePageSpeed InsightsWeb Vitals Chrome extension",{"id":3265,"title":3221,"titles":3266,"content":3267,"level":1828},"/glossary/fcp#measure-in-browser",[3231,3261],"Run this in your browser console to see FCP timing. type Rating = 'good' | 'needs-improvement' | 'poor'\n\nfunction rateValue(ms: number): Rating {\n return ms <= 1800 ? 'good' : ms <= 3000 ? 'needs-improvement' : 'poor'\n}\n\nconst observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.name === 'first-contentful-paint') {\n const rating = rateValue(entry.startTime)\n console.log(`FCP: ${(entry.startTime / 1000).toFixed(2)}s (${rating})`)\n }\n }\n})\n\nobserver.observe({ type: 'paint', buffered: true })",{"id":3269,"title":3270,"titles":3271,"content":3272,"level":1756},"/glossary/fcp#improving-fcp","Improving FCP",[3231],"Key optimization strategies: Reduce server response time - Optimize TTFB with caching and CDNsEliminate render-blocking resources - Defer non-critical CSS/JS, inline critical CSSMinify CSS - Remove unused styles and compress what remainsPreconnect to origins - Use for third-party domainsAvoid redirects - Each redirect adds latencyOptimize font loading - Use font-display: swap or optional FCP is a Lighthouse lab metric, not a Core Web Vital. However, improving FCP typically improves LCP, which is a Core Web Vital and ranking factor. html pre.shiki code .swqme, html code.shiki .swqme{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#C792EA}html pre.shiki code .sryBE, html code.shiki .sryBE{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#FFCB6B}html pre.shiki code .sc1V3, html code.shiki .sc1V3{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#89DDFF}html pre.shiki code .sbw7o, html code.shiki .sbw7o{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#89DDFF}html pre.shiki code .sJnJ8, html code.shiki .sJnJ8{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#C3E88D}html pre.shiki code .s0YkB, html code.shiki .s0YkB{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#82AAFF}html pre.shiki code .sx-uw, html code.shiki .sx-uw{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#89DDFF}html pre.shiki code .sgUNn, html code.shiki .sgUNn{--shiki-light:#E36209;--shiki-light-font-style:inherit;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s9nlO, html code.shiki .s9nlO{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FFCB6B}html pre.shiki code .smL2f, html code.shiki .smL2f{--shiki-light:#D73A49;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sqjlB, html code.shiki .sqjlB{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#BABED8}html pre.shiki code .sjz_z, html code.shiki .sjz_z{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#F78C6C}html pre.shiki code .smpaK, html code.shiki .smpaK{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#BABED8}html pre.shiki code .sqVJQ, html code.shiki .sqVJQ{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#F07178}html pre.shiki code .s4OlC, html code.shiki .s4OlC{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#BABED8}html pre.shiki code .sGFTI, html code.shiki .sGFTI{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":3274,"title":3275,"titles":3276,"content":3277,"level":1766},"/glossary","Core Web Vitals Guide",[],"Complete guide to Core Web Vitals and Lighthouse metrics. Learn what LCP, CLS, and INP measure, their impact on SEO, and how to improve them. Core Web Vitals are Google's key metrics for user experience and are a direct ranking factor in search results. Understanding and optimizing these metrics improves both SEO and user experience.",{"id":3279,"title":3280,"titles":3281,"content":3282,"level":1756},"/glossary#core-web-vitals","Core Web Vitals",[3275],"Google's three key metrics that affect search rankings: Largest Contentful Paint - Measures loading performance. How quickly does the main content appear?Cumulative Layout Shift - Measures visual stability. Does content jump around unexpectedly?Interaction to Next Paint - Measures responsiveness. How quickly does the page respond to clicks?",{"id":3284,"title":3285,"titles":3286,"content":3287,"level":1756},"/glossary#lighthouse-performance-metrics","Lighthouse Performance Metrics",[3275],"Additional metrics reported by Lighthouse that contribute to your performance score: First Contentful Paint - When the first content renders. Is anything happening?Time to First Byte - Server response time. How fast is your backend?Total Blocking Time - Main thread blocking during load. 30% of Lighthouse score.Speed Index - Visual loading progress. How quickly does content fill the viewport?",{"id":3289,"title":3290,"titles":3291,"content":3292,"level":1828},"/glossary#lighthouse-score-weights","Lighthouse Score Weights",[3275,3285],"MetricWeightTypeTBT30%LabLCP25%Core Web VitalCLS25%Core Web VitalFCP10%LabSpeed Index10%Lab",{"id":3294,"title":3295,"titles":3296,"content":3297,"level":1828},"/glossary#deprecated-metrics","Deprecated Metrics",[3275,3285],"TTI (Time to Interactive) - Removed in Lighthouse 10. Use TBT or INP instead.",{"id":3299,"title":3300,"titles":3301,"content":3302,"level":1756},"/glossary#core-web-vitals-and-seo","Core Web Vitals and SEO",[3275],"Since 2021, Core Web Vitals have been a Google ranking factor. Sites with good Core Web Vitals may rank higher in search results and appear in Google's \"Top Stories\" carousel. Google measures Core Web Vitals from real user data (Chrome User Experience Report). Improving these metrics: Boosts search rankingsImproves user engagementReduces bounce ratesIncreases conversions",{"id":3304,"title":3305,"titles":3306,"content":3307,"level":1756},"/glossary#measuring-your-site","Measuring Your Site",[3275],"Use Unlighthouse CLI to audit all these metrics across your entire website in a single scan: npx unlighthouse --site https://example.com Unlike single-page tools like PageSpeed Insights, Unlighthouse scans your entire site and identifies which pages need the most attention. html pre.shiki code .sryBE, html code.shiki .sryBE{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#FFCB6B}html pre.shiki code .sJnJ8, html code.shiki .sJnJ8{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#C3E88D}html pre.shiki code .sJFDI, html code.shiki .sJFDI{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":3309,"title":3310,"titles":3311,"content":3312,"level":1766},"/glossary/inp","What is Interaction to Next Paint (INP)?",[],"Learn what Interaction to Next Paint means, why it replaced FID as a Core Web Vital, and how to improve your site's responsiveness. Interaction to Next Paint measures how quickly your page responds to user interactions. It replaced First Input Delay (FID) as a Core Web Vital in March 2024 and is now a Google ranking factor.",{"id":3314,"title":3315,"titles":3316,"content":3317,"level":1756},"/glossary/inp#what-inp-measures","What INP Measures",[3310],"INP tracks the latency of all clicks, taps, and keyboard interactions throughout a page's lifecycle, then reports a value representative of the overall experience (typically the worst interaction, with some outlier handling). The measurement includes: Input delay - Time from interaction to event handler startProcessing time - Time to run event handlersPresentation delay - Time to render the next frame",{"id":3319,"title":3320,"titles":3321,"content":3322,"level":1756},"/glossary/inp#inp-score-thresholds","INP Score Thresholds",[3310],"ScoreRating≤ 200msGood200ms - 500msNeeds Improvement> 500msPoor Google recommends an INP of 200 milliseconds or less for at least 75% of page visits.",{"id":3324,"title":3325,"titles":3326,"content":3327,"level":1756},"/glossary/inp#inp-vs-fid","INP vs FID",[3310],"FID only measured the first interaction's input delay—ignoring processing and presentation time entirely. A page could have great FID but terrible responsiveness afterward. INP is more comprehensive: Measures all interactions, not just the firstIncludes the full interaction lifecycleBetter represents actual user experience",{"id":3329,"title":3330,"titles":3331,"content":3332,"level":1756},"/glossary/inp#why-inp-matters","Why INP Matters",[3310],"Users expect instant feedback. When they click a button and nothing happens for 500ms, they assume it's broken and click again—or leave. Good INP means: Responsive, fluid interactionsUsers trust the interface worksLower frustration and abandonmentBetter search rankings",{"id":3334,"title":3335,"titles":3336,"content":3337,"level":1756},"/glossary/inp#common-inp-issues","Common INP Issues",[3310],"Long JavaScript tasks - Any task over 50ms blocks the main thread and delays interactions. Heavy event handlers - Click handlers that do too much work before updating the UI. Hydration delays - SPAs that look interactive but aren't until JavaScript loads. Third-party scripts - Analytics, ads, and widgets competing for main thread time. Large DOM size - More elements mean slower style recalculation and layout.",{"id":3339,"title":3340,"titles":3341,"content":3342,"level":1756},"/glossary/inp#how-to-measure-inp","How to Measure INP",[3310],"Unlighthouse reports responsiveness metrics across your site. For INP specifically, you need field data since it measures real user interactions. Measurement tools: Chrome User Experience Report (CrUX) - Real user dataWeb Vitals Chrome extension - Your own interactionsPageSpeed Insights - Field data sectionPerformance panel in DevTools - Interaction traces",{"id":3344,"title":3221,"titles":3345,"content":3346,"level":1828},"/glossary/inp#measure-in-browser",[3310,3340],"Run this in your browser console to track INP as you interact with the page. type Rating = 'good' | 'needs-improvement' | 'poor'\n\nfunction rateValue(ms: number): Rating {\n return ms <= 200 ? 'good' : ms <= 500 ? 'needs-improvement' : 'poor'\n}\n\nlet worstInp = 0\n\nconst observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries() as (PerformanceEntry & {\n duration: number\n interactionId: number\n name: string\n })[]) {\n // Only track actual interactions (has interactionId)\n if (!entry.interactionId)\n continue\n\n if (entry.duration > worstInp) {\n worstInp = entry.duration\n const rating = rateValue(worstInp)\n console.log(`INP: ${worstInp}ms (${rating}) - ${entry.name}`)\n }\n }\n})\n\nobserver.observe({ type: 'event', buffered: true, durationThreshold: 16 })\n\nconsole.log('INP tracking active. Interact with the page to measure.') Lab tools like Lighthouse can't fully measure INP because it requires real user interactions over time. Use field data for accurate INP scores.",{"id":3348,"title":3349,"titles":3350,"content":3351,"level":1756},"/glossary/inp#improving-inp","Improving INP",[3310],"Key optimization strategies: Break up long tasks - Use setTimeout or scheduler.yield() to yield to the main threadDefer non-critical work - Move analytics and non-essential code out of interaction handlersUse web workers - Offload heavy computation off the main threadOptimize event handlers - Do the minimum work needed, then update UIReduce DOM size - Fewer elements mean faster renderingDebounce rapid interactions - Avoid processing every keystroke // Yield to main thread during long tasks\nasync function processItems(items) {\n for (const item of items) {\n process(item)\n // Let browser handle pending interactions\n await scheduler.yield()\n }\n} html pre.shiki code .swqme, html code.shiki .swqme{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#C792EA}html pre.shiki code .sryBE, html code.shiki .sryBE{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#FFCB6B}html pre.shiki code .sc1V3, html code.shiki .sc1V3{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#89DDFF}html pre.shiki code .sbw7o, html code.shiki .sbw7o{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#89DDFF}html pre.shiki code .sJnJ8, html code.shiki .sJnJ8{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#C3E88D}html pre.shiki code .s0YkB, html code.shiki .s0YkB{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#82AAFF}html pre.shiki code .sx-uw, html code.shiki .sx-uw{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#89DDFF}html pre.shiki code .sgUNn, html code.shiki .sgUNn{--shiki-light:#E36209;--shiki-light-font-style:inherit;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s9nlO, html code.shiki .s9nlO{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FFCB6B}html pre.shiki code .smL2f, html code.shiki .smL2f{--shiki-light:#D73A49;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sqjlB, html code.shiki .sqjlB{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#BABED8}html pre.shiki code .sjz_z, html code.shiki .sjz_z{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#F78C6C}html pre.shiki code .smpaK, html code.shiki .smpaK{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#BABED8}html pre.shiki code .sqVJQ, html code.shiki .sqVJQ{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#F07178}html pre.shiki code .sWpk2, html code.shiki .sWpk2{--shiki-light:#E36209;--shiki-default:#E36209;--shiki-dark:#F07178}html pre.shiki code .sTBSN, html code.shiki .sTBSN{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sGFTI, html code.shiki .sGFTI{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":3353,"title":3354,"titles":3355,"content":3356,"level":1766},"/glossary/lcp","What is Largest Contentful Paint (LCP)?",[],"Learn what Largest Contentful Paint means, why it matters for Core Web Vitals, and how to measure and improve LCP scores. Largest Contentful Paint measures how long it takes for the largest visible content element to render on screen. It's one of Google's three Core Web Vitals and directly impacts your search rankings.",{"id":3358,"title":3359,"titles":3360,"content":3361,"level":1756},"/glossary/lcp#what-lcp-measures","What LCP Measures",[3354],"LCP tracks the render time of the largest image, video, or text block visible in the viewport. Common LCP elements include: Hero imagesFeatured video thumbnailsLarge heading text blocksAbove-the-fold content images The metric starts when the page begins loading and ends when the largest element finishes rendering.",{"id":3363,"title":3364,"titles":3365,"content":3366,"level":1756},"/glossary/lcp#lcp-score-thresholds","LCP Score Thresholds",[3354],"ScoreRating≤ 2.5sGood2.5s - 4.0sNeeds Improvement> 4.0sPoor Google recommends achieving an LCP of 2.5 seconds or less for at least 75% of page visits.",{"id":3368,"title":3369,"titles":3370,"content":3371,"level":1756},"/glossary/lcp#why-lcp-matters","Why LCP Matters",[3354],"LCP directly correlates with perceived load speed. Users don't care about technical metrics—they care about seeing content. A fast LCP means: Better user experienceLower bounce ratesHigher search rankings (it's a ranking factor)Improved conversion rates",{"id":3373,"title":3374,"titles":3375,"content":3376,"level":1756},"/glossary/lcp#common-lcp-issues","Common LCP Issues",[3354],"Slow server response - Time to First Byte (TTFB) delays everything downstream. Render-blocking resources - CSS and JavaScript that block the main thread delay LCP elements. Unoptimized images - Large, uncompressed images take longer to download and render. Client-side rendering - SPAs that render content via JavaScript often have poor LCP.",{"id":3378,"title":3379,"titles":3380,"content":3381,"level":1756},"/glossary/lcp#how-to-measure-lcp","How to Measure LCP",[3354],"Use Unlighthouse to measure LCP across your entire site at once, rather than checking pages individually. For individual page testing: Chrome DevTools Performance panelLighthouse in ChromePageSpeed InsightsChrome User Experience Report (CrUX) for field data",{"id":3383,"title":3221,"titles":3384,"content":3385,"level":1828},"/glossary/lcp#measure-in-browser",[3354,3379],"Run this in your browser console to track LCP in real-time. Based on webperf-snippets. type Rating = 'good' | 'needs-improvement' | 'poor'\n\nfunction rateValue(ms: number): Rating {\n return ms <= 2500 ? 'good' : ms <= 4000 ? 'needs-improvement' : 'poor'\n}\n\nconst observer = new PerformanceObserver((list) => {\n const entries = list.getEntries() as PerformanceEntry[]\n const lastEntry = entries.at(-1) as PerformanceEntry & {\n startTime: number\n element?: Element\n url?: string\n size?: number\n }\n if (!lastEntry)\n return\n\n const navEntry = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming\n const activationStart = navEntry?.activationStart || 0\n const lcpTime = Math.max(0, lastEntry.startTime - activationStart)\n const rating = rateValue(lcpTime)\n\n console.log(`LCP: ${(lcpTime / 1000).toFixed(2)}s (${rating})`)\n\n if (lastEntry.element) {\n console.log('LCP Element:', lastEntry.element)\n lastEntry.element.style.outline = '3px dashed lime'\n }\n})\n\nobserver.observe({ type: 'largest-contentful-paint', buffered: true })",{"id":3387,"title":3388,"titles":3389,"content":3390,"level":1756},"/glossary/lcp#improving-lcp","Improving LCP",[3354],"Key optimization strategies: Optimize your server - Use caching, CDNs, and efficient backend codePreload critical resources - Use for LCP imagesCompress images - Use modern formats (WebP, AVIF) and proper sizingRemove render-blocking resources - Defer non-critical CSS/JSUse SSR or SSG - Avoid client-side rendering for above-the-fold content LCP is measured in the field (real users) and lab (synthetic tests). Field data from CrUX is what Google uses for rankings. html pre.shiki code .swqme, html code.shiki .swqme{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#C792EA}html pre.shiki code .sryBE, html code.shiki .sryBE{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#FFCB6B}html pre.shiki code .sc1V3, html code.shiki .sc1V3{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#89DDFF}html pre.shiki code .sbw7o, html code.shiki .sbw7o{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#89DDFF}html pre.shiki code .sJnJ8, html code.shiki .sJnJ8{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#C3E88D}html pre.shiki code .s0YkB, html code.shiki .s0YkB{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#82AAFF}html pre.shiki code .sx-uw, html code.shiki .sx-uw{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#89DDFF}html pre.shiki code .sgUNn, html code.shiki .sgUNn{--shiki-light:#E36209;--shiki-light-font-style:inherit;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s9nlO, html code.shiki .s9nlO{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FFCB6B}html pre.shiki code .smL2f, html code.shiki .smL2f{--shiki-light:#D73A49;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sqjlB, html code.shiki .sqjlB{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#BABED8}html pre.shiki code .sjz_z, html code.shiki .sjz_z{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#F78C6C}html pre.shiki code .smpaK, html code.shiki .smpaK{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#BABED8}html pre.shiki code .sqVJQ, html code.shiki .sqVJQ{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#F07178}html pre.shiki code .sWpk2, html code.shiki .sWpk2{--shiki-light:#E36209;--shiki-default:#E36209;--shiki-dark:#F07178}html pre.shiki code .s4OlC, html code.shiki .s4OlC{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#BABED8}html pre.shiki code .sGFTI, html code.shiki .sGFTI{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":3392,"title":3393,"titles":3394,"content":3395,"level":1766},"/glossary/speed-index","What is Speed Index?",[],"Learn what Speed Index measures, its thresholds, and how to improve visual loading speed for better user experience. Speed Index measures how quickly visible content populates the viewport during page load. It captures the overall visual loading experience rather than a single moment in time.",{"id":3397,"title":3398,"titles":3399,"content":3400,"level":1756},"/glossary/speed-index#what-speed-index-measures","What Speed Index Measures",[3393],"Speed Index analyzes a video of the page loading and calculates how quickly the viewport fills with content. It considers the visual progression between frames: A page that renders 80% of content instantly then slowly loads the rest scores better thanA page that loads content evenly over time Lower scores are better. A page that shows all content immediately has a Speed Index of 0.",{"id":3402,"title":3403,"titles":3404,"content":1843,"level":1756},"/glossary/speed-index#speed-index-thresholds","Speed Index Thresholds",[3393],{"id":3406,"title":3407,"titles":3408,"content":3409,"level":1828},"/glossary/speed-index#mobile","Mobile",[3393,3403],"ScoreRating≤ 3.4sGood3.4s - 5.8sNeeds Improvement> 5.8sPoor",{"id":3411,"title":3412,"titles":3413,"content":3414,"level":1828},"/glossary/speed-index#desktop","Desktop",[3393,3403],"ScoreRating≤ 1.3sGood1.3s - 2.3sNeeds Improvement> 2.3sPoor Desktop thresholds are lower because desktop connections are typically faster.",{"id":3416,"title":3417,"titles":3418,"content":3419,"level":1756},"/glossary/speed-index#how-speed-index-works","How Speed Index Works",[3393],"Lighthouse captures video frames during page load and uses the Speedline library to: Calculate visual completeness at each frameCompute the area under the visual progress curveGenerate a score in milliseconds The score represents the average time at which visible parts of the page are displayed.",{"id":3421,"title":3422,"titles":3423,"content":3424,"level":1756},"/glossary/speed-index#why-speed-index-matters","Why Speed Index Matters",[3393],"Speed Index reflects perceived load speed better than single-moment metrics. A page might have fast FCP but still feel slow if subsequent content takes long to appear. Good Speed Index means: Users see content appearing quicklyReduced perceived wait timeBetter visual loading experienceContributes 10% to Lighthouse score",{"id":3426,"title":3427,"titles":3428,"content":3429,"level":1756},"/glossary/speed-index#speed-index-vs-other-metrics","Speed Index vs Other Metrics",[3393],"MetricMeasuresSingle point vs RangeFCPFirst content appearsSingle momentLCPLargest content appearsSingle momentSpeed IndexOverall visual progressRange (area under curve) Speed Index complements FCP and LCP by measuring the experience between these points.",{"id":3431,"title":3432,"titles":3433,"content":3434,"level":1756},"/glossary/speed-index#common-speed-index-issues","Common Speed Index Issues",[3393],"Render-blocking resources - CSS and JavaScript that delay initial rendering. Large images above the fold - Unoptimized hero images that load slowly. Web font loading - FOIT (Flash of Invisible Text) delays text rendering. Client-side rendering - JavaScript frameworks that render content after load. Third-party embeds - Social widgets and ads that load in the viewport.",{"id":3436,"title":3437,"titles":3438,"content":3439,"level":1756},"/glossary/speed-index#how-to-measure-speed-index","How to Measure Speed Index",[3393],"Use Unlighthouse to measure Speed Index across your entire site. For individual pages: Lighthouse in Chrome DevToolsPageSpeed InsightsWebPageTest (original source of the metric) Speed Index can't be measured with JavaScript in the browser. It requires video capture and frame-by-frame analysis, which only lab tools like Lighthouse can perform.",{"id":3441,"title":3442,"titles":3443,"content":3444,"level":1756},"/glossary/speed-index#improving-speed-index","Improving Speed Index",[3393],"Key optimization strategies from Chrome DevTools documentation: Minimize main thread work - Reduce JavaScript execution during loadReduce JavaScript execution time - Optimize and split codeEnsure text remains visible during webfont load - Use font-display: swap Additional strategies: Optimize critical rendering path - Inline critical CSS, defer non-criticalOptimize images - Compress, use modern formats (WebP, AVIF), lazy-load below foldPrioritize visible content - Load above-the-fold content firstUse SSR or SSG - Server-render initial content instead of client-side rendering",{"id":3446,"title":3447,"titles":3448,"content":3449,"level":1756},"/glossary/speed-index#lighthouse-weight","Lighthouse Weight",[3393],"Speed Index contributes 10% to the overall Lighthouse Performance score: MetricWeightTBT30%LCP25%CLS25%FCP10%Speed Index10% Speed Index is a lab metric, not a Core Web Vital. Focus on LCP, CLS, and INP for search ranking impact.",{"id":3451,"title":3452,"titles":3453,"content":3454,"level":1766},"/glossary/tbt","What is Total Blocking Time (TBT)?",[],"Learn what Total Blocking Time measures, its thresholds, and how to reduce main thread blocking for better interactivity. Total Blocking Time measures the total time the main thread was blocked during page load. It's the heaviest-weighted Lighthouse metric (30%) and indicates how responsive a page will feel during the loading phase.",{"id":3456,"title":3457,"titles":3458,"content":3459,"level":1756},"/glossary/tbt#what-tbt-measures","What TBT Measures",[3452],"TBT counts the \"blocking\" portion of all Long Tasks between FCP and when the page becomes reliably interactive. A Long Task is any JavaScript task that runs for more than 50ms. For each Long Task, only the time beyond 50ms counts toward TBT: Task duration: 70ms → Blocking time: 20ms (70 - 50)\nTask duration: 250ms → Blocking time: 200ms (250 - 50)\nTask duration: 30ms → Blocking time: 0ms (under threshold) While the main thread is blocked, the browser can't respond to user input like clicks or taps.",{"id":3461,"title":3462,"titles":3463,"content":3464,"level":1756},"/glossary/tbt#tbt-score-thresholds","TBT Score Thresholds",[3452],"ScoreRating≤ 200msGood200ms - 600msNeeds Improvement> 600msPoor Lighthouse tests on simulated mobile hardware. A TBT under 200ms indicates the page should feel responsive during load.",{"id":3466,"title":3467,"titles":3468,"content":3469,"level":1756},"/glossary/tbt#tbt-vs-inp","TBT vs INP",[3452],"TBT and INP both measure responsiveness, but differently: MetricWhenWhatTypeTBTDuring loadMain thread blockingLab metricINPThroughout sessionActual interaction latencyField metric TBT is a lab proxy for interactivity during load. INP measures real user interactions over time. Low TBT often correlates with good INP, but not always.",{"id":3471,"title":3472,"titles":3473,"content":3474,"level":1756},"/glossary/tbt#why-tbt-matters","Why TBT Matters",[3452],"TBT has the highest weight in Lighthouse performance scoring at 30%. It directly reflects whether users can interact with your page during load. High TBT means: Clicks and taps are delayed or ignoredScrolling may feel jankyUsers think the page is frozenPoor Lighthouse performance score",{"id":3476,"title":3477,"titles":3478,"content":3479,"level":1756},"/glossary/tbt#common-tbt-issues","Common TBT Issues",[3452],"Large JavaScript bundles - More code means more parsing and execution time. Unoptimized third-party scripts - Analytics, ads, and widgets competing for main thread. Heavy frameworks - Client-side rendering with large framework overhead. Synchronous operations - Layout thrashing, forced reflows, blocking API calls. No code splitting - Loading JavaScript that isn't needed for initial view.",{"id":3481,"title":3482,"titles":3483,"content":3484,"level":1756},"/glossary/tbt#how-to-measure-tbt","How to Measure TBT",[3452],"Use Unlighthouse to measure TBT across your entire site. For individual pages: Lighthouse in Chrome DevToolsPageSpeed Insights - Lab data sectionWebPageTest",{"id":3486,"title":3221,"titles":3487,"content":3488,"level":1828},"/glossary/tbt#measure-in-browser",[3452,3482],"Run this in your browser console to track Long Tasks that contribute to TBT. let tbt = 0\nlet taskCount = 0\n\nconst observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n // Only the blocking portion (time over 50ms) counts\n const blockingTime = entry.duration - 50\n if (blockingTime > 0) {\n tbt += blockingTime\n taskCount++\n console.log(`Long Task: ${entry.duration.toFixed(0)}ms (blocking: ${blockingTime.toFixed(0)}ms)`)\n }\n }\n})\n\nobserver.observe({ type: 'longtask', buffered: true })\n\n// Check total TBT anytime\nfunction getTBT() {\n const rating = tbt <= 200 ? 'good' : tbt <= 600 ? 'needs-improvement' : 'poor'\n console.log(`TBT: ${tbt.toFixed(0)}ms from ${taskCount} long tasks (${rating})`)\n return tbt\n}\n\nconsole.log('TBT tracking active. Call getTBT() to see current total.')",{"id":3490,"title":3491,"titles":3492,"content":3493,"level":1756},"/glossary/tbt#improving-tbt","Improving TBT",[3452],"Key optimization strategies: Break up Long Tasks - Split large functions using setTimeout, requestIdleCallback, or scheduler.yield()Reduce JavaScript - Remove unused code, tree-shake dependenciesCode split - Load only what's needed for initial viewDefer third-party scripts - Load analytics and ads after critical contentUse web workers - Move heavy computation off the main threadOptimize CSS - Large stylesheets can block the main thread during parsing // Break up a long task\nasync function processLargeArray(items: Item[]) {\n for (const item of items) {\n processItem(item)\n // Yield to main thread periodically\n if (items.indexOf(item) % 100 === 0) {\n await new Promise(resolve => setTimeout(resolve, 0))\n }\n }\n} TBT is only measured in lab conditions. Real-world interactivity is measured by INP. Optimize for both, but prioritize INP since it's a Core Web Vital and ranking factor.",{"id":3495,"title":3447,"titles":3496,"content":3497,"level":1756},"/glossary/tbt#lighthouse-weight",[3452],"TBT has the largest impact on your Lighthouse Performance score: MetricWeightTBT30%LCP25%CLS25%FCP10%Speed Index10% html pre.shiki code .swqme, html code.shiki .swqme{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#C792EA}html pre.shiki code .sqjlB, html code.shiki .sqjlB{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#BABED8}html pre.shiki code .sc1V3, html code.shiki .sc1V3{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#89DDFF}html pre.shiki code .sjz_z, html code.shiki .sjz_z{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#F78C6C}html pre.shiki code .smpaK, html code.shiki .smpaK{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#BABED8}html pre.shiki code .s0YkB, html code.shiki .s0YkB{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#82AAFF}html pre.shiki code .sx-uw, html code.shiki .sx-uw{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#89DDFF}html pre.shiki code .sgUNn, html code.shiki .sgUNn{--shiki-light:#E36209;--shiki-light-font-style:inherit;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .smL2f, html code.shiki .smL2f{--shiki-light:#D73A49;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sqVJQ, html code.shiki .sqVJQ{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#F07178}html pre.shiki code .sTBSN, html code.shiki .sTBSN{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbw7o, html code.shiki .sbw7o{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#89DDFF}html pre.shiki code .sJnJ8, html code.shiki .sJnJ8{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#C3E88D}html pre.shiki code .s4OlC, html code.shiki .s4OlC{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#BABED8}html pre.shiki code .sGFTI, html code.shiki .sGFTI{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sryBE, html code.shiki .sryBE{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#FFCB6B}html pre.shiki code .s9nlO, html code.shiki .s9nlO{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FFCB6B}",{"id":3499,"title":3500,"titles":3501,"content":3502,"level":1766},"/glossary/ttfb","What is Time to First Byte (TTFB)?",[],"Learn what Time to First Byte measures, its thresholds, and how to optimize server response time for faster page loads. Time to First Byte measures how long it takes for the browser to receive the first byte of response from the server. It's a foundational metric that affects all other loading performance metrics.",{"id":3504,"title":3505,"titles":3506,"content":3507,"level":1756},"/glossary/ttfb#what-ttfb-measures","What TTFB Measures",[3500],"TTFB captures the total time for these phases: Redirect time - Processing any HTTP redirectsService worker startup - If applicableDNS lookup - Resolving the domain nameConnection setup - TCP handshakeTLS negotiation - SSL/HTTPS handshakeRequest/response - Time until first response byte arrives A high TTFB delays everything downstream: FCP, LCP, and full page load.",{"id":3509,"title":3510,"titles":3511,"content":3512,"level":1756},"/glossary/ttfb#ttfb-score-thresholds","TTFB Score Thresholds",[3500],"ScoreRating≤ 800msGood800ms - 1800msNeeds Improvement> 1800msPoor Google recommends a TTFB of 800 milliseconds or less.",{"id":3514,"title":3515,"titles":3516,"content":3517,"level":1756},"/glossary/ttfb#why-ttfb-matters","Why TTFB Matters",[3500],"TTFB is the starting point for all other metrics. Nothing can render until the browser receives that first byte. For SPAs that rely on JavaScript rendering, fast TTFB is especially critical since client-side rendering adds additional time on top. Impact of slow TTFB: Delays all subsequent loading metricsExtends time to first renderHurts perceived performanceCan indicate server or infrastructure problems",{"id":3519,"title":3520,"titles":3521,"content":3522,"level":1756},"/glossary/ttfb#common-ttfb-issues","Common TTFB Issues",[3500],"Slow server processing - Complex database queries, unoptimized code, or insufficient server resources. No caching - Regenerating responses that could be cached. Geographic distance - Server far from users without CDN. DNS resolution - Slow or unreliable DNS provider. Too many redirects - Each redirect adds a full round-trip. Missing HTTP/2 or HTTP/3 - Older protocols have more overhead.",{"id":3524,"title":3525,"titles":3526,"content":3527,"level":1756},"/glossary/ttfb#how-to-measure-ttfb","How to Measure TTFB",[3500],"Use Unlighthouse to audit TTFB across your entire site. For individual pages: Chrome DevTools Network panel (look for \"Waiting for server response\")PageSpeed Insights - Shows TTFB in field dataWebPageTest for detailed waterfall analysis",{"id":3529,"title":3221,"titles":3530,"content":3531,"level":1828},"/glossary/ttfb#measure-in-browser",[3500,3525],"Run this in your browser console to see TTFB with sub-part breakdown. Based on webperf-snippets. type Rating = 'good' | 'needs-improvement' | 'poor'\n\nfunction rateValue(ms: number): Rating {\n return ms <= 800 ? 'good' : ms <= 1800 ? 'needs-improvement' : 'poor'\n}\n\nnew PerformanceObserver((list) => {\n const nav = list.getEntriesByType('navigation')[0] as PerformanceNavigationTiming\n const ttfb = nav.responseStart\n\n const rating = rateValue(ttfb)\n console.log(`TTFB: ${ttfb.toFixed(0)}ms (${rating})`)\n\n // Sub-parts breakdown\n console.log('Breakdown:')\n console.log(` DNS: ${(nav.domainLookupEnd - nav.domainLookupStart).toFixed(0)}ms`)\n console.log(` TCP: ${(nav.connectEnd - nav.connectStart).toFixed(0)}ms`)\n console.log(` SSL: ${(nav.connectEnd - (nav.secureConnectionStart || nav.connectStart)).toFixed(0)}ms`)\n console.log(` Server: ${(nav.responseStart - nav.requestStart).toFixed(0)}ms`)\n}).observe({ type: 'navigation', buffered: true })",{"id":3533,"title":3534,"titles":3535,"content":3536,"level":1756},"/glossary/ttfb#improving-ttfb","Improving TTFB",[3500],"Key optimization strategies: Use a CDN - Serve content from edge locations closer to usersEnable caching - Cache responses at CDN, server, and application levelsOptimize server code - Profile and fix slow database queries, inefficient codeUpgrade hosting - More CPU, memory, or faster infrastructureUse HTTP/2 or HTTP/3 - Modern protocols reduce connection overheadMinimize redirects - Each redirect adds a full round-tripOptimize DNS - Use a fast, reliable DNS providerPreconnect to origins - for known third-party domains TTFB is not a Core Web Vital, but it directly impacts LCP which is. A slow TTFB makes it nearly impossible to achieve good LCP scores.",{"id":3538,"title":3539,"titles":3540,"content":3541,"level":1756},"/glossary/ttfb#ttfb-sub-parts","TTFB Sub-Parts",[3500],"When debugging slow TTFB, identify which phase is the bottleneck: PhaseOptimizationDNS LookupUse faster DNS, enable DNS prefetchingTCP ConnectionEnable HTTP/2+, use CDNTLS NegotiationEnable TLS 1.3, session resumptionServer ResponseOptimize backend, add caching html pre.shiki code .swqme, html code.shiki .swqme{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#C792EA}html pre.shiki code .sryBE, html code.shiki .sryBE{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#FFCB6B}html pre.shiki code .sc1V3, html code.shiki .sc1V3{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#89DDFF}html pre.shiki code .sbw7o, html code.shiki .sbw7o{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#89DDFF}html pre.shiki code .sJnJ8, html code.shiki .sJnJ8{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#C3E88D}html pre.shiki code .s0YkB, html code.shiki .s0YkB{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#82AAFF}html pre.shiki code .sx-uw, html code.shiki .sx-uw{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#89DDFF}html pre.shiki code .sgUNn, html code.shiki .sgUNn{--shiki-light:#E36209;--shiki-light-font-style:inherit;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s9nlO, html code.shiki .s9nlO{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FFCB6B}html pre.shiki code .smL2f, html code.shiki .smL2f{--shiki-light:#D73A49;--shiki-light-font-style:inherit;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sqjlB, html code.shiki .sqjlB{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#BABED8}html pre.shiki code .sjz_z, html code.shiki .sjz_z{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#F78C6C}html pre.shiki code .smpaK, html code.shiki .smpaK{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#BABED8}html pre.shiki code .sqVJQ, html code.shiki .sqVJQ{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#F07178}html pre.shiki code .s4OlC, html code.shiki .s4OlC{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#BABED8}html pre.shiki code .sTBSN, html code.shiki .sTBSN{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sGFTI, html code.shiki .sGFTI{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#FF9CAC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":3543,"title":3544,"titles":3545,"content":3546,"level":1766},"/glossary/tti","What is Time to Interactive (TTI)?",[],"Learn what Time to Interactive measured, why it was deprecated in Lighthouse 10, and what metrics replaced it. Time to Interactive (TTI) was removed from Lighthouse 10 in February 2023. Use TBT for lab measurement and INP for field measurement of interactivity. Time to Interactive measured when a page became fully interactive. It was a Lighthouse metric from 2017-2023 before being deprecated due to measurement issues.",{"id":3548,"title":3549,"titles":3550,"content":3551,"level":1756},"/glossary/tti#what-tti-measured","What TTI Measured",[3544],"TTI marked the point when: The page displayed useful content (FCP fired)Event handlers registered for visible elementsThe page responded to interactions within 50ms The metric identified a 5-second \"quiet window\" where no Long Tasks occurred and fewer than 2 network requests were in flight.",{"id":3553,"title":3554,"titles":3555,"content":3556,"level":1756},"/glossary/tti#why-tti-was-deprecated","Why TTI Was Deprecated",[3544],"Google removed TTI in Lighthouse 10 because: Overly sensitive to outliers - A single late network request or Long Task could dramatically inflate TTI, even if the page felt interactive. Better alternatives exist - LCP and Speed Index better indicate when content feels loaded. TBT measures main-thread availability more robustly. Poor correlation with real experience - A page could have terrible TTI but still feel responsive to users, or vice versa. Field measurement issues - TTI required long observation periods and was impractical to measure in real user monitoring.",{"id":3558,"title":3559,"titles":3560,"content":1843,"level":1756},"/glossary/tti#what-replaced-tti","What Replaced TTI",[3544],{"id":3562,"title":3563,"titles":3564,"content":3565,"level":1828},"/glossary/tti#for-lab-testing","For Lab Testing",[3544,3559],"Total Blocking Time (TBT) - Measures cumulative main thread blocking during load. More robust, less sensitive to outliers. When TTI was removed, its 10% score weight shifted to CLS, making the new Lighthouse weights: MetricWeightTBT30%LCP25%CLS25%FCP10%Speed Index10%",{"id":3567,"title":3568,"titles":3569,"content":3570,"level":1828},"/glossary/tti#for-field-measurement","For Field Measurement",[3544,3559],"Interaction to Next Paint (INP) - Measures actual interaction responsiveness across the entire page lifecycle. Became a Core Web Vital in March 2024.",{"id":3572,"title":3573,"titles":3574,"content":3575,"level":1756},"/glossary/tti#tti-thresholds-historical","TTI Thresholds (Historical)",[3544],"When TTI was active, thresholds were: ScoreRating≤ 3.8sGood3.8s - 7.3sNeeds Improvement> 7.3sPoor",{"id":3577,"title":3578,"titles":3579,"content":3580,"level":1756},"/glossary/tti#still-need-tti","Still Need TTI?",[3544],"If you have legacy systems that rely on TTI: It's still available in Lighthouse JSON output with score: 0It's hidden from the HTML reportScripted access to the JSON value continues to work However, you should migrate to TBT or INP for meaningful interactivity measurement.",{"id":3582,"title":3583,"titles":3584,"content":3585,"level":1756},"/glossary/tti#migration-guide","Migration Guide",[3544],"Old ApproachNew ApproachTTI in LighthouseUse TBT (30% of score)TTI in field/RUMUse INP (Core Web Vital)TTI CI assertionsSwitch to TBT thresholds For most sites, the removal of TTI improved Lighthouse scores since pages typically score better on CLS than they did on TTI.",{"id":3587,"title":3588,"titles":3589,"content":3590,"level":1756},"/glossary/tti#measuring-interactivity-today","Measuring Interactivity Today",[3544],"Use Unlighthouse to measure TBT across your site for lab data. For real-user interactivity: Chrome User Experience Report (CrUX) for INP field dataPageSpeed Insights shows both lab TBT and field INPWeb Vitals library for custom RUM",{"id":3592,"title":3593,"titles":3594,"content":3595,"level":1766},"/integration-deprecations","Integration Deprecations",[],"Build tool integrations are deprecated in v1.0. Learn about migration paths and alternatives. The following build tool integrations are deprecated and will be removed in v1.0: @unlighthouse/nuxt@unlighthouse/vite@unlighthouse/webpack Start migrating to CLI or CI integrations for continued support.",{"id":3597,"title":3598,"titles":3599,"content":3600,"level":1756},"/integration-deprecations#background","Background",[3593],"When Unlighthouse was being developed, the goal was to make it as simple as possible to use with your development site. To allow for this,\nintegrations\nwhere added that set up Unlighthouse automatically for you. This provided the site URL, automatic rescans on page updates and route discovery, which allowed for smarter sampling of dynamic routes.",{"id":3602,"title":3603,"titles":3604,"content":3605,"level":1756},"/integration-deprecations#why-deprecate","Why Deprecate?",[3593],"Simply, the integrations are too difficult to maintain, error-prone and provide low-value. In nearly all raised issues related to integration, they weren't needed and the CLI could be used instead.",{"id":3607,"title":3608,"titles":3609,"content":3610,"level":1756},"/integration-deprecations#upgrading","Upgrading",[3593],"You should remove any of the following packages from your project. @unlighthouse/nuxt@unlighthouse/vite@unlighthouse/webpack Instead, you should simply use the CLI. npx unlighthouse --site localhost:3000 The HMR integration be solved by manually rescanning routes using the UI. The route discovery\nwill still work when scanned in the root directory or an app with pages. html pre.shiki code .sryBE, html code.shiki .sryBE{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#FFCB6B}html pre.shiki code .sJnJ8, html code.shiki .sJnJ8{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#C3E88D}html pre.shiki code .sJFDI, html code.shiki .sJFDI{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"id":3190,"title":3612,"titles":3613,"content":3614,"level":1766},"What is cumulative layout shift (CLS)?",[],"CLS measures visual stability. Learn what it is, thresholds, and how to prevent layout shifts. Cumulative Layout Shift (CLS) measures visual stability - how much content unexpectedly moves during loading. It's one of Google's three Core Web Vitals and affects both UX and search rankings.",{"id":3616,"title":3617,"titles":3618,"content":3619,"level":1756},"/glossary/cls#thresholds","Thresholds",[3612],"ScoreRating≤ 0.1Good0.1 - 0.25Needs Improvement> 0.25Poor Aim for a score of 0.1 or less at the 75th percentile of page loads to pass the Google threshold.",{"id":3621,"title":3622,"titles":3623,"content":3624,"level":1756},"/glossary/cls#how-lighthouse-calculates-cls","How Lighthouse calculates CLS",[3612],"CLS quantifies unexpected shifts by multiplying impact fraction (viewport affected) by distance fraction (how far elements moved). User-initiated shifts within 500ms of interaction don't count.",{"id":3626,"title":3627,"titles":3628,"content":3629,"level":1756},"/glossary/cls#why-it-matters","Why it matters",[3612],"Layout shifts cause accidental clicks and lost reading position. 79% of mobile sites pass CLS - it's the best-performing Core Web Vital. Redbus reduced CLS to 0 and saw 80-100% higher conversions.",{"id":3631,"title":3632,"titles":3633,"content":3634,"level":1756},"/glossary/cls#common-issues","Common issues",[3612],"Images without width/height dimensionsAds and embeds without reserved spaceWeb fonts causing text reflowDynamically injected content",{"id":3636,"title":3637,"titles":3638,"content":3639,"level":1756},"/glossary/cls#measure-cls","Measure CLS",[3612],"Core Web Vitals Checker - test any pageChrome DevTools Performance panelLighthouse auditPageSpeed Insights (field data)Web Vitals Chrome extension → Complete CLS guide",{"id":3230,"title":3641,"titles":3642,"content":3643,"level":1766},"What is first contentful paint (FCP)?",[],"FCP measures when the first content renders. Learn what it is, thresholds, and how to improve it. First Contentful Paint (FCP) measures when the browser renders the first piece of content - text, image, SVG, or canvas element. It answers \"is anything happening?\" and contributes 10% to your Lighthouse score.",{"id":3645,"title":3617,"titles":3646,"content":3647,"level":1756},"/glossary/fcp#thresholds",[3641],"ScoreRating≤ 1.8sGood1.8s - 3.0sNeeds Improvement> 3.0sPoor Aim for a score of 1.8 seconds or less at the 75th percentile of page loads to pass the Google threshold.",{"id":3245,"title":3246,"titles":3649,"content":3650,"level":1756},[3641],"MetricMeasuresQuestion It AnswersFCPFirst content appears\"Is anything happening?\"LCPLargest content appears\"Is the main content loaded?\" A page can have fast FCP (spinner appears) but slow LCP (actual content takes longer). Both matter for UX.",{"id":3652,"title":3627,"titles":3653,"content":3654,"level":1756},"/glossary/fcp#why-it-matters",[3641],"FCP marks when users perceive the page is loading. Before FCP, they see only a blank screen. Fast FCP reassures users something is happening, reducing early abandonment.",{"id":3656,"title":3632,"titles":3657,"content":3658,"level":1756},"/glossary/fcp#common-issues",[3641],"Slow server response (TTFB)Render-blocking CSS/JavaScriptLarge CSS files blocking first paintWeb fonts with font-display: block",{"id":3660,"title":3661,"titles":3662,"content":3663,"level":1756},"/glossary/fcp#measure-fcp","Measure FCP",[3641],"Chrome DevTools Performance panelLighthouse auditPageSpeed Insights FCP is a Lighthouse metric, not a Core Web Vital. Improving FCP typically improves LCP, which is a Core Web Vital and ranking factor.",{"id":3309,"title":3665,"titles":3666,"content":3667,"level":1766},"What is interaction to next paint (INP)?",[],"INP measures responsiveness. Learn what it is, thresholds, and how to improve interaction speed. Interaction to Next Paint (INP) measures how quickly your page responds to user interactions. It replaced FID as a Core Web Vital in March 2024 and is a Google ranking factor.",{"id":3669,"title":3617,"titles":3670,"content":3671,"level":1756},"/glossary/inp#thresholds",[3665],"ScoreRating≤ 200msGood200ms - 500msNeeds Improvement> 500msPoor Aim for a score of 200 milliseconds or less at the 75th percentile of page loads to pass the Google threshold.",{"id":3324,"title":3325,"titles":3673,"content":3674,"level":1756},[3665],"FID only measured the first interaction's input delay. INP measures all interactions throughout the page lifecycle, including processing time and rendering. Since 90% of user time is spent after page load, INP better reflects actual experience.",{"id":3676,"title":3627,"titles":3677,"content":3678,"level":1756},"/glossary/inp#why-it-matters",[3665],"While 93% of sites had good FID, only 74% have good INP. Users expect instant feedback - slow interactions make sites feel broken.",{"id":3680,"title":3632,"titles":3681,"content":3682,"level":1756},"/glossary/inp#common-issues",[3665],"Long-running JavaScript blocking main threadHeavy event handlersThird-party scripts (analytics, ads)Hydration delays in SPAs",{"id":3684,"title":3685,"titles":3686,"content":3687,"level":1756},"/glossary/inp#measure-inp","Measure INP",[3665],"Core Web Vitals Checker - test any pagePageSpeed Insights (field data)Search Console Core Web Vitals reportWeb Vitals Chrome extensionTBT as lab proxy → Complete INP guide",{"id":3353,"title":3689,"titles":3690,"content":3691,"level":1766},"What is largest contentful paint (LCP)?",[],"LCP measures loading performance. Learn what it is, thresholds, and how to improve your score. Largest Contentful Paint (LCP) measures how long it takes for the largest visible element to render. It's one of Google's three Core Web Vitals and directly impacts search rankings.",{"id":3693,"title":3617,"titles":3694,"content":3695,"level":1756},"/glossary/lcp#thresholds",[3689],"ScoreRating≤ 2.5sGood2.5s - 4.0sNeeds Improvement> 4.0sPoor Aim for a score of 2.5 seconds or less at the 75th percentile of page loads to pass the Google threshold.",{"id":3697,"title":3698,"titles":3699,"content":3700,"level":1756},"/glossary/lcp#what-triggers-lcp","What triggers LCP",[3689],"LCP tracks when the largest image, video poster, or text block renders. 73% of mobile pages have an image as their LCP element.",{"id":3702,"title":3627,"titles":3703,"content":3704,"level":1756},"/glossary/lcp#why-it-matters",[3689],"LCP is the hardest Core Web Vital to pass - only 59% of mobile pages achieve good scores. Vodafone improved LCP by 31% and saw 8% more sales.",{"id":3706,"title":3632,"titles":3707,"content":3708,"level":1756},"/glossary/lcp#common-issues",[3689],"Slow server response (TTFB)Render-blocking CSS/JavaScriptLarge unoptimized imagesClient-side rendering delays",{"id":3710,"title":3711,"titles":3712,"content":3713,"level":1756},"/glossary/lcp#measure-lcp","Measure LCP",[3689],"Core Web Vitals Checker - test any pageChrome DevTools Performance panelLighthouse auditPageSpeed Insights (field data)Search Console Core Web Vitals report → Complete LCP guide",{"id":3392,"title":3715,"titles":3716,"content":3717,"level":1766},"Lighthouse Speed Index: What It Means, Good Scores & How to Fix",[],"Speed Index (SI) measures how fast visible content fills the viewport. Good: ≤3.4s mobile, ≤1.3s desktop. 10% of Lighthouse performance score. Thresholds, tools, fixes. Speed Index measures how quickly visible content populates the viewport during load. It captures overall visual loading experience rather than a single moment, contributing 10% to your Lighthouse score.",{"id":3719,"title":3617,"titles":3720,"content":1843,"level":1756},"/glossary/speed-index#thresholds",[3715],{"id":3406,"title":3407,"titles":3722,"content":3409,"level":1828},[3715,3617],{"id":3411,"title":3412,"titles":3724,"content":3725,"level":1828},[3715,3617],"ScoreRating≤ 1.3sGood1.3s - 2.3sNeeds Improvement> 2.3sPoor",{"id":3727,"title":2248,"titles":3728,"content":3729,"level":1756},"/glossary/speed-index#how-it-works",[3715],"Lighthouse captures video frames during load and calculates how quickly the viewport fills with content. A page showing 80% content instantly scores better than one loading evenly over time.",{"id":3426,"title":3731,"titles":3732,"content":3733,"level":1756},"Speed Index vs other metrics",[3715],"MetricMeasuresFCPFirst content appearsLCPLargest content appearsSpeed IndexOverall visual progress Speed Index complements FCP and LCP by measuring the experience between these points.",{"id":3735,"title":3632,"titles":3736,"content":3737,"level":1756},"/glossary/speed-index#common-issues",[3715],"Render-blocking CSS/JavaScriptLarge above-the-fold imagesWeb font loading delaysClient-side rendering",{"id":3739,"title":3740,"titles":3741,"content":3742,"level":1756},"/glossary/speed-index#measure-speed-index","Measure speed index",[3715],"Lighthouse in Chrome DevToolsPageSpeed Insights - Speed Index appears in the \"Diagnostics\" sectionWebPageTest (the original source of the metric)Unlighthouse Bulk PageSpeed Test - test Speed Index across your entire site Speed Index is a lab metric, not a Core Web Vital. Focus on LCP, CLS, and INP for search ranking impact. Use the Lighthouse Score Calculator to see how Speed Index (10% weight) affects your overall score.",{"id":3451,"title":3744,"titles":3745,"content":3746,"level":1766},"What is total blocking time (TBT)?",[],"TBT measures main thread blocking during load. Learn what it is, thresholds, and how to reduce blocking time. Total Blocking Time (TBT) measures main thread blocking between FCP and page interactive. It's the highest-weighted Lighthouse metric at 30% and a strong proxy for INP.",{"id":3748,"title":3617,"titles":3749,"content":3750,"level":1756},"/glossary/tbt#thresholds",[3744],"ScoreRating≤ 200msGood200ms - 600msNeeds Improvement> 600msPoor",{"id":3752,"title":3753,"titles":3754,"content":3755,"level":1756},"/glossary/tbt#how-tbt-works","How TBT works",[3744],"TBT counts the \"blocking\" portion of Long Tasks (JavaScript tasks >50ms). Only time beyond 50ms counts: 70ms task → 20ms blocking time250ms task → 200ms blocking time30ms task → 0ms (under threshold) While the main thread is blocked, the browser can't respond to user input.",{"id":3466,"title":3467,"titles":3757,"content":3758,"level":1756},[3744],"MetricWhenTypeTBTDuring loadLab metricINPThroughout sessionField metric TBT is a lab proxy for interactivity. Low TBT typically correlates with good INP, but they can diverge if interactions happen late.",{"id":3760,"title":3627,"titles":3761,"content":3762,"level":1756},"/glossary/tbt#why-it-matters",[3744],"TBT has the largest impact on Lighthouse Performance score. High TBT means clicks and taps are delayed during page load.",{"id":3764,"title":3632,"titles":3765,"content":3766,"level":1756},"/glossary/tbt#common-issues",[3744],"Large JavaScript bundlesUnoptimized third-party scriptsHeavy framework hydrationSynchronous operations and layout thrashing",{"id":3768,"title":3769,"titles":3770,"content":3771,"level":1756},"/glossary/tbt#measure-tbt","Measure TBT",[3744],"Lighthouse in Chrome DevToolsPageSpeed Insights (lab data section)WebPageTest TBT is a lab metric. INP measures real-world interactivity, which is a Core Web Vital and ranking factor.",{"id":3499,"title":3773,"titles":3774,"content":3775,"level":1766},"What is time to first byte (TTFB)?",[],"TTFB measures server response time. Learn what it is, thresholds, and how to optimize it. Time to First Byte (TTFB) measures how long until the browser receives the first byte from the server. It's a foundational metric - nothing can render until this completes.",{"id":3777,"title":3617,"titles":3778,"content":3779,"level":1756},"/glossary/ttfb#thresholds",[3773],"MetricGoodNeeds ImprovementPoorCore Web Vitals≤ 800ms800ms - 1800ms> 1800msLighthouse Audit< 600ms600ms - 1200ms> 1200ms Aim for a field score of 800 milliseconds or less at the 75th percentile to pass the Google threshold. However, the Lighthouse audit requires a server response time under 600ms to pass the lab check.",{"id":3781,"title":3782,"titles":3783,"content":3784,"level":1756},"/glossary/ttfb#what-ttfb-includes","What TTFB includes",[3773],"Redirect timeDNS lookupTCP connectionTLS negotiationServer processing time Sites with poor LCP have an average TTFB of 2,270ms - nearly consuming the entire 2.5s LCP budget.",{"id":3786,"title":3627,"titles":3787,"content":3788,"level":1756},"/glossary/ttfb#why-it-matters",[3773],"TTFB is the starting point for all other metrics. High TTFB delays FCP, LCP, and everything else. For SPAs, fast TTFB is especially critical since client-side rendering adds more time.",{"id":3790,"title":3632,"titles":3791,"content":3792,"level":1756},"/glossary/ttfb#common-issues",[3773],"Slow server processing / database queriesNo caching (regenerating cacheable responses)Geographic distance without CDNToo many redirects",{"id":3794,"title":3795,"titles":3796,"content":3797,"level":1756},"/glossary/ttfb#improve-ttfb","Improve TTFB",[3773],"Use a CDNEnable caching at all levelsOptimize backend codeUse HTTP/2 or HTTP/3Minimize redirects",{"id":3799,"title":3800,"titles":3801,"content":3802,"level":1756},"/glossary/ttfb#measure-ttfb","Measure TTFB",[3773],"Chrome DevTools Network panel (\"Waiting for server response\")PageSpeed InsightsWebPageTest waterfall TTFB directly impacts LCP, a Core Web Vital. Slow TTFB makes good LCP nearly impossible.",{"id":3543,"title":3804,"titles":3805,"content":3806,"level":1766},"What is time to interactive (TTI)?",[],"TTI measured page interactivity but was deprecated in Lighthouse 10. Learn what replaced it. Time to Interactive (TTI) was removed from Lighthouse 10 in February 2023. Use TBT for lab measurement and INP for field measurement. Time to Interactive measured when a page became fully interactive - displaying useful content, event handlers registered, and responding within 50ms. It identified a 5-second \"quiet window\" with no Long Tasks.",{"id":3553,"title":3808,"titles":3809,"content":3810,"level":1756},"Why TTI was deprecated",[3804],"Google removed TTI because: Overly sensitive to outliers - A single late network request could inflate TTIBetter alternatives exist - TBT measures blocking more robustlyPoor correlation with real experience - Terrible TTI could still feel responsive",{"id":3558,"title":3812,"titles":3813,"content":1843,"level":1756},"What replaced TTI",[3804],{"id":3815,"title":3816,"titles":3817,"content":3818,"level":1828},"/glossary/tti#lab-testing","Lab testing",[3804,3812],"Total Blocking Time (TBT) - Measures cumulative main thread blocking. Now has 30% Lighthouse weight.",{"id":3820,"title":3821,"titles":3822,"content":3823,"level":1828},"/glossary/tti#field-measurement","Field measurement",[3804,3812],"Interaction to Next Paint (INP) - Measures actual interaction responsiveness. Core Web Vital since March 2024.",{"id":3825,"title":3826,"titles":3827,"content":3828,"level":1756},"/glossary/tti#historical-thresholds","Historical thresholds",[3804],"ScoreRating≤ 3.8sGood3.8s - 7.3sNeeds Improvement> 7.3sPoor",{"id":3830,"title":3831,"titles":3832,"content":3833,"level":1756},"/glossary/tti#migration","Migration",[3804],"OldNewTTI in LighthouseUse TBTTTI in field/RUMUse INPTTI CI assertionsSwitch to TBT thresholds",[3835,3910,3928,3939,3969],{"title":3836,"path":3837,"stem":3838,"children":3839,"page":3855,"_path":3837},"Guide","/guide","1.guide",[3840,3856,3893],{"title":3841,"path":3842,"stem":3843,"children":3844,"page":3855,"_path":3842},"Getting Started","/guide/getting-started","1.guide/1.getting-started",[3845,3848,3850,3852],{"title":3846,"path":1814,"stem":3847,"_path":1814},"CLI","1.guide/1.getting-started/0.installation",{"title":3846,"path":1875,"stem":3849,"_path":1875},"1.guide/1.getting-started/0.unlighthouse-cli",{"title":1913,"path":1912,"stem":3851,"_path":1912},"1.guide/1.getting-started/1.integrations",{"title":3853,"path":1927,"stem":3854,"_path":1927},"How It Works","1.guide/1.getting-started/how-it-works",false,{"title":3857,"path":3858,"stem":3859,"children":3860,"page":3855,"_path":3858},"Guides","/guide/guides","1.guide/guides",[3861,3863,3866,3869,3871,3873,3876,3879,3881,3883,3886,3889,3891],{"title":1997,"path":1996,"stem":3862,"_path":1996},"1.guide/guides/0.config",{"title":3864,"path":2064,"stem":3865,"_path":2064},"Debugging","1.guide/guides/1.debugging",{"title":3867,"path":2113,"stem":3868,"_path":2113},"Authentication","1.guide/guides/authentication",{"title":2164,"path":2163,"stem":3870,"_path":2163},"1.guide/guides/chrome-dependency",{"title":2184,"path":2183,"stem":3872,"_path":2183},"1.guide/guides/common-errors",{"title":3874,"path":2193,"stem":3875,"_path":2193},"Device Configuration","1.guide/guides/device",{"title":3877,"path":2227,"stem":3878,"_path":2227},"Docker","1.guide/guides/docker",{"title":2243,"path":2242,"stem":3880,"_path":2242},"1.guide/guides/dynamic-sampling",{"title":2675,"path":2262,"stem":3882,"_path":2262},"1.guide/guides/generating-static-reports",{"title":3884,"path":2311,"stem":3885,"_path":2311},"Lighthouse Config","1.guide/guides/lighthouse",{"title":3887,"path":2326,"stem":3888,"_path":2326},"Puppeteer","1.guide/guides/puppeteer",{"title":2405,"path":2404,"stem":3890,"_path":2404},"1.guide/guides/route-definitions",{"title":2420,"path":2419,"stem":3892,"_path":2419},"1.guide/guides/url-discovery",{"title":3894,"path":3895,"stem":3896,"children":3897,"page":3855,"_path":3895},"Recipes","/guide/recipes","1.guide/recipes",[3898,3901,3904,3907],{"title":3899,"path":2464,"stem":3900,"_path":2464},"UI Customization","1.guide/recipes/client",{"title":3902,"path":2479,"stem":3903,"_path":2479},"Improving Accuracy","1.guide/recipes/improving-accuracy",{"title":3905,"path":2509,"stem":3906,"_path":2509},"Large Sites","1.guide/recipes/large-sites",{"title":3908,"path":2549,"stem":3909,"_path":2549},"SPAs","1.guide/recipes/spa",{"title":1913,"path":3911,"stem":3912,"children":3913,"page":3855,"_path":3911},"/integrations","2.integrations",[3914,3916,3919,3922,3925],{"title":3846,"path":2574,"stem":3915,"_path":2574},"2.integrations/0.cli",{"title":3917,"path":2625,"stem":3918,"_path":2625},"CI/CD","2.integrations/1.ci",{"title":3920,"path":2706,"stem":3921,"_path":2706},"Nuxt","2.integrations/3.nuxt",{"title":3923,"path":2744,"stem":3924,"_path":2744},"Vite","2.integrations/4.vite",{"title":3926,"path":2773,"stem":3927,"_path":2773},"Webpack","2.integrations/webpack",{"title":3929,"path":3071,"stem":3930,"children":3931,"_path":3071},"Api Doc","3.api-doc",[3932,3934,3937],{"title":3072,"path":3071,"stem":3933,"_path":3071},"3.api-doc/index",{"title":3935,"path":2807,"stem":3936,"_path":2807},"Config Reference","3.api-doc/config",{"title":3020,"path":3019,"stem":3938,"_path":3019},"3.api-doc/glossary",{"title":3940,"path":3274,"stem":3941,"children":3942,"_path":3274},"Glossary","glossary",[3943,3945,3948,3951,3954,3957,3960,3963,3966],{"title":3280,"path":3274,"stem":3944,"_path":3274},"glossary/index",{"title":3946,"path":3190,"stem":3947,"_path":3190},"CLS","glossary/cls",{"title":3949,"path":3230,"stem":3950,"_path":3230},"FCP","glossary/fcp",{"title":3952,"path":3309,"stem":3953,"_path":3309},"INP","glossary/inp",{"title":3955,"path":3353,"stem":3956,"_path":3353},"LCP","glossary/lcp",{"title":3958,"path":3392,"stem":3959,"_path":3392},"Speed Index","glossary/speed-index",{"title":3961,"path":3451,"stem":3962,"_path":3451},"TBT","glossary/tbt",{"title":3964,"path":3499,"stem":3965,"_path":3499},"TTFB","glossary/ttfb",{"title":3967,"path":3543,"stem":3968,"_path":3543},"TTI (Deprecated)","glossary/tti",{"title":3940,"path":3274,"stem":3941,"children":3970,"page":3855,"_path":3274},[3971,3972,3973,3974,3975,3976,3977,3978],{"title":3946,"path":3190,"stem":3947,"_path":3190},{"title":3949,"path":3230,"stem":3950,"_path":3230},{"title":3952,"path":3309,"stem":3953,"_path":3309},{"title":3955,"path":3353,"stem":3956,"_path":3353},{"title":3958,"path":3392,"stem":3959,"_path":3392},{"title":3961,"path":3451,"stem":3962,"_path":3451},{"title":3964,"path":3499,"stem":3965,"_path":3499},{"title":3967,"path":3543,"stem":3968,"_path":3543},["Reactive",3980],{"$scolor-mode":3981,"$snuxt-seo-utils:routeRules":3984,"$stoasts":3985,"$ssite-config":3986},{"preference":3982,"value":3982,"unknown":3983,"forced":3855},"system",true,{"head":-1,"seoMeta":-1},[],{"_priority":3987,"description":3990,"env":3991,"name":3992,"titleSeparator":3993,"url":3994},{"env":3988,"url":3989,"name":3989,"description":3989,"titleSeparator":3989},-15,-3,"Google Lighthouse for your entire site.","production","Unlighthouse","·","https://unlighthouse.dev",["Set"],["ShallowReactive",3997],{"stats":-1,"search":-1,"navigation":-1}]