Fix guides

Fix: page speed — slow pages, TTFB, page size, requests, compression and caching

Fix Slow pages (over 3 s), Time to First Byte, Server Response Time, Page Size, HTTP Requests and Text compression, with caching, CDN, nginx and Apache steps.

Updated Oct 24, 2026

Page speed affects rankings, conversions and how much of a site Google crawls. This guide covers the speed checks in the audit’s Load speed section, the Slow pages (over 3 s) crawl issue and the most common Lighthouse speed audits. For LCP, INP and CLS, see Fix: Core Web Vitals.

Find the affected pages in the app

  1. Site crawl: open the crawl in Site crawl › Issues tab › Slow pages (over 3 s) lists the affected URLs. In the Pages tab, the Load time column shows each page’s time; open Export for the full list.
  2. Site crawl › Resources: choose Large files to see images over 300 KB, JavaScript over 150 KB and CSS over 100 KB, with Used on (how many pages load them).
  3. Audit report › Load speed: open the audit in Audits; each metric shows the measured value and its target. Failing metrics are listed in Issues to fix.
  4. + audits: the Google Lighthouse section lists opportunities (you can run the same test yourself in PageSpeed Insights) with estimated savings in seconds.

Slow pages (over 3 s)

How we detect it

For every crawled page that returns 200, the crawler records how long it took to download the page’s HTML from our server (connection, server processing and transfer). Pages over 3 seconds are listed. It does not include images, scripts or rendering, so a slow value almost always means a slow server response.

Why it matters

Slow HTML delays everything that follows. Google also crawls fewer pages on slow sites, so new content is found later.

Common causes

  • Only some pages are slow → those pages are not cached (search, filters, cart) or run heavy queries (large archives, related-product widgets).
  • Every page is slow → no page cache, an old PHP version, an overloaded shared server or a far-away server.
  • Slow only sometimes → the server is busy at peak times, or a cron/backup job runs during the crawl.
  • Very slow (10 s and more) → a plugin calls an external API on every page load, or the database is huge (WooCommerce sessions, logs, revisions).

Fix: basic

  1. Turn on page caching (see Platform steps for the exact menus).
  2. Update PHP to a supported version (8.2 or newer). In cPanel › Software › Select PHP Version (or MultiPHP Manager), in Plesk › Websites & Domains › PHP (Plesk docs), in hPanel › Advanced › PHP Configuration.
  3. Remove plugins and apps you don’t use, especially those that add widgets to every page.
  4. Clean the database: WP-Optimize › Database (delete revisions, transients, spam comments) or Advanced Database Cleaner.
  5. If the server is overloaded at busy times, move to a better plan or host (the crawl’s Load time column gives you numbers to show the host).

Fix: expert

Measure server time directly:

curl -o /dev/null -s -w "dns %{time_namelookup}s  connect %{time_connect}s  tls %{time_appconnect}s  ttfb %{time_starttransfer}s  total %{time_total}s\n" https://www.example.com/page/

If ttfb is high and connect is low, the server is slow to build the page. Enable PHP OPcache (php.ini):

opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=1
opcache.revalidate_freq=60

Add a server-level page cache (nginx FastCGI cache):

# http {} block
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=WP:100m inactive=60m;

# server {} block
set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
if ($request_uri ~* "/wp-admin/|/cart/|/checkout/|/my-account/") { set $skip_cache 1; }
if ($http_cookie ~* "wordpress_logged_in|woocommerce_items_in_cart") { set $skip_cache 1; }

location ~ \.php$ {
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_cache WP;
    fastcgi_cache_valid 200 301 60m;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
    add_header X-Cache $upstream_cache_status;
}

Add an object cache (Redis) for database-heavy sites: install Redis on the server, then the Redis Object Cache plugin and click Enable Object Cache.

Platform steps

