Fixing Slow Rendering for AI Crawlers
An AI crawler asks your server for a page and works with whatever comes back. If the reply is slow, the crawler may give up before it arrives. If the reply is fast but holds only an empty shell that JavaScript is meant to fill in later, the crawler gets the shell.
Either way the page is effectively missing from the material an AI assistant can draw on. This guide shows how to measure what a crawler actually receives and how long it waits, then how to fix the server, the cache and the rendering so every request gets complete HTML quickly.
Why speed and rendering matter more for AI crawlers
A person on a slow connection waits, watches a spinner and eventually reads the page. A crawler works differently. It has a queue of URLs to get through, it sets a limit on how long each request may take, and when a request runs past that limit it moves on. None of the major AI providers publish their exact limits, so there is no official number to aim for, but the logic is simple: the longer your server takes, the more likely a fetch is to be abandoned or deprioritised.
The second difference is rendering. A browser downloads your HTML, then your scripts, then runs those scripts to build the page. Google's crawlers do something similar, in a later rendering pass. Most AI crawlers do not. They keep the HTML from the first response and extract text from it. If your product descriptions, article bodies or prices only appear once a script has run and called an API, the crawler's copy of the page does not contain them.
So "slow rendering" in the audit covers two separate faults that often travel together:
- A slow first response. The server takes a long time to start sending the HTML, usually because every request builds the page from scratch with database queries and nothing is cached.
- Content that arrives late. The HTML arrives quickly but is incomplete, and the real content only appears after scripts run. For a crawler that does not run scripts, "late" means "never".
Fixing the first without the second gives crawlers an empty page faster. Fixing the second without the first gives them a complete page they may not wait for. You need both.
Measuring what a crawler waits for
Browser tools report a lot of timings that crawlers never experience, such as image decoding and layout. For a crawler, measure the plain HTTP request. curl can print a timing breakdown for a single fetch:
curl -s -o page.html -A "ClaudeBot" \
-w "status %{http_code}\nconnect %{time_connect}s\ntls %{time_appconnect}s\nfirst byte %{time_starttransfer}s\ntotal %{time_total}s\nbytes %{size_download}\n" \
https://www.example.co.uk/guides/boiler-servicing/
Read the output like this:
| Figure | What it tells you | What a high value usually means |
|---|---|---|
| status | Whether the request succeeded | Anything other than 200 is a bigger problem than speed. A 403 or 429 points to a firewall or rate limit; see the crawler access guide. |
| connect and tls | Network and certificate negotiation | Distance to the server, or no CDN in front of it. |
| first byte | How long the server spent before sending anything | The page is built on every request, slow database queries, or a cache miss. |
| total | Time until the whole HTML document arrived | A very large document, no compression, or a server streaming slowly. |
| bytes | Size of the HTML as transferred | Inline data blobs, inline SVG sprites or huge embedded scripts. |
Run it several times. The first request after a quiet period is often slow because nothing is cached;
the second may be fast. Crawlers frequently request pages that nobody has visited recently, so the slow,
uncached figure is the one that reflects their experience. Adding a random query string, such as ?nocache=123,
often forces a miss on simple caches and shows you the origin time.
Your own connection is not the crawler's. AI providers run their crawlers from their own infrastructure, often in data centres far from a UK host. If your server sits in one UK data centre with no CDN, a crawler's connection time will be higher than yours. An online testing service that lets you pick a test location and a custom user agent gives a fairer picture than a test from your desk.
Spotting an empty or half-built page
The fastest test is to look at page.html from the curl command above. Open it in a text
editor and search for a distinctive sentence from the middle of the page. Then look at what the body
contains. These patterns mean a crawler gets little or nothing:
- A body that is mostly one element such as
<div id="root"></div>or<div id="app"></div>followed by script tags. This is a client-rendered single-page app. - Headings and layout present, but placeholder text such as "Loading..." or skeleton blocks where the content should be. The template is rendered on the server but the data is fetched in the browser.
- The article text present, but prices, stock, reviews or specifications missing. Those parts come from a widget or app that loads after the page.
- All the text present inside a large
<script>block as JSON, but not in the visible HTML. Some frameworks ship page data this way for hydration. A crawler that only extracts visible text will not use it.
In a browser, you can confirm the same thing by turning JavaScript off in developer tools and reloading. What is left is roughly what a non-rendering crawler receives. Do not rely on the Elements panel with scripts on: it shows the page after JavaScript has built it, which is exactly what the crawler does not see.
Rendering options compared
If the content is added by scripts, the lasting fix is to change where the HTML is built. There are four common approaches, and most modern frameworks support more than one.
| Approach | How it works | Suits | Watch out for |
|---|---|---|---|
| Static generation | Pages are built into HTML files when you deploy, then served as files | Articles, guides, service pages, most marketing content | Content that changes often needs a rebuild or timed regeneration |
| Server-side rendering | The server builds the full HTML for each request | Pages with personalised or frequently changing data, search results, stock levels | Slow origins become slow first bytes unless the output is cached |
| Pre-rendering service | A separate service runs a headless browser, saves the result, and serves that saved HTML to bots | Older client-rendered apps that cannot be rebuilt soon | Stale snapshots, extra cost, and the risk of bots and people seeing different content |
| Client rendering only | The server sends a shell and scripts build everything | Logged-in dashboards and tools that crawlers should not index anyway | Public content built this way is largely invisible to AI crawlers |
Static generation is usually the best choice for content pages because it removes both problems at once: the HTML is complete and it is a file, so it is served almost instantly. Server-side rendering with a cache in front comes close. Pre-rendering is a workaround; Google has described serving a separate rendered version to bots, which it calls dynamic rendering, as a stopgap rather than a long-term solution, and the same reasoning applies to AI crawlers. The framework details for React and Next.js are in the React and Next.js agent readiness guide.
The fix, step by step
Step 1
Time the response a crawler gets
Run the Agent Readiness Audit on one page from each template, then repeat the check yourself with curl using a crawler user agent and the timing output shown above. Record the status code, time to first byte, total time and HTML size for a cached request and for a forced cache miss. Test the home page, an article, a product or service page and a category page, because each template is usually built and cached differently.
Step 2
Check the HTML is complete without scripts
Open the saved HTML file in a text editor and search for three things you can see on the live page: a sentence from the main body, a price or key fact, and a heading near the bottom. Then reload the page with JavaScript switched off in developer tools. Anything missing in either test is being built by scripts. Note which parts are missing, because the fix depends on whether it is the whole page or one widget.
Step 3
Cache finished HTML close to the crawler
Put a CDN in front of the site if there is none, and set it to cache HTML for public pages,
not only images and scripts. Send a header such as Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400
so the edge keeps a copy and refreshes it in the background. Exclude basket, checkout, account and admin
paths, and bypass the cache when a login or session cookie is present, so private pages are never shared.
Step 4
Speed up the uncached origin
Crawlers often hit pages nobody has requested lately, so the origin still matters. Enable full-page caching in your CMS or application, turn on an object cache such as Redis for database-heavy sites, and look for slow queries in the page template, such as related-post lists that scan every record. Check the server is not starved of memory or PHP workers. Aim for a first byte well under a second even on a cache miss.
Step 5
Render content on the server or at build time
Where the main content is built by scripts, move it into the server response. Switch content pages to static generation or server-side rendering in your framework, and fetch the data on the server rather than in the browser after load. Where only one widget is script-built, such as reviews or a specification table, ask whether its provider offers server-rendered output, or print the key facts into the template directly.
Step 6
Trim what the HTML carries
Check
the HTML is compressed by looking for Content-Encoding: br or gzip in the response
headers, and turn compression on at the server or CDN if it is missing. Then look for bulk inside the
document: large inline JSON used for hydration, inline SVG icon sets, base64-encoded images and repeated
mega-menu markup. Move these to separate cached files or load them lazily, so the text a crawler needs
arrives in fewer bytes.
Step 7
Confirm crawlers get the fast version
Repeat the curl timings with several crawler user agents and a normal browser user agent, and compare. The HTML text should be the same for all of them and the timings should be similar. Then search your access logs for crawler names and check the response codes and response times recorded there. Finally, run the Agent Readiness Audit again on each template and keep the results for comparison after future changes.
Where the slowness usually comes from
WordPress and other PHP CMSs
Without page caching, every request runs PHP, loads plugins and queries the database. A caching plugin or host-level page cache turns that into a file read. Most WordPress pages are rendered on the server already, so the rendering half of the problem is usually limited to page-builder widgets, review plugins and sliders that load content with scripts. The WordPress agent readiness guide covers the settings.
Shopify and hosted platforms
The platform runs the servers and a CDN, so first-byte time is largely out of your hands and is usually reasonable. The rendering problems come from apps that inject reviews, size guides, FAQs and bundles with scripts. See the Shopify agent readiness guide.
JavaScript frameworks
This is where empty HTML is most common. A single-page app built with a client-only template sends a shell. A framework that supports server rendering can still produce empty pages if the data is fetched inside browser-only code. Fixing it is a code change, not a setting.
Headless setups
A headless CMS feeding a front end built separately adds a network hop on every uncached render. Cache API responses on the server side as well as the HTML, and prefer building pages at deploy time so the CMS is not called on each crawler request.
Pitfalls and edge cases
- Serving bots something different. If you pre-render for crawlers, the saved HTML must match what people see. Adding extra keyword text or hiding content only in the bot version is cloaking, and search engines treat it as spam. The safest approach is one HTML response for everyone.
- Bot protection that adds delay. Some firewall modes hold every unfamiliar client for a JavaScript challenge. A crawler cannot pass it, so the "slow page" is really a blocked page. The crawler access guide covers allowing verified crawlers.
- Cache keyed on user agent. If your cache varies by the full user-agent string, every crawler version gets its own cold cache and is always served slowly. Vary on device type at most.
- Streaming responses. Some frameworks stream HTML in chunks, sending the page frame first and the slower parts later in the same response. The text still arrives in the HTML, but a crawler with a short time limit may cut the stream off before the last chunk. Keep the main content in the first part of the stream.
- Soft errors. A client-rendered app often answers every URL with status 200 and shows "not found" by script. Crawlers then store an error page as if it were content. Make genuinely missing pages return 404 from the server.
- Very large documents. Google documents that Googlebot only processes the first 15 MB of an HTML file. AI crawlers publish no such figure, and some may stop much sooner. Keep documents small and put the main content early in the source.
Keeping it fast after the fix
Speed and rendering regress quietly, because the site still looks fine in a browser. Build a few checks into your routine:
- Keep a short list of test URLs, one per template, and re-run the curl timing and raw-HTML text search after every deployment, theme update or new plugin or app.
- Add an automated check to your build or monitoring that fetches each test URL without running scripts and fails if a known phrase is missing.
- Watch the proportion of cache hits in your CDN dashboard. A sudden drop usually means a new cookie or header is making every request look private.
- Review crawler entries in your access logs monthly for rising response times or error codes.
- Re-run the Agent Readiness Audit after platform or hosting changes, which is when these problems most often start.
For a deeper look at server response time in general, see the TTFB fix guide. For the separate problem of facts hidden in tabs, images and PDFs even when the HTML is complete, see fixing poor content extractability.
1. How fast does a page need to be for AI crawlers?
No AI provider publishes a firm time limit for its crawlers, so any exact figure you see quoted is a guess. The practical aim is to make the complete HTML arrive as quickly as a well-cached static file, which on a decent CDN means a first byte in a fraction of a second. A page that takes several seconds to start responding on a cache miss is at real risk of being abandoned or fetched less often, so treat that as the thing to fix first.
2. My Core Web Vitals are good, so why does the audit say rendering is slow?
Core Web Vitals measure what visitors experience in a browser that runs your scripts. A page can show its main content quickly to a person because scripts build it fast, while the HTML the server sends contains almost none of that content. A crawler that does not run scripts never sees the result. The audit looks at the raw response a crawler receives, which is a different question from how quickly a browser paints the page for a human visitor.
3. Do AI crawlers run JavaScript at all?
Most AI crawlers work from the HTML in the first response and do not run page scripts, or do so only in limited cases. Google is the main exception because its crawlers use the same rendering service as Google Search. Some assistants may use a real browser when a user asks them to open a specific page, but you cannot rely on that for general crawling. The safe assumption is that anything built by scripts after the page loads may never be seen.
4. Is dynamic rendering for bots allowed?
Serving pre-rendered HTML to crawlers while people get the script-built version is not banned in itself, provided both versions contain the same content. Google has described it as a workaround rather than a recommended long-term solution, because it doubles the number of things that can break and snapshots go stale. If the bot version contains different text from the human version, it becomes cloaking. Server-side rendering or static generation for everyone is the more robust fix.
5. Will caching HTML at the CDN show visitors the wrong content?
It can if you cache pages that differ per person, such as the basket, account pages or anything showing a logged-in name. Only cache public pages that look the same for everyone, exclude private paths, and bypass the cache whenever a session or login cookie is present. For pages that change often, a short cache lifetime combined with stale-while-revalidate keeps the content fresh while still answering crawlers quickly from the edge.
6. Why is the page fast for me but slow in the audit?
You are probably getting a cached copy, or you are close to the server. Pages you visit often stay warm in the cache, while a crawler may be the first request in hours and trigger a full rebuild on the origin. Crawlers also connect from their own data centres, which may be far from a UK host. Test with a cache-busting query string and, if you can, from a testing service located outside the UK.
7. Does page speed affect whether AI assistants cite my site?
AI providers do not publish how they choose sources, so nobody can promise a direct link between speed and citations. What is clear is the mechanism: a page that times out or arrives without its text cannot be read, and a page that cannot be read cannot be used as a source. Fixing speed and rendering removes a reason to be left out rather than guaranteeing inclusion, which is why it sits near the top of the fix order.
The Agent Readiness Audit requests your page with real AI crawler user agents, tests how much of the content depends on JavaScript and measures how easily the text can be extracted, alongside robots.txt, llms.txt, JSON-LD and semantic HTML checks.
Open Agent Readiness Fixes โ