A frontend performance audit is not a list of warnings copied from one tool. It is an investigation that starts with a user journey, gathers evidence, identifies the dominant constraint and produces changes that can be verified. The same page may be limited by server latency on a cold visit, JavaScript execution on a mid-range phone and an oversized image on a narrow network.
This checklist moves from field data to network and main-thread analysis, then covers images, caching, accessibility and regression budgets. It is designed for an application team that needs findings with owners and acceptance criteria, not a decorative score. Use the dedicated Core Web Vitals guide when LCP, INP or CLS needs deeper diagnosis.
Define the audit scope before opening DevTools
Select representative journeys rather than testing only the home page. Include an anonymous entry route, a signed-in high-value workflow and at least one interaction-heavy screen. Document the test account state, viewport, device class, network conditions, cache state and release identifier.
- Journey: what the user is trying to complete.
- Population: device, geography, connection and account segment.
- Evidence window: enough production traffic to avoid reacting to noise.
- Success measure: a user-facing metric and a guardrail for correctness.
Run both cold and warm-cache scenarios when they represent real behavior. A repeat visit can hide an expensive first load, while a cold-only test can miss interaction regressions in a long session.
Start with field evidence
Field data tells you which pages and populations need attention. Segment carefully: an overall median can hide slow mobile visits or a problematic region. Review the 75th percentile for Core Web Vitals, but also inspect business and reliability signals such as task completion, errors and abandoned interactions.
Lab tools then help reproduce a representative problem. Do not claim a production improvement from a single synthetic run. Use several comparable runs, control major variables and return to field monitoring after release.
Read the network waterfall as a dependency story
| Observation | Question | Possible action |
|---|---|---|
| Slow first response | Redirect, origin, database or cache miss? | Trace server work and caching |
| Important image discovered late | Is it absent from initial HTML? | Improve discovery and priority |
| Large JavaScript before content | Is all of it needed now? | Remove, split or defer optional code |
| Repeated unchanged resources | Are cache headers or URLs unstable? | Use versioned assets and correct caching |
| Many third-party requests | Which product need owns each tag? | Remove or delay low-value integrations |
Check transferred and uncompressed sizes. Compression helps transfer but not the parse and execution cost of the expanded JavaScript. For ordering choices, use the async, defer and module guide.
Inspect main-thread work around a real interaction
Record a performance trace while reproducing the slow task. Find long tasks, expensive event handlers, style recalculation, layout and paint. A busy timeline before the input may create queueing delay; a large synchronous handler extends processing; rendering work postpones the next frame.
Add application marks around a suspected pure calculation to make traces easier to interpret. This example measures only filtering work, not network time or the final paint.
performance.mark('catalog-filter-start');
const visibleProducts = products.filter(matchesActiveFilters);
performance.mark('catalog-filter-end');
performance.measure(
'catalog-filter',
'catalog-filter-start',
'catalog-filter-end'
);
console.table(
performance.getEntriesByName('catalog-filter').map(({ name, duration }) => ({
name,
duration: `${duration.toFixed(2)} ms`
}))
);
If React dominates the trace, inspect component commits before adding caching. The React performance guide covers state placement, stable props, memoization and list windowing.
Audit images, fonts and layout stability
- Confirm the LCP element and when its resource is discovered.
- Inspect which
srcsetcandidate the browser selected at each viewport. - Verify intrinsic dimensions reserve space for media and embeds.
- Do not lazy-load the true LCP image; lazy-load appropriate off-screen media.
- Check whether font loading changes text geometry or delays important text.
The responsive images guide provides complete markup examples.
Review caching by resource type
A content-hashed static asset can use a long freshness lifetime because a changed file receives a new URL. HTML normally needs revalidation so it can discover a new deployment. no-cache permits storage but requires validation before reuse; it does not mean “never store.”
/assets/app.a1b2c3.js
Cache-Control: public, max-age=31536000, immutable
/index.html
Cache-Control: no-cache
Do not apply immutable to a stable URL whose bytes change. Ensure CDN and browser policies match deployment and rollback behavior.
Include accessibility and correctness guardrails
A faster interaction that loses focus, hides error feedback or removes a useful label is a regression. Test keyboard operation, focus visibility, form labels, error announcement, zoom and reflow on the audited journey. The accessibility guide contains a layered test plan.
Also verify data accuracy, permissions, analytics and error recovery. Performance work often changes loading order and rendering boundaries, which can expose race conditions that a visual happy-path check misses.
Turn findings into decisions
Every finding should contain evidence, user impact, an owner, a bounded proposed change and a verification method. “Reduce JavaScript” is not actionable. “Remove the unused chart library from the anonymous landing route and verify transferred script bytes plus LCP on mobile” is.
| Priority | Evidence | Decision rule |
|---|---|---|
| High | Large field impact on a key journey | Assign owner and near-term target |
| Medium | Reproducible lab cost with plausible user impact | Measure or schedule with related work |
| Low | Tool warning without demonstrated impact | Document, do not disrupt higher-value work |
Add regression budgets
Budgets can cover initial JavaScript, image weight, request count, key route timing or a user-centric metric. Choose limits from product requirements and measured baselines, not a universal template. A budget should fail with a useful explanation and an intentional exception process, otherwise teams learn to ignore it.
Common pitfalls
- Using one Lighthouse score as the audit conclusion.
- Testing only a powerful desktop with a warm cache.
- Optimizing transferred bytes while ignoring execution and rendering.
- Applying every recommendation without prioritizing user impact.
- Shipping a change without production monitoring or a rollback signal.
- Improving speed while breaking keyboard, focus or error behavior.
Frequently asked questions
Is Lighthouse a complete performance audit?
No. It is a useful controlled tool. A complete audit connects field evidence, representative traces, product journeys, accessibility and post-release verification.
Is a smaller bundle always a faster experience?
It often helps, but execution, rendering, caching, server response and user flow also matter. Measure the route and interaction rather than file size alone.
Should every warning be fixed?
No. Prioritize demonstrated user impact, correctness and engineering cost. Document lower-value findings so they can be reconsidered with new evidence.
Authoritative references
- web.dev: Web Vitals
- Chrome DevTools: performance analysis reference
- Google Search Central: helpful, reliable, people-first content
Test your frontend skills
Use the linked mock to verify the performance, React, loading, image and accessibility concepts from this audit.
A practical assessment of Core Web Vitals, React rendering, JavaScript loading, responsive images, caching, semantic HTML, and accessible forms. Start the trivia-style player right inside the article.Modern Frontend Performance & Accessibility Mock Test



Discussion
0 comments
Ask a question or share what stood out to you.