WordPress

  1. LiteSpeed server (many shared hosts, Hostinger, A2): install LiteSpeed Cache, go to LiteSpeed Cache › Cache › Cache and set Enable Cache to ON. Save.
  2. WP Rocket: page caching is on when the plugin is active. Go to Settings › WP Rocket › Preload and switch on Activate Preloading so pages are cached before visitors arrive.
  3. W3 Total Cache: Performance › General Settings › Page Cache › tick Enable, method Disk: Enhanced. Save and purge.
  4. Hosts with built-in caching (SiteGround, Kinsta, WP Engine, Cloudways): turn it on in the host panel (for SiteGround Speed Optimizer › Caching › Dynamic Caching). Don’t stack two page caches.

Cloudflare

  1. In the Cloudflare dashboard, pick your site › Caching › Configuration: Caching Level: Standard, Browser Cache TTL: Respect Existing Headers.
  2. For WordPress, turn on Automatic Platform Optimization (Speed › Optimization, paid add-on on the Free plan) to cache HTML at the edge, or create a Cache Rule: Caching › Cache Rules › Create rule, expression below, Eligible for cache, Edge TTL 2 hours.
(http.host eq "www.example.com" and not starts_with(http.request.uri.path, "/wp-admin") and not starts_with(http.request.uri.path, "/cart") and not starts_with(http.request.uri.path, "/checkout") and not http.cookie contains "wordpress_logged_in")

Shopify, Wix, Squarespace

  1. Server speed is managed by the platform. Focus on the theme: remove unused apps, sections and large images, and use a fast theme (Shopify’s Dawn or a lightweight theme scores well).

Verify the fix

  1. Run the curl command above twice: the second run should be much faster when caching works (X-Cache: HIT or cf-cache-status: HIT in the headers).
  2. In the app, open the crawl in Site crawl, click Crawl again, then Compare. Slow pages (over 3 s) should move to Fixed and the Load time column should drop.

Automation

Automatable: enabling page caching and PHP upgrades with WordPress admin access via a plugin or hosting panel access (cPanel/Plesk/hPanel); server cache rules need server SSH or a Cloudflare API token.

Time to First Byte (TTFB)

How we detect it

The audit measures the time from the request until the first byte of the page arrives. The target shown is 200 ms or less (“Minimize Time to First Byte & keep under 200 ms”). Lighthouse (+ audits) reports the same problem as “Reduce initial server response time” / “Document request latency” (server-response-time).

Why it matters

Nothing can render before the first byte. A slow TTFB pushes back FCP and LCP.

Common causes

  • No page cache → the page is built by PHP and the database for every visitor.
  • Slow hosting or an overloaded shared server.
  • Server far from the audit location or visitors, with no CDN.
  • Redirects before the page (counted in the wait) → see Fix: HTTPS, SSL and redirects.

Fix: basic

  1. Turn on page caching (see Slow pages above).
  2. Add a CDN (Cloudflare dashboard: add the site, change the nameservers at your registrar to the two Cloudflare gives you, set SSL to Full (strict)).
  3. Link straight to the final URL so there is no redirect before the page.

Fix: expert

Use the curl timing command above. Check slow queries with Query Monitor (WordPress plugin, Queries by component panel) and fix or remove the component at the top.

Platform steps

WordPress

  1. Enable OPcache and object caching as shown above, or ask the host’s panel to switch them on (hPanel › Advanced › PHP Configuration › PHP extensions › opcache).

Verify the fix

  1. Click Run again on the audit in Audits and compare Time to First Byte (TTFB).

Automation

Automatable with hosting panel access or WordPress admin access via a caching plugin.

Server Response Time

How we detect it

The audit measures how long the server took to answer the request. Target: 200 ms or less (“Keep initial server response time under 200 ms”).

Why it matters

It is the server part of TTFB: the time the server spends building the page.

Common causes

  • Uncached dynamic pages, slow database queries, heavy plugins, old PHP.

Fix: basic

  1. Apply the caching and PHP steps under Slow pages.
  2. Deactivate plugins one by one on a staging copy to find the slow one (or use Query Monitor).

Fix: expert

