Skip to content
← Tilbage til Learn
Crawling & Indexing Advarsel

Slow page response times

TTFB above 600 ms throttles Google's crawl and degrades INP, LCP, and FCP. Diagnose origin work vs network. Fix with caching at the right layer.

Time to First Byte (TTFB) is the time between the crawler sending the request and your server returning the first byte. It’s the floor for every other speed metric — you can’t have a 2-second LCP if TTFB alone is 2.5 seconds.

Google’s documented thresholds (CrUX, 75th percentile):

  • Good: TTFB < 800 ms
  • Needs improvement: 800 ms – 1800 ms
  • Poor: > 1800 ms

In practice, sustained TTFB above ~600 ms also causes Google to throttle crawl rate. That alone is a discovery problem before it’s a ranking problem.

How to detect it

curl -o /dev/null -s -w \
  "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
  https://example.com/

The number that matters most for crawlers is time_starttransfer minus time_appconnect — that’s pure server work, network neutralized.

Three signals worth checking together:

  1. CrUX TTFB at 75th percentile (PageSpeed Insights, real-user data)
  2. Sampled crawler TTFB (Search Console → Settings → Crawl stats → Avg response time)
  3. Lab TTFB (curl from the same region as your origin)

A gap between CrUX and lab means real users hit different edges or different cache states. A gap between Search Console and lab means Googlebot is hitting cold paths.

The fix — find the actual cost

Sources of slow TTFB, ordered by frequency:

  1. Database query inside the request path — N+1 queries, missing indexes, joins on cold tables.
  2. Cold starts on serverless — first request to an idle function pays minutes-old container init.
  3. Synchronous third-party calls — calling an analytics or auth API in the request handler, blocking on its response.
  4. Origin without a CDN — every request traverses the public internet to one machine.
  5. Render fan-out — the page makes 50 internal HTTP calls to build itself.

Universal — add a CDN cache layer

The cheapest TTFB fix is to serve already-rendered HTML from an edge cache. Set explicit cache headers:

Cache-Control: public, s-maxage=300, stale-while-revalidate=86400

s-maxage is for shared caches (CDNs). stale-while-revalidate lets the CDN serve a slightly stale copy while it refreshes — TTFB stays low even when the page changes.

For pages that legitimately can’t be cached (logged-in user pages, personalized homepages), the fix is to make the origin work faster, not to cache.

WordPress

Order of impact:

  1. Add an object cache (Redis or Memcached) — wp-config.php constant WP_CACHE, plus a drop-in like Redis Object Cache.
  2. Add a full-page cache (WP Rocket, LiteSpeed Cache, or Cloudflare APO).
  3. Audit plugins — query-monitor will show you the slowest DB queries per request. Disable or replace plugins that scan wp_options on every load.

Shopify

Shopify’s origin is already fast. Slow TTFB on Shopify is almost always one of:

  • A theme that makes synchronous calls to a third-party app from theme.liquid.
  • A bloated app that injects script and waits for it to evaluate before the page completes.

Audit with ?view=performance query params on a few key pages, or use the Shopify performance debugger in the admin.

Next.js (App Router)

Use static generation where possible (force-static route segment config). For dynamic pages, enable PPR (Partial Pre-Rendering) or ISR via revalidate:

// app/products/[slug]/page.tsx
export const revalidate = 3600; // ISR — refresh every hour

export default async function Page({ params }: { params: { slug: string } }) {
  const product = await getProduct(params.slug);
  return <Product product={product} />;
}

For RSC pages, audit your await chain. Parallelize independent fetches:

// before — serial, slow
const product = await getProduct(slug);
const reviews = await getReviews(slug);

// after — parallel
const [product, reviews] = await Promise.all([
  getProduct(slug),
  getReviews(slug),
]);

Nginx (as a microcache)

A 30-second microcache in front of a slow origin is a one-line fix that hides almost any spike:

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mc:10m max_size=1g;

server {
  location / {
    proxy_pass http://origin;
    proxy_cache mc;
    proxy_cache_valid 200 30s;
    proxy_cache_use_stale updating error timeout;
    add_header X-Cache $upstream_cache_status;
  }
}

Crawlers hit the cache almost every time. Users hit the cache during traffic spikes. TTFB drops to single-digit milliseconds.

Pitfalls

Don’t optimize the wrong layer. TTFB at the browser includes DNS, TLS, network, and server. If your TTFB is 1.2s and 800ms is TLS handshake from a faraway region, optimizing your database won’t help. Measure first.

Don’t cache personalized content blindly. A logged-in dashboard cached for an anonymous bot is a data leak. Vary by Authorization header or by session cookie.

Don’t ignore third-party scripts at the document level. A <script src="…"> in <head> that blocks parsing doesn’t move TTFB, but it gates every other metric. Defer or lazy-load anything below-the-fold.

stale-while-revalidate is your friend. Most pages don’t need to be perfectly fresh. Letting the CDN serve a 5-minute-old version keeps TTFB low even during a refresh.

Fix at the edge with Serpwise

When the origin is genuinely slow and re-architecting is a quarter-long project, the edge does the work for you.

Serpwise caches HTML at the edge with full control over the cache key (per URL, per query param, per user agent), respects Cache-Control headers from your origin, and serves stale content during origin outages. TTFB drops to whatever your edge is, regardless of what your origin is doing.

See pricing or run a free AI visibility audit.

Fra diagnose til live rettelse

Find issue'et. Få rettelsen live.

Brug Learn til at forstå problemet, og kør derefter Serpwise på dit eget site for at se, hvad der kan rettes og komme live.