ScreenshotNeo

BlogEngineering

Automated Web Audits with Font Analysis

Run reproducible Lighthouse audits, diagnose web-font visibility problems, and combine automated findings with essential manual accessibility checks.

By the ScreenshotNeo team1 October 20269 min read

Direct answer: Run Lighthouse against a specific URL with a documented browser, device, viewport, and throttling setup. Review performance, accessibility, best-practices, and SEO findings, then inspect the page’s font loading separately for invisible text (FOIT), fallback-to-custom swaps (FOUT), and layout shifts. Use font-display and carefully measured preloads as implementation options, and finish with keyboard, screen-reader, and reflow checks that automation cannot establish.

1. Choose an audit interface

Lighthouse is available in Chrome DevTools, PageSpeed Insights, the Lighthouse command-line interface, and Node-based workflows. Pick the interface that matches the job:

Use case Recommended path Why
One-page diagnosis Chrome DevTools Lighthouse Fast feedback with device, category, and throttling controls.
Repeatable local or CI checks Lighthouse CLI Scriptable runs with explicit configuration and output files.
Shareable public report PageSpeed Insights Convenient hosted report for a URL.
Detailed performance investigation Chrome DevTools Performance panel Chrome currently recommends this panel when you need deeper performance debugging than Lighthouse provides.

Lighthouse documentation describes the categories and interfaces in its overview. A Lighthouse result is a diagnostic lead for the page and test setup, not proof that every user experiences the same result.

2. Create a reproducible Lighthouse baseline

  1. Record the URL, date, browser version, viewport, emulated device, network and CPU throttling, logged-in state, cookies, and whether extensions were disabled.
  2. Run the same categories and settings for every comparison.
  3. Repeat a run when a result is surprising; local device load, extensions, and stored device settings can influence scores. Results from different machines are not directly comparable.
  4. Save the HTML or JSON report with the setup notes.

Chrome DevTools

  1. Open the page in Chrome.
  2. Open DevTools, select Lighthouse, and choose the device and categories.
  3. Set throttling deliberately, then click Analyze page load.
  4. Open each failed audit’s reference documentation before changing code.

Lighthouse CLI

npm install --save-dev lighthouse
npx lighthouse https://example.com \
  --output html \
  --output-path ./reports/example.html \
  --chrome-flags='--headless' \
  --only-categories=performance,accessibility,best-practices,seo

For machine processing, request JSON as well:

npx lighthouse https://example.com \
  --output json \
  --output-path ./reports/example.json \
  --chrome-flags='--headless'

Keep the URL and command in version control with your report metadata. Do not compare a desktop run with a mobile-throttled run as if they were the same test.

3. Read the report without overclaiming

Start with the failing audit title, then open its explanation and references. Group findings by root cause instead of applying every suggestion blindly:

  • Performance: identify blocking resources, long tasks, image work, and font timing. Use the Performance panel when a trace-level investigation is required.
  • Accessibility: fix detectable markup, name, role, value, and contrast issues, then perform the manual checks in Section 7.
  • Best practices: verify security and browser-compatibility recommendations against your deployment constraints.
  • SEO: check crawlability, metadata, and rendering prerequisites for the audited URL.

A score is an output of this page and this environment. It is not a population statistic, an accessibility certification, or a guarantee that every font renders correctly for every visitor.

4. Diagnose web-font loading and invisible text

Large or late-loading fonts can delay readable text. Some browsers hide text until a custom font is ready, producing a flash of invisible text (FOIT). Showing a fallback first produces a flash of unstyled text (FOUT); content appears sooner, but the font replacement can still move text and affect cumulative layout shift.

Inspect the request and rendering timeline

  1. Open DevTools Network, filter by font, and inspect request priority, transfer size, response status, and timing.
  2. In Computed styles, confirm the declared family and the actual rendered font where your browser exposes it.
  3. Use a Performance recording to correlate font requests with first contentful paint, largest contentful paint, and layout shifts.
  4. Test a cold cache and a repeat visit. A cached font can hide a first-load problem.
  5. Throttle the connection and CPU to expose races that are invisible on a fast development machine.

Use font-display deliberately