Raise PHP-FPM workers when the server queues requests (pool config, /etc/php/8.3/fpm/pool.d/www.conf):

pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10

Size pm.max_children to available RAM divided by the memory of one PHP process (often 60 to 100 MB).

Platform steps

WordPress

  1. WooCommerce: in WooCommerce › Status › Scheduled Actions, clear failed and old completed actions; a huge actions table slows every page.

Verify the fix

  1. Run again and compare Server Response Time.

Automation

Assisted: needs hosting panel or server SSH access.

Server Connection Time

How we detect it

The audit measures the time to open the connection (DNS, TCP and TLS). The report shows the target (“Reduce initial server connection time under 50 ms”).

Why it matters

Every new visitor pays this cost before any data arrives.

Common causes

  • Server far away from visitors.
  • No HTTP/2 or HTTP/3, or an old TLS setup without session resumption.
  • Slow DNS provider.

Fix: basic

  1. Put the site behind a CDN (Cloudflare), which ends connections close to the visitor.
  2. In the Cloudflare dashboard, pick your site › Speed › Optimization › Protocol Optimization: turn on HTTP/3 (with QUIC) and 0-RTT Connection Resumption.
  3. Use a fast DNS provider (Cloudflare DNS is free).

Fix: expert

Enable HTTP/2 and TLS session reuse (nginx):

server {
    listen 443 ssl;
    http2 on;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_stapling on;
    ssl_stapling_verify on;
}

Apache: Protocols h2 http/1.1 in the virtual host (needs mod_http2).

Platform steps

Cloudflare

  1. In the Cloudflare dashboard, pick your site › set SSL/TLS › Edge Certificates › TLS 1.3 to On.

Verify the fix

  1. Run again and compare Server Connection Time.

Automation

Automatable with a Cloudflare API token; server changes need SSH.

Server Blocking Time

How we detect it

The audit measures time the request spent blocked or queued before it could be sent. Target: 200 ms or less (“Keep server blocking time under 200 ms”).

Why it matters

Blocked requests wait in line, so the page loads in slow waves.

Common causes

  • Too many requests to the same domain on HTTP/1.1.
  • Requests to slow third-party servers.

Fix: basic

  1. Enable HTTP/2 or HTTP/3 (see Server Connection Time).
  2. Remove third-party scripts and fonts you don’t need; host Google Fonts locally (OMGF or WP Rocket in WordPress).

Fix: expert

Add early connections only for third parties you must keep:

<link rel="preconnect" href="https://cdn.example-widget.com" crossorigin>

Platform steps

WordPress

  1. WP Rocket › Preload › Preconnect / Prefetch DNS requests: list the external domains still in use.

Verify the fix

  1. Run again and compare Server Blocking Time.

Automation

Assisted: needs WordPress admin or code access.

Fully Loaded Time

How we detect it

The audit measures the time until every file of the page has finished loading. Target: 2 s or less (“Keep fully loaded time is under 2 seconds”).

Why it matters

It reflects the total weight of the page. A heavy page is slow on mobile networks and uses visitors’ data.

Common causes

  • Large images, many scripts, video backgrounds, chat widgets and tracking tags.

Fix: basic

  1. Compress and resize images and use WebP (see Fix: images).
  2. Lazy-load images below the first screen (WordPress does this by default; check your caching plugin’s Lazy Load option for iframes and videos too).
  3. Remove unused plugins, apps and tracking tags.

Fix: expert

<img src="/img/gallery-1.webp" width="800" height="600" loading="lazy" decoding="async" alt="Finished kitchen project">
<iframe src="https://www.google.com/maps/embed?pb=..." width="600" height="450" loading="lazy" title="Map"></iframe>

Platform steps

Shopify

  1. Use the image_url filter with a width (for example image_url: width: 800) so Shopify serves resized WebP images.

Verify the fix

  1. Run again and compare Fully Loaded Time.

Automation

Assisted: image optimisation is automatable with WordPress admin access via an image plugin; removing scripts needs a person.

First Contentful Paint

How we detect it

