The Complete Website Speed Checklist: 47 Things to Check
By Rome Thorndike
Images (Items 1-8)
- Convert to WebP or AVIF. WebP is 25-35% smaller than JPEG. AVIF is 30-50% smaller. All modern browsers support both. This is the single highest-impact change for most sites.
- Add responsive srcset. Serve 400px images to phones, 800px to tablets, 1200px to desktops. Mobile users should not download desktop-sized images.
- Lazy-load below-the-fold images. Add
loading="lazy"to every image below the initial viewport. Do NOT lazy-load the hero image. - Set explicit width and height. Every
<img>tag needs width and height attributes. Without them, the browser cannot reserve space, causing layout shift (CLS). - Compress to target sizes. Hero images under 100KB. Content images under 50KB. Thumbnails under 20KB. Any image over 200KB needs attention.
- Use fetchpriority="high" on the hero image. This tells the browser to prioritize downloading the LCP element before other resources.
- Remove EXIF data. Camera metadata adds 10-50KB per image. Strip it during compression.
- Serve images from a CDN. Images hosted on a CDN load from the nearest edge server. This reduces latency by 50-200ms per image on first load.
CSS (Items 9-15)
- Inline critical CSS. CSS needed to render the visible viewport should be in the
<head>, not in an external file. This eliminates a render-blocking request. - Remove unused CSS. Most sites load CSS for components not on the current page. Tools like PurgeCSS can strip unused rules. Our static sites ship 25-40KB of CSS because every rule is intentional.
- Minify CSS. Remove whitespace, comments, and redundant syntax. Saves 15-30% file size. Use cssnano or Lightning CSS.
- Avoid CSS @import. @import creates sequential loading. Use
<link>tags instead so the browser downloads CSS files in parallel. - Use CSS instead of JavaScript for interactions. Smooth scroll, hover effects, accordions (
<details>), and simple animations can all be CSS-only. - Reduce specificity and nesting. Deeply nested selectors slow style recalculation. Keep selectors flat and specific.
- Consolidate to one CSS file. Multiple CSS files mean multiple HTTP requests. Combine into one minified file under 50KB.
JavaScript (Items 16-23)
- Defer all non-critical JS. Add
deferto script tags. This downloads in parallel but executes after HTML parsing. - Remove unused JavaScript libraries. If you loaded jQuery for one animation, replace it with 5 lines of vanilla JS and save 90KB.
- Audit every script. For each script: is it still used? Can it be replaced with CSS? Does it need to load on every page?
- Load third-party scripts after DOMContentLoaded. Analytics, chat widgets, and tracking pixels do not need to block page rendering.
- Bundle and minify. Combine JavaScript files and minify with Terser or esbuild. Reduces requests and file size.
- Remove console.log and dev-only code. Development artifacts add bytes that production visitors download.
- Limit Total Blocking Time. Keep TBT under 200ms. If any single script takes more than 50ms to execute, split it or defer it.
- Avoid document.write. It forces synchronous parsing and blocks rendering.
Fonts (Items 24-28)
- Use font-display: swap. Shows text immediately in a fallback font, then swaps when the custom font loads. Prevents invisible text.
- Self-host fonts. Loading from Google Fonts adds 2 extra round trips (DNS + CSS). Self-hosting is one round trip.
- Preload the primary font.
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin> - Limit font weights. Each weight is a separate file. Two to three weights (400, 600, 700) cover most designs. Do not load 6 weights.
- Use variable fonts. One file contains all weights. Often smaller total size than loading 3-4 individual weight files.
Server and Hosting (Items 29-35)
- Target TTFB under 200ms. If your server takes 800ms to respond, nothing else can start. Move to managed hosting or static files on a CDN.
- Enable GZIP or Brotli compression. Reduces text-based file transfers by 60-80%. Most modern hosts enable this by default.
- Set Cache-Control headers. Static assets (CSS, JS, images, fonts) should have
max-age=31536000. Use versioned filenames for cache busting. - Use a CDN. Cloudflare (free tier) or another CDN ensures assets are served from the nearest edge server worldwide.
- Enable HTTP/2 or HTTP/3. Multiplexes requests over a single connection. Most modern hosts support this.
- Use HTTPS. Required for HTTP/2, improves security, and is a minor ranking signal. Free via Let's Encrypt.
- Consider static hosting. GitHub Pages, Cloudflare Pages, and Netlify serve static files from a global CDN for $0. TTFB: 10-30ms.
Third-Party Scripts (Items 36-41)
- Audit all third-party scripts. Open DevTools Network tab, filter by third-party. Count requests and total size. Common offender: chat widgets at 200-400KB.
- Remove unused tracking. If nobody checks the Hotjar dashboard, remove the script. Every removed script improves speed with zero effort.
- Replace chat widgets with a contact link. If less than 1% of visitors use chat, save 200-400KB on every page load for the 99% who do not.
- Use Google Tag Manager sparingly. GTM makes it easy to add scripts. That ease leads to bloat. Audit GTM tags quarterly.
- Delay non-essential scripts until interaction. Load analytics on first scroll. Load chat on first click. Keeps initial load clean.
- Consolidate analytics. GA4 + Facebook Pixel + Hotjar + HubSpot = 4 tracking scripts. Do you need all of them? Each one costs 30-80KB.
CMS-Specific (Items 42-47)
- WordPress: Reduce plugins to under 10. Each plugin adds global JS/CSS. 20 plugins = 800KB+ of overhead. Audit and remove ruthlessly.
- WordPress: Replace page builders with a lightweight theme. Elementor adds 300KB+ to every page. GeneratePress or Astra add under 30KB.
- WordPress: Enable server-side caching. WP Rocket or LiteSpeed Cache. Eliminates PHP processing on repeat visits.
- Webflow: Minimize interactions. Each interaction adds JS payload. Sites with 10+ interactions score 8-15 points lower.
- Webflow: Optimize images manually. Webflow does not enforce image optimization. Compress before uploading.
- Consider rebuilding on static HTML. If you have exhausted the above items and still cannot break 85, the platform is the bottleneck. Static HTML scores 90-98 by default. Migration starts at $2,500. Audit your site to see the gap.
Read our complete page speed optimization guide for detailed explanations of each technique.
Frequently Asked Questions
Which items should I fix first?
Images (items 1-8) and JavaScript (items 16-23) have the highest impact. Image optimization alone can improve scores by 15-30 points. Deferring JavaScript reduces Total Blocking Time immediately.
How long does it take to work through this checklist?
Basic items (image compression, defer scripts, caching headers) take 1-2 days. Advanced items (critical CSS, font optimization, third-party script management) take 3-5 days. A full audit and fix cycle typically takes 1-2 weeks.
What if I fix everything and still score below 85?
The platform is the bottleneck. WordPress, Webflow, and Squarespace have architectural ceilings. Rebuilding on static HTML is the only way to consistently score 90+. Migration starts at $2,500.
Do I need to implement all 47 items?
No. Focus on the high-impact items first (images, JavaScript, caching). Most sites can gain 20-30 points by fixing items 1-8 and 16-23. The remaining items provide incremental improvements.
Ready to Fill Your Next Event?
We build the page, set up the pixels, and run the ads. You run the event.