Documentation
A complete guide to Core Web Vitals, every tab and feature, what the scores mean, and how to act on the data.
Overview
Vital Lens measures real Core Web Vitals from inside your browser as pages load — no external APIs, no Lighthouse, no guesswork.
Open the extension on any page and it immediately starts collecting LCP, CLS, INP, FCP, and TTFB using the same web-vitals library that Google itself uses for the Chrome User Experience Report. Metrics update live as the page loads and as you interact with it.
Installation
Vital Lens installs as a standard Chrome extension and works immediately — no account, no API key, no configuration required.
Search for “Vital Lens” in the Chrome Web Store and click Add to Chrome.
Click the puzzle-piece icon in Chrome’s toolbar, find Vital Lens, and click the pin icon to keep it accessible in one click.
Navigate to any http:// or https:// page and click the Vital Lens icon. Measurement starts immediately — no reload required.
Click the panel toggle icon in the popup header to dock Vital Lens as a persistent sidebar that stays open across all tabs.
chrome:// pages, the Chrome Web Store, or PDF viewer pages. On those pages you’ll see a “Cannot measure this page” message.
How It Works
Vital Lens uses two coordinated content scripts to measure real performance events from inside the page’s own JavaScript context.
Chrome extensions run in an isolated JavaScript context by default — separate from the page. But accurate performance measurement (LCP paint events, layout shift records, interaction timings) requires access to the same JavaScript heap that the page uses. Vital Lens solves this with a two-script architecture:
Both scripts are injected at document_start — before the page begins loading — so no paint or layout event is ever missed.
Measurement Priority
To avoid competing with page scripts, observers are set up using scheduler.postTask({ priority: 'user-blocking' }) — the highest available browser task priority. This means Vital Lens registers its observers before most page scripts run, without slowing down the page itself.
When Snapshots Are Saved
A snapshot is written to history when you navigate away from a page or close the tab — not while you’re on it. This ensures the snapshot captures the most complete set of metrics available. INP in particular can only be recorded after a user interaction, so waiting until navigate-away gives it the best chance of capturing a real value.
Overview Tab
Your real-time performance dashboard — a weighted score ring, three Core Web Vital cards with live elapsed timers, secondary metrics, and quick-action buttons.
Performance Score Ring
The circular ring shows a weighted score from 0 to 100 calculated across all five metrics. Weights reflect each metric’s relative importance to user experience:
| Metric | Weight | Why |
|---|---|---|
| LCP | 35% | Directly reflects perceived load speed — the most impactful CWV for users |
| INP | 30% | Measures responsiveness to all interactions — replaced FID as a Core Web Vital in 2024 |
| CLS | 25% | Visual stability — unexpected layout shifts are one of the most frustrating user experiences |
| FCP | 5% | Diagnostic — fast FCP with slow LCP indicates render-blocking resources |
| TTFB | 5% | Diagnostic — high TTFB points to server, CDN, or network latency issues |
Each metric that hasn’t arrived yet is scored as “needs improvement” (60/100 points for that weight), not zero. This prevents a page mid-load from showing an artificially low score.
Core Web Vital Cards (LCP · CLS · INP)
Three cards show the three official Google Core Web Vitals. Each card has a color-coded top border, the metric value, a progress bar showing how close to the “poor” threshold you are, and a rating label:
Elapsed Timer
While a metric is still being collected, the card shows a live elapsed timer (e.g. 2.3s…) with a pulsing progress bar. This tells you exactly how long the page has been loading and when each metric typically arrives:
INP — “Tap Page to Measure”
INP (Interaction to Next Paint) measures how quickly the page responds after you click, tap, or press a key. By definition, it cannot be measured until you interact with the page — the browser has nothing to time. Vital Lens shows a grid icon with “Tap page to measure” instead of a spinner. Click, tap, or type anywhere on the page and INP will populate within a second.
Secondary Metrics (FCP · TTFB)
FCP (First Contentful Paint) and TTFB (Time to First Byte) are diagnostic metrics — not Core Web Vitals, but essential for understanding why LCP may be slow:
| Metric | What it measures | If it’s high, suspect… |
|---|---|---|
| FCP | How fast the first text or image appears on screen | Render-blocking CSS/JS, large critical resources, slow server |
| TTFB | How long until the browser receives the first byte from the server | Slow server processing, missing CDN, poor hosting, no caching |
LCP Element Inspector
Click Inspect LCP to highlight the exact element that Chrome identified as the Largest Contentful Paint element — the image, heading, or text block that dominated the viewport when LCP fired. An indigo overlay appears on the page with a label showing the element type.
The panel below the buttons shows the element’s CSS selector and image source URL (if it’s an image). This pinpoints exactly what to optimise — whether it’s an uncompressed hero image, a late-loading webfont, or a large text block.
Pin Baseline
Click Pin Baseline to save the current metrics snapshot as a named reference point for this URL. The baseline is stored with a timestamp and available in the Compare tab. Use this before making performance optimisations — after changes, the Compare tab will show exact before/after deltas.
PageSpeed Button
Opens Google PageSpeed Insights with the current page URL pre-filled. PageSpeed Insights runs a Lighthouse audit on a simulated throttled connection and provides server-side optimisation suggestions that Vital Lens (which runs in your browser) cannot — like image format recommendations, unused CSS elimination, and server response time analysis.
History Tab
A per-domain record of every page load — with an LCP sparkline chart showing your trend over time.
LCP Trend Sparkline
When at least two history entries exist for the current domain, a sparkline chart appears showing LCP values across recent page loads (chronological, oldest to newest). Two threshold lines are drawn:
A filled dot marks the most recent measurement. If the line trends upward over time, LCP is getting worse. If it trends down and stays below the green line, you’re in good shape.
Measurements List
Each row in the history list shows:
| Column | Meaning |
|---|---|
| URL | The page path (truncated) — hover to see the full URL |
| LCP | Colour-coded green/amber/red per the Good/Poor thresholds |
| CLS | Colour-coded — 0.000 means no layout shift was recorded |
| INP | Colour-coded — “—” means no interaction occurred during that session |
| Time | Relative time since the snapshot was saved (e.g. “3m ago”, “2h ago”) |
Up to 40 entries are shown. History is stored per hostname — visiting any page on example.com adds to that domain’s history regardless of the path.
Data Retention
Old entries are automatically pruned based on the retention setting in the Settings tab. The default is 30 days. To keep all history indefinitely, set retention to “Forever” in Settings.
Compare Tab
A before/after comparison between a pinned baseline snapshot and the current live metrics — showing exact deltas for all five metrics.
How Baselines Work
Baselines are saved per URL (exact match — not per hostname). Pin a baseline from the Overview tab’s Pin Baseline button before making performance changes, then return after deploying to see exactly what improved and by how much.
The Compare tab shows two columns:
Delta Badges
Each Current value has a delta badge showing the percentage change from baseline:
Clear Baseline
Click Clear Baseline to remove the pinned baseline for the current URL. The tab will show “No baseline pinned” until you pin a new one from the Overview tab.
Resources Tab
A filterable breakdown of every network resource loaded by the page — sorted by transfer size, with type badges and load duration.
Filter Bar
| Filter | Shows |
|---|---|
| All | Every resource sorted by size (largest first) |
| JS | JavaScript files — script type resources |
| CSS | Stylesheets — stylesheet type resources |
| Images | Image files — image type resources |
| Fonts | Web fonts — font type resources |
| Fetch | API calls — fetch / xmlhttprequest resources |
Resource Row Columns
| Column | Meaning |
|---|---|
| Filename | The resource filename (path stripped, query string stripped). Full URL visible on hover via title attribute. |
| Size | Compressed transfer size in bytes/KB/MB. This is what was actually sent over the wire, not the uncompressed size. |
| Bar | Visual width proportional to the largest resource in the current filter. Makes it easy to spot outliers at a glance. |
| Type badge | Colour-coded resource type: violet = JS, green = CSS, amber = Image, pink = Font, cyan = Fetch, grey = Other. |
| Duration | How many milliseconds the request took from start to end. High durations on critical JS files directly delay LCP. |
Up to 40 resources are shown per filter. Resources are collected from performance.getEntriesByType('resource') at the time you open the extension — they reflect the page’s load state at that moment.
Settings Tab
Configure performance budget alerts, notification behaviour, data retention, and history management.
Performance Budget Alerts
When enabled, Vital Lens monitors every page load and fires a browser notification if any metric exceeds its budget. Budgets are checked as metrics arrive — if LCP crosses your threshold at 3.8 seconds, you’ll know immediately without having to open the extension.
| Budget field | Unit | Default | Recommended starting point |
|---|---|---|---|
| LCP | milliseconds | 2500ms | Match the Good threshold: 2500ms |
| CLS | × 0.01 (integer) | 10 (= 0.10) | 10 for Good threshold (0.10) |
| INP | milliseconds | 200ms | Match the Good threshold: 200ms |
| FCP | milliseconds | 1800ms | Match the Good threshold: 1800ms |
10 for a budget of 0.10, 25 for 0.25. The field label shows “×0.01” as a reminder. Vital Lens divides by 100 internally when comparing against the actual CLS float value.Browser Notifications
When enabled alongside Budget Alerts, Vital Lens shows a native Chrome notification when any budget is exceeded. The notification includes the metric name, its actual value, and your configured budget — so you can see at a glance how far over it went. Notification ID is unique per tab per alert so multiple violations are shown separately.
Data Retention
Controls how long history snapshots are kept in your browser’s IndexedDB. Options: 7 days, 30 days (default), 90 days, or Forever. Old snapshots are pruned automatically after each new page load based on this setting.
Clear History
The Clear All History for This Domain button in the Danger Zone permanently deletes all saved snapshots for the current hostname. This cannot be undone. Baselines for that domain are not affected — those are stored separately and must be cleared from the Compare tab.
Sidebar Mode
Dock Vital Lens as a persistent Chrome Native Side Panel — always visible while you browse, updating automatically as you switch tabs and navigate between pages.
Enabling Sidebar Mode
The rectangular icon with a vertical divider line opens the sidebar immediately and enables auto-open mode.
The page viewport shrinks to accommodate the panel. Chrome places the sidebar in the browser’s native side panel slot — not overlapping page content.
Navigate to new pages, switch tabs — the sidebar updates automatically. Close it using the × in Chrome’s panel header whenever you’re done.
What Updates Automatically
| Action | Sidebar behaviour |
|---|---|
| Navigate to a new URL in the current tab | URL header updates instantly, metrics reset, new measurements stream in as the page loads |
| Switch to a different tab | Sidebar switches context to the new tab — shows that tab’s live vitals or last-known values |
| Open a new tab | Sidebar switches to the new tab context |
| Close the active tab | Sidebar switches to the next active tab |
Limitations
Chrome requires a real user gesture to open the Side Panel programmatically. This means:
- The sidebar cannot auto-open silently when you install the extension or open Chrome
- On new tab switches, Chrome may decline the auto-open request — the panel is still accessible via the Chrome toolbar side panel button
- The sidebar opens immediately and reliably when you click the toggle in the popup (because the click itself is the required user gesture)
Sidebar vs Popup
| Popup | Sidebar | |
|---|---|---|
| Width | 400px fixed | Variable (user resizable) |
| Persistence | Closes when focus leaves | Stays open across navigation |
| Tab awareness | Shows current tab only | Follows tab switches automatically |
| Settings tab | ✅ | ✅ |
| Sidebar toggle | ✅ (opens sidebar) | — (already is the sidebar) |
Interpreting Scores
Quick reference for all five metrics — what counts as Good, Needs Work, and Poor, and what each threshold means in practice.
Core Web Vitals Thresholds
| Metric | Good | Needs Work | Poor | What it means |
|---|---|---|---|---|
| LCP Largest Contentful Paint |
≤ 2.5s | 2.5s – 4.0s | > 4.0s | How fast the main content of the page loads and becomes visible |
| CLS Cumulative Layout Shift |
≤ 0.10 | 0.10 – 0.25 | > 0.25 | How much page content unexpectedly moves after it first appears |
| INP Interaction to Next Paint |
≤ 200ms | 200ms – 500ms | > 500ms | How quickly the page responds visually after every user interaction |
| FCP First Contentful Paint |
≤ 1.8s | 1.8s – 3.0s | > 3.0s | How fast the first text or image appears — signals render-blocking issues |
| TTFB Time to First Byte |
≤ 800ms | 800ms – 1.8s | > 1.8s | How fast the server (or CDN) responds — the foundation every other metric builds on |
Performance Score Ranges
| Score | Grade | Typical meaning |
|---|---|---|
| 85–100 | Excellent | All three Core Web Vitals are Good. Page likely passes Google’s CWV assessment. |
| 65–84 | Good | Most metrics are Good, one may be in Needs Work. Investigate and address the outlier. |
| 45–64 | Needs Work | Multiple metrics are struggling. Users will notice slowness or jank. Prioritise LCP and INP fixes. |
| 0–44 | Poor | Critical issues. High likelihood of failing Google’s Core Web Vitals assessment, which affects Search ranking. |
Frequently Asked Questions
Common questions about measurements, data accuracy, browser behaviour, and troubleshooting.
Measurements & Accuracy
Vital Lens measures your specific browser session on your current network. PageSpeed Insights simulates a mid-range mobile device on a throttled 4G connection, which is significantly slower than most developer setups. Additionally, PageSpeed Insights uses field data (real user measurements collected by Chrome from many visitors), which may include users on slow connections or low-end devices.
Both measurements are useful: Vital Lens shows you real-time feedback while you make changes; PageSpeed Insights shows how real users across all conditions are experiencing your page.
Yes, some variation is completely normal. LCP can vary based on: browser cache state (first load vs cached load), network congestion, server response time variation, third-party script load times, and CPU load on your machine. Measure across 3–5 reloads on an empty cache (Ctrl+Shift+R / Cmd+Shift+R) to get a representative value. The History tab’s sparkline makes this easy to spot trends.
CLS is cumulative — it only accumulates during your current session. If the layout shifts happen as the page loads but you opened Vital Lens after they occurred, the current value will be 0. To capture the full CLS: reload the page fresh, then open Vital Lens before interacting with the page. The CLS value will accumulate as the page settles. Also note: layout shifts caused by user interactions (like clicking an accordion) are excluded from CLS by the spec — only unexpected shifts count.
A few possibilities: (1) The click target might not be an interactive element that triggers a visible repaint — INP requires an interaction that causes the browser to update what’s displayed on screen. Clicking a static element with no visual feedback won’t register. Try clicking a button, link, or dropdown. (2) Some pages use passive event listeners that don’t trigger a repaint on interaction. (3) On very fast pages, INP may register as 0ms or <10ms and appear as “0ms · Good” rather than staying blank — look more carefully at the card.
History & Data
Snapshots are saved when you navigate away from a page or close the tab — not while you’re on the page. If you visited a page and closed the browser directly, the snapshot may not have saved in time (the service worker may have been killed). Also, a snapshot is only saved if at least one core metric (LCP or CLS) was measured — pages where the extension had no time to collect any data won’t generate history entries.
No — Vital Lens stores data in IndexedDB which is cleared when you clear site data or browser storage. If you used Chrome’s “Clear browsing data” with “Hosted app data” or “Cookies and other site data” checked with a broad time range, extension storage may have been included. Uninstalling and reinstalling the extension also clears all history. There is no cloud backup — data is local only.
Export functionality is not available in version 1.0. History can be viewed within the extension’s History tab, and the Compare tab allows before/after comparison against a pinned baseline. CSV/JSON export is planned for a future version.
Sidebar & UI
This is a Chrome API limitation: chrome.sidePanel.open() requires a user gesture. When you switch tabs, the extension attempts to open the panel but Chrome may silently reject the request because there’s no direct user gesture on the extension. The panel remains available via the side panel button in Chrome’s toolbar (the small panel icon to the right of the address bar). Once you manually open it once after a tab switch, it stays open for subsequent switches during that session.
This usually means the sidebar opened before it could identify which tab is active. Try clicking anywhere in the sidebar to trigger a re-check, or close and reopen the sidebar. If the issue persists, hard-reload the active tab (Cmd+Shift+R / Ctrl+Shift+R) to ensure the content scripts are freshly injected.
Some sites use a strict Content Security Policy (CSP) that blocks script injection. In these cases, the content scripts cannot run and Vital Lens cannot collect measurements. This is particularly common on high-security pages like banking portals and internal enterprise apps. chrome:// pages, the Chrome Web Store, and PDF viewer tabs also block all extensions by design.
Performance Budgets
Either raise your budget thresholds to be less strict, or disable Browser Notifications in Settings (keeping Budget Alerts enabled means budgets are still tracked but without desktop notifications). You can also disable Budget Alerts entirely — metrics will still be measured and colour-coded, you just won’t get notifications. The Settings tab lets you tune each metric’s budget independently, so you can be strict about LCP but lenient about FCP.
Yes — CLS budgets are stored as integers multiplied by 100 to avoid floating-point precision issues in number inputs. Enter 10 for a budget of 0.10, 25 for 0.25. The field is labelled “×0.01” to indicate this. Vital Lens divides the stored value by 100 internally when checking whether your actual CLS (e.g. 0.08) exceeds the budget.
Privacy & Data
No. There is no analytics, telemetry, or usage tracking of any kind. Vital Lens does not know what sites you’ve visited. All data — history, baselines, settings — is stored exclusively in your browser’s local IndexedDB. Nothing is transmitted to echozat.com or any external service. The extension makes no outbound network calls.
storage — to save history, baselines, and settings in IndexedDB. tabs — to query the active tab’s URL and listen for tab switches and navigations. activeTab — to inject content scripts into the current page for measurement. scripting — required by MV3 for content script injection. sidePanel — to enable the Native Side Panel feature. notifications — to show budget alert notifications. host permissions (<all_urls>) — content scripts must be allowed to run on any page to measure any site you visit.