In the classic report, First Contentful Paint is the time until the first text or image appears. Target: 1.8 s or less (“Keep First Contentful Paint 1.8 seconds or less”).

Why it matters

Visitors leave when the screen stays blank.

Common causes

  • Slow TTFB, render-blocking CSS and JavaScript, fonts that hide text.

Fix: basic

  1. Follow the First Contentful Paint steps in Fix: Core Web Vitals and check the page in PageSpeed Insights.

Fix: expert

Inline critical CSS and add defer to scripts in the head (snippet in the Core Web Vitals guide).

Platform steps

WordPress

  1. WP Rocket File Optimization › Remove Unused CSS, or LiteSpeed Cache Page Optimization › CSS Settings › Load CSS Asynchronously with Generate Critical CSS.

Verify the fix

  1. Run again and compare First Contentful Paint.

Automation

Automatable with WordPress admin access via a caching plugin.

HTTP Requests

How we detect it

The audit counts the files the page loads. Target: 30 or fewer (“Don’t exceed more than 30 HTTP requests”).

Why it matters

Each request adds a round trip, which slows the page on mobile networks.

Common causes

  • Each plugin or app adds its own CSS and JavaScript files.
  • Icon fonts, several font weights, social widgets, tracking pixels.
  • Galleries loading all images at once.

Fix: basic

  1. Remove plugins and apps you don’t use.
  2. Unload scripts on pages that don’t need them (Perfmatters › Script Manager or Asset CleanUp in WordPress).
  3. Load only the font weights you use (usually two).
  4. Lazy-load images and embeds below the first screen.

Fix: expert

With HTTP/2, combining files matters less than removing them. Replace icon fonts with inline SVG icons, and self-host one variable font file instead of several weights.

Platform steps

Shopify

  1. In Shopify admin, review Settings › Apps and sales channels; each storefront app usually adds at least one script.

Verify the fix

  1. Run again and compare HTTP Requests.

Automation

Assisted: needs WordPress admin, Shopify admin or code access, and testing.

Page Size

How we detect it

The audit adds up the size of all files the page loads. The report shows the target (“Reduce page size & keep under 150 KB”). Scanner lines break it down: “Total JavaScript requests size should not be more than 150 KB”, “Total CSS requests size should not be more than 50 KB”, “Total HTML requests size should not be more than 100 KB”, and “Total other requests size should not be more than 50 KB”. Lighthouse (+ audits) reports “Avoid enormous network payloads” (total-byte-weight).

Why it matters

Heavy pages load slowly on phones and cost visitors data.

Common causes

  • Images → by far the most common (see Lighthouse image audits below).
  • JavaScript → page builders, sliders, analytics and chat widgets.
  • CSS → full framework or page-builder stylesheets loaded on every page.
  • HTML → inline SVGs, inline styles and huge menus.
  • Other → fonts and videos.

Fix: basic

  1. Open Site crawl › your crawl › Resources › Large files to see the biggest files and how many pages use them.
  2. Compress images and convert them to WebP (ShortPixel, Imagify or LiteSpeed Image Optimization; see Fix: images).
  3. Remove unused CSS and JavaScript (WP Rocket Remove Unused CSS, LiteSpeed Generate UCSS).
  4. Minify CSS and JavaScript (WP Rocket File Optimization › Minify CSS files / Minify JavaScript files; LiteSpeed Page Optimization › CSS Minify / JS Minify).
  5. Replace self-hosted background videos with a poster image, or host videos on YouTube or Vimeo with a click-to-play preview.

Fix: expert

Check what is loaded and how big it is in Chrome DevTools › Network (tick Disable cache, reload, sort by Size). The Lighthouse “Reduce unused JavaScript” and “Reduce unused CSS” audits list each file with the KB you could save.

Platform steps

Wix and Squarespace

  1. You can’t change server files. Reduce page weight by removing apps and heavy elements (slideshows, video backgrounds, embedded feeds) and uploading images no wider than they are displayed.

