Best Practices Score Explained
Best Practices is a grab bag of modern web hygiene. Here's what gets checked, why it matters, and how to fix the common failures.
Table of contents
- The score ranges
- Security checks
- HTTPS
- No vulnerable JavaScript libraries
- Content Security Policy
- COOP / COEP
- Browser console
- No console errors
- No browser deprecation warnings
- User experience
- Allows pasting into password fields
- Doesn't request permissions on page load
- Avoids document.write()
- Allows back/forward cache
- Modern web
- Uses HTTP/2 or HTTP/3
- Image aspect ratio is correct
- Images have appropriate resolution
- `<!DOCTYPE html>` is set
- Charset is declared early
- Performance-adjacent
- Source maps for production JavaScript
- Avoids excessive DOM size
- How to hit 100
- When it can't reach 100
- The bottom line
The Lighthouse Best Practices score covers a grab bag of modern web hygiene — security, modern APIs, console cleanliness, and a few user-experience oddities. Most well-built sites should score 100. Here's the full list of what's checked.
The score ranges
| Score | Rating |
|---|---|
| 90–100 | Good |
| 50–89 | Needs improvement |
| 0–49 | Poor |
Best Practices is mostly binary — each audit either passes or fails. A single console error can drop your score 5–10 points.
Security checks
HTTPS
Your site must be served over HTTPS. Mixed content (HTTP resources on an HTTPS page) is also flagged.
Fix: Get a free certificate from Let's Encrypt or use a host that auto-provisions HTTPS (Vercel, Netlify, Cloudflare Pages all do this).
No vulnerable JavaScript libraries
Lighthouse checks your loaded JS against a database of known vulnerable versions (jQuery, AngularJS, Lodash, etc.).
Fix: Update your dependencies. Run npm audit or yarn audit regularly. Don't pin old versions.
Content Security Policy
A CSP header tells the browser which sources of script, style, and image are allowed. It's one of the strongest defenses against XSS.
Fix: Add a CSP header. Start permissive and tighten over time:
Content-Security-Policy: default-src 'self' https:; script-src 'self' 'unsafe-inline' https:;
COOP / COEP
Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy isolate your page from cross-origin attacks. Lighthouse warns if they're missing.
Fix: Add headers:
Cross-Origin-Opener-Policy: same-origin
Be cautious — strict COEP can break third-party embeds.
Browser console
No console errors
Lighthouse reads the browser console during the audit. Any console.error or uncaught exception counts as a failure.
Fix: Open DevTools, watch the console during page load, fix every error. Common culprits:
- 404s on missing assets
- Third-party scripts failing
- Deprecated API warnings
- React/Vue dev warnings (in production builds)
No browser deprecation warnings
Using APIs Chrome has marked as deprecated. Examples: synchronous XHR, certain crypto methods, document.execCommand.
Fix: Update libraries that use deprecated APIs. Replace your own usages.
User experience
Allows pasting into password fields
Some sites disable paste to "improve security". This actually hurts security — users won't use password managers.
Fix: Remove any JavaScript that calls event.preventDefault() on paste events for password inputs.
Doesn't request permissions on page load
Asking for notifications, geolocation, or microphone access the moment the page loads is hostile UX. Lighthouse flags this.
Fix: Only request permissions in response to a user action (a button click).
Avoids document.write()
document.write() is a synchronous DOM operation that blocks rendering and breaks the back/forward cache.
Fix: Remove all document.write() calls. Use appendChild, insertAdjacentHTML, or framework rendering instead.
Allows back/forward cache
The browser's back/forward cache (bfcache) makes back-navigation instant. Several things disable it:
unloadevent listenersCache-Control: no-storeheaders on the document- Certain features like
getUserMedia
Fix: Replace unload listeners with pagehide and visibilitychange. Don't set no-store on HTML documents.
Modern web
Uses HTTP/2 or HTTP/3
Older HTTP/1.1 has serialization limits. HTTP/2+ multiplexes requests.
Fix: Use a modern host or CDN. Cloudflare and most major CDNs serve HTTP/2 and HTTP/3 by default.
Image aspect ratio is correct
If you set width="800" height="200" but the image is actually 800×400, you've distorted it.
Fix: Use the image's actual dimensions in HTML attributes.
Images have appropriate resolution
A 300×300 image stretched to 1000×1000 looks blurry. Lighthouse flags low-resolution images displayed at higher sizes.
Fix: Serve images at (at least) the resolution they're displayed at, ideally with srcset for high-DPI displays.
<!DOCTYPE html> is set
Without a doctype, browsers enter "quirks mode" which breaks layout.
Fix: Always start your HTML with <!DOCTYPE html>.
Charset is declared early
The browser needs to know the character encoding before parsing. Put it in the first 1024 bytes of your HTML:
<meta charset="utf-8">
Performance-adjacent
Source maps for production JavaScript
Helps with debugging in production. Not strictly required but flagged.
Fix: Generate source maps and serve them. Don't ship them inline — link them via //# sourceMappingURL= comments.
Avoids excessive DOM size
Pages with more than ~1500 nodes can hurt rendering performance.
Fix: Virtualize long lists. Don't render thousands of hidden elements. Use pagination or "load more" patterns.
How to hit 100
A realistic checklist for most sites:
- ✅ Serve over HTTPS
- ✅ Update all dependencies (
npm audit) - ✅ Add a Content Security Policy header
- ✅ Fix every console error and 404
- ✅ Add COOP header
- ✅ Remove any
document.write()usage - ✅ Replace
unloadlisteners withpagehide - ✅ Verify
<!DOCTYPE html>and<meta charset>are present - ✅ Don't request notification/geolocation permissions on page load
Most issues can be resolved in a day. Run a free audit to see your specific failures.
When it can't reach 100
A few legitimate reasons your Best Practices might never hit 100:
- Required third-party scripts that throw console warnings (analytics, chat widgets)
- Embedded content (YouTube, Stripe Elements) that has its own deprecation warnings
- Cookie/consent banners that legally require certain JS patterns
If you've fixed everything in your control and you're at 92–95, that's fine. The score is a guideline, not a religion.
The bottom line
Best Practices is largely about web hygiene. Most failures are quick fixes — update libraries, clean up console errors, add security headers. Aim for 100. Settle for 95 if a third-party makes it impossible.
For the broader picture, see what PageSpeed Insights actually checks.
Frequently Asked Questions
What's a good Best Practices score?+
95 or higher. Most checks are pass/fail, so a single console error or missing HTTPS can drop you from 100 to 92 quickly. Sites should aim for 100.
Why does my Best Practices score change between runs?+
Some checks depend on what scripts log to console during a specific run. A third-party script that occasionally errors will cause score variance. Average a few runs to get a stable picture.
Do I need a Content Security Policy?+
Strongly recommended. CSP prevents many XSS attacks and is one of the highest-impact security headers you can add. It's also a check in the Lighthouse Best Practices category.
See how your site really performs
Run a full website health check on mobile and desktop in 30 seconds — no signup needed.