@font-face {
  font-family: 'Example Sans';
  src: url('/fonts/example-sans.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

body {
  font-family: 'Example Sans', system-ui, sans-serif;
}

swap, fallback, and optional tell the browser it may use a system fallback when the custom font is not ready. They change the FOIT/FOUT tradeoff rather than making the font load instantly:

Value Typical behavior Check after changing it
swap Show fallback quickly and swap to the custom face. Text visibility, replacement timing, and layout shift.
fallback Use a short block period, then fallback; replacement may still occur. Slow connections and whether late replacement is useful.
optional Allows the browser to keep the fallback when the custom face is not readily available. Branding impact, repeat visits, and layout stability.

Preload only measured critical fonts

<link rel='preload'
      href='/fonts/example-sans.woff2'
      as='font'
      type='font/woff2'
      crossorigin>

Preloading can help a truly critical font arrive earlier, and Chrome’s guidance describes pairing preloads with font-display: optional as one way to mitigate layout shift. Excessive preloads compete with CSS, scripts, and images and can worsen load metrics. Add one only when the trace shows a real bottleneck, then A/B test for regressions.

Font audit checklist

  • Serve modern, compressed formats such as WOFF2 where your browser support allows.
  • Subset character ranges when the page does not need the full typeface.
  • Declare the weights and styles actually used; avoid triggering synthetic faces accidentally.
  • Check cross-origin headers and the crossorigin attribute on preloads.
  • Compare first load, repeat load, mobile emulation, and a slow network.
  • Capture screenshots at a fixed delay only after deciding whether the product experience should show fallback or final typography.

5. Automate the audit in CI

Run against a stable staging URL or fixture, keep the Lighthouse configuration in the repository, and archive the JSON report. Gate only on thresholds your team has agreed to; a single score change can reflect environment noise.

npx lighthouse https://staging.example.com \
  --only-categories=performance,accessibility \
  --output=json \
  --output-path=./artifacts/lighthouse.json \
  --chrome-flags='--headless=new'

For comparisons, report the environment beside the values. If you need a detailed trace for a suspected regression, collect a Performance-panel trace or an equivalent browser trace rather than adding more Lighthouse runs.

6. Capture visual evidence of font and responsive states

A screenshot can show FOIT, FOUT, clipping, and reflow failures that are difficult to communicate from a score alone. Capture the same viewport and state after a defined wait, and capture both a slow-loading and settled state when diagnosing a race.

7. Complete the accessibility review manually

Automated checks can identify many programmatic markup and contrast problems, but they cannot establish that keyboard and screen-reader navigation works. Chrome’s accessibility reference states: “The only way to find errors related to question #1 is to try using a page with a keyboard or screen reader yourself.”

  • Tab through every interactive control; verify a visible, logical focus order.
  • Use the keyboard to open, close, submit, and escape dialogs, menus, and custom controls.
  • With a screen reader, confirm headings, landmarks, labels, error messages, status updates, and link purpose.
  • Zoom and resize or rotate the viewport; check that content reflows without horizontal scrolling or hidden controls.
  • Check text and controls against the real background in each theme.
  • Repeat the checks after fonts load and after a fallback font is displayed.

Use the Chrome accessibility reference for the automated/manual boundary. The W3C WAI tools directory also lists automated, semi-automated, and manual testing tools; an adjacent option such as axe DevTools can add issue details, but it is not a font-analysis tool.

8. Troubleshooting common failures

Symptom Likely cause Fix
CLI cannot launch Chrome Chrome is missing, blocked, or an incompatible binary is selected. Install a supported Chrome/Chromium build, verify the executable path, and run the same command locally before CI.
Scores vary between runs CPU, extensions, cache, background work, or throttling differs. Record setup, close competing work, use a consistent profile, repeat runs, and compare like-for-like environments.
Text is invisible briefly Font block period creates FOIT. Evaluate swap, fallback, or optional; confirm the fallback has similar metrics and measure layout shift.
Text jumps when the font arrives Fallback and web font have different metrics or a late replacement occurs. Adjust fallback metrics, font loading, or carefully measured preload; verify with a trace and A/B test.
Preload warning or slower page The font is not used soon, is duplicated, or competes with more critical resources. Remove unnecessary preloads and keep only those proven to help the audited page.
Font request is blocked CORS, MIME type, CSP, or an incorrect URL. Inspect the response and console, then correct headers, policy, type, and path.
Automated accessibility report is clean but users struggle Keyboard and screen-reader behavior was not exercised. Run the manual checklist and test resized and rotated layouts.
Screenshot shows a popup or consent dialog The capture occurred before state setup or dismissal. Dismiss it in the test flow, wait for the target state, or hide only known non-content selectors for diagnostic captures.

9. Performance, reliability, and cost notes

  • Performance: Lighthouse itself is a measurement tool; keep its overhead and throttling consistent. Use the Performance panel for detailed causality.
  • Reliability: Stabilize authentication, test data, consent state, cache state, and network conditions. A report without those details is difficult to reproduce.
  • Fonts: Optimize for readable text first, then validate FCP, LCP, and layout shift after every loading-policy change.
  • Cost: Local DevTools and CLI runs have no service charge, but CI consumes compute time. Hosted screenshot or audit APIs can add per-capture costs, so cache deterministic pages and capture only states you need.

10. Or skip the browser setup

ScreenshotNeo provides a website screenshot API and MCP server. It accepts one GET request and returns PNG, JPEG, WebP, or PDF. Cookie and consent banners are accepted and removed before capture, along with more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status.

Use the ScreenshotNeo API documentation for all options. This minimal call captures a page after your audit setup has selected the URL:

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

For audit evidence, ScreenshotNeo also supports full-page capture with lazy images loaded, CSS-element capture, device presets or custom viewports, retina scale, dark mode, custom CSS and JavaScript, click and wait actions, selector hiding, request blocking, custom headers/cookies/user agents, timezone and geolocation, resizing, caching with a chosen TTL, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, PDFs, and a usage API. Its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients.

There is a free plan with 1,000 screenshots per month and no card. Paid plans start at $5 for 3,000 screenshots; every feature is included on every plan. Create a free ScreenshotNeo account.

11. Short FAQ

Does Lighthouse test every accessibility requirement?

No. It can find many detectable issues, but keyboard operation, screen-reader interpretation, and real reflow still require human review.

Should every web font be preloaded?

No. Preload only a font proven to be critical for the audited page, because unnecessary preloads compete with other resources.

Is font-display: swap always best?

No. It often improves text visibility, but the fallback-to-custom replacement can change layout. Compare it with fallback or optional using your page’s measurements.

Why did two Lighthouse machines produce different scores?

Device load, extensions, browser settings, cache, and throttling differ. Record and match the full setup before interpreting a change.

Can a screenshot prove a page is accessible?

No. It can document visual states and reflow, but it cannot prove keyboard or screen-reader behavior.