Verify the fix

  1. Run again and compare Page Size and the scanner lines.

Automation

Assisted: compression and minification are automatable with WordPress admin access via a plugin; removing features needs a person.

Text compression

How we detect it

The audit checks whether HTML, CSS and JavaScript are sent compressed (gzip or Brotli). Page facts › Technical shows Compression: On or None. Lighthouse (+ audits): “Enable text compression” (uses-text-compression).

Why it matters

Compression cuts text file size by about 70%, for free.

Common causes

  • Compression is not enabled on the server.
  • A proxy or CDN in front of the server removes it.
  • Only some file types are compressed (for example HTML but not JavaScript or SVG).

Fix: basic

  1. Cloudflare: compression is automatic for proxied sites (orange cloud). In the Cloudflare dashboard, pick your site › check DNS › Records: the site’s records should be Proxied.
  2. WordPress: WP Rocket adds gzip rules to .htaccess automatically on Apache. LiteSpeed servers compress by default.
  3. cPanel: Software › Optimize Website › Compress All Content › Update Settings.
  4. Plesk (Plesk docs): Websites & Domains › Apache & nginx Settings › add the nginx directives below to Additional nginx directives.

Fix: expert

nginx (gzip; add Brotli if the module is installed):

gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_vary on;
gzip_proxied any;
gzip_types text/plain text/css text/xml application/json application/javascript application/xml application/rss+xml image/svg+xml font/ttf font/otf;

# With ngx_brotli:
brotli on;
brotli_comp_level 5;
brotli_types text/plain text/css text/xml application/json application/javascript application/xml image/svg+xml;

Apache (.htaccess):

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/plain text/css text/xml application/javascript application/json application/xml image/svg+xml
</IfModule>
<IfModule mod_brotli.c>
  AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/css application/javascript application/json image/svg+xml
</IfModule>

Platform steps

Shopify, Wix, Squarespace, Webflow

  1. Compression is on by default. If the check fails, a proxy in front of the site may be removing it: check the content-encoding header with the curl command below.

Verify the fix

  1. Run: curl -sI -H "Accept-Encoding: br, gzip" https://www.example.com/ | grep -i content-encoding — it should print br or gzip.
  2. Click Run again on the audit in Audits. Text compression should pass and Page facts should show Compression: On.

Automation

Automatable with hosting panel access (cPanel/Plesk), a Cloudflare API token, or server SSH.

Serve static assets with an efficient cache policy

How we detect it

Lighthouse (+ audits) audit uses-long-cache-ttl, titled “Serve static assets with an efficient cache policy” or, in newer versions, “Use efficient cache lifetimes”. It lists files with a short or missing cache time.

Why it matters

Without browser caching, returning visitors download the same images, CSS and JavaScript again on every page.

Common causes

  • No Cache-Control or Expires headers on static files.
  • Third-party files (analytics, widgets) with short cache times, which you can’t change.

Fix: basic

  1. WordPress: WP Rocket adds browser caching rules automatically on Apache; in LiteSpeed Cache go to Cache › Browser and set Browser Cache to ON.
  2. Cloudflare: in the Cloudflare dashboard, pick your site › Caching › Configuration › Browser Cache TTL: set 1 year only if file names change when files change (most themes add a version number); otherwise Respect Existing Headers with server rules below.
  3. cPanel: many hosts offer Optimize Website or a caching toggle; otherwise add the .htaccess rules below.

Fix: expert

nginx:

location ~* \.(css|js|mjs|woff2?|ttf|otf|svg|png|jpe?g|gif|webp|avif|ico)$ {
    expires 1y;
    add_header Cache-Control "public, max-age=31536000, immutable";
    access_log off;
}

Apache (.htaccess):

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/webp "access plus 1 year"
  ExpiresByType image/avif "access plus 1 year"
  ExpiresByType image/jpeg "access plus 1 year"
  ExpiresByType image/png "access plus 1 year"
  ExpiresByType image/svg+xml "access plus 1 year"
  ExpiresByType text/css "access plus 1 year"
  ExpiresByType application/javascript "access plus 1 year"
  ExpiresByType font/woff2 "access plus 1 year"
</IfModule>

Use long cache times only for versioned files (for example style.css?ver=6.6 or app.3f9a1c.js), so updates still reach visitors.

Platform steps

Shopify, Wix, Squarespace

  1. Static files are cached by the platform’s CDN. Remaining items in the list are usually third-party scripts; remove the ones you don’t need.

Verify the fix

  1. curl -sI https://www.example.com/wp-content/themes/x/style.css | grep -i cache-control should show a long max-age.
  2. Run again on the + audit in Audits.

Automation

Automatable with WordPress admin access via a caching plugin, hosting panel access, a Cloudflare API token or server SSH.

Lighthouse image audits

How we detect it

  • audits list these Lighthouse opportunities with estimated savings: “Serve images in next-gen formats” (modern-image-formats), “Efficiently encode images” (uses-optimized-images), “Properly size images” (uses-responsive-images) and “Defer offscreen images” (offscreen-images). Newer Lighthouse versions combine them into “Improve image delivery”.

Why it matters

Images are usually most of a page’s weight and often the LCP element.

Common causes

  • JPEG/PNG instead of WebP or AVIF.
  • Photos uploaded straight from a camera or stock site (4,000 px wide, several MB).
  • One large image served to phones and desktops alike (no srcset).
  • Images below the first screen loaded immediately.

Fix: basic

  1. Install an image optimiser: ShortPixel, Imagify, EWWW or LiteSpeed Cache Image Optimization. Turn on WebP (or AVIF) creation and run Bulk optimize on existing images.
  2. Before uploading, resize photos to the largest display size (usually 1,600 px wide or less).
  3. Keep WordPress’s native lazy loading on (it is on by default) and make sure the first image is not lazy-loaded.

Fix: expert

<picture>
  <source type="image/avif" srcset="/img/work-800.avif 800w, /img/work-1600.avif 1600w" sizes="(max-width: 800px) 100vw, 800px">
  <img src="/img/work-800.webp" srcset="/img/work-800.webp 800w, /img/work-1600.webp 1600w"
       sizes="(max-width: 800px) 100vw, 800px" width="800" height="533" loading="lazy" decoding="async" alt="Finished roof in Leeds">
</picture>

Bulk-convert on a server: cwebp -q 80 input.jpg -o output.webp.

Platform steps

Shopify

  1. Shopify converts images to WebP automatically when themes use image_url. Upload images at most 2,048 px wide and use widths in image_tag for responsive sizes.

Cloudflare

  1. In the Cloudflare dashboard, Polish (paid plans) compresses and converts images to WebP on the fly; Image Resizing can serve smaller versions.

Verify the fix

  1. Run again on the + audit in Audits; the image opportunities should shrink or disappear.
  2. Crawl again in Site crawl and check Resources › Large files.

Automation

Automatable with WordPress admin access via an image optimisation plugin, or a Cloudflare API token.

Common questions

The crawl says a page is slow but it opens fast in my browser. Why?

The crawl measures how long our server takes to download the page's HTML, without your browser cache or a warm CDN cache. Pages that are not cached on the server, or that run slow database queries, can take over 3 seconds for a first visitor even if they feel fast to you. Turn on page caching and check the server response time.

What is a good Time to First Byte?

The report's target is 200 ms or less. Under about 800 ms is acceptable for real visitors; over that, almost always the page is not cached or the server is overloaded.

Do I need a CDN?

If visitors are far from the server, or the site serves many images, a CDN such as Cloudflare cuts connection time and load. For a local business with a fast host in the same country, page caching matters more than a CDN.

Will a caching plugin break my site?

Page caching is safe on almost all sites. CSS and JavaScript optimisation (combine, defer, delay) can break sliders, forms or menus. Turn those options on one at a time and test the pages after each change.

Still need help?

Ask in the chat inside the app, or send us a message on the contact page. You can also browse all help topics.