Edge SSR for JS-heavy sites
Make every page crawlable by every AI search engine.
A Cloudflare Worker that renders your React, Vue, or Angular SPA into fully-formed HTML at the edge — for Googlebot, GPTBot, ClaudeBot, PerplexityBot, and your actual users. Same HTML for everyone, sub-100ms cache hits, no changes to your origin.
Live demo proves it: raw SPA vs prerendered version — view-source on each.
The problem in 30 seconds
Modern web frameworks — Next.js, Vite + React, Vue 3, Angular — ship a minimal HTML shell and build the page on the user’s device. That’s fine for humans (their browser runs the JavaScript) but a disaster for AI bots:
- GPTBot, ClaudeBot, PerplexityBot, Bingbot do not execute JavaScript at all
- Googlebot does, but on a delayed second pass that often misses recent changes
- Your site looks like an empty
<div id="root">to every bot that matters - You disappear from AI search citations and lose organic discovery
What an AI crawler sees on a CSR site: a 500-byte empty shell. There is nothing to quote, cite, or index. Compare to the prerendered version on the right: every link, heading, structured-data block already in the HTML.
How it works
One small Worker on your Cloudflare zone intercepts every request, asks our engine for the prerendered HTML, and serves it. The engine handles Browser Rendering, caching, and content transforms.
1. Edge worker
~60 lines of TypeScript deployed on the client’s Cloudflare zone. Inspects the User-Agent, branches on bot vs human, and proxies to the engine.
2. Engine
Hosted at prerender.searchtides.com. Uses Cloudflare Browser Rendering (real Chromium) to render the page, extracts CSSOM runtime styles, applies HTMLRewriter transforms, caches in KV, logs to D1.
3. Caching layer
Workers KV stores rendered HTML by URL with configurable per-domain TTL. Globally replicated — first render anywhere warms the cache for every region.
4. Per-domain config
D1 holds wait selectors, hydration delay, content transforms, and cache TTL per client domain. A new client onboards with one INSERT.
Request lifecycle
The edge worker treats bots and humans differently. Bots can wait for a sync render because they don’t mind a 10-second response — partial HTML is worse than delayed HTML. Humans never wait: they get either a cache HIT (instant) or origin fallback while the cache warms in the background.
Real-world numbers
We tested against www.cdvalet.com (Next.js, no SSR, WAF blocks Googlebot UA at the edge) and sportsbook.fanduel.com/navigation/nba (PerimeterX-protected SPA).
From an empty shell to fully-rendered HTML with rate tables, nav, and JSON-LD.
28× the text content. Every rate, every bank, every link reachable.
PerimeterX blocks normal bot UAs. Our render returned 256 KB of live NBA odds.
KV replication is global; warm-cache visitors get HTML faster than origin would render.
What you get
- Bot detection for 30+ crawlers including GPTBot, ClaudeBot, PerplexityBot, OAI-SearchBot, Bingbot, Applebot
- HTMLRewriter content transforms per domain: inject JSON-LD, rewrite meta tags, set titles, prepend head fragments
- Server-side screenshot endpoint for demos and visual regression
- Static-preview mode (
?static=1) for sites with aggressive anti-bot - Render-log analytics in D1: cache hit rate, latency, bot mix per domain
- Stripped script output OR full-script output configurable per request
- Sub-50ms cache hits, 24h default TTL, force-fresh via query param
Try it yourself
Open these and compare:
Raw SPA
Identical React app, no prerender. View-source shows empty shell.
prerender-demo.pages.devUniversal prerender
Same app, same code, served via edge worker. View-source shows full HTML.
prerender-demo.searchtides.comScreenshot of a client SPA
cdvalet.com captured via our engine.
PNG screenshotStatic HTML preview
cdvalet bot-view HTML, scripts stripped so it renders cleanly in any browser.
Static renderIntegrate in 3 steps
- Register your domain. A single INSERT into our D1 table with your origin URL, wait selector, and cache TTL. Takes 30 seconds.
INSERT INTO domains ( host, origin_url, cache_ttl_seconds, wait_until, wait_selector, post_load_delay_ms ) VALUES ( 'www.yoursite.com', 'https://www.yoursite.com', 86400, 'networkidle2', 'main, [role="main"]', 2000 );
- Drop the edge worker on your zone. One
wrangler.toml, one route pattern, one deploy. ~60 lines of code you can audit in 2 minutes.[vars] ENGINE_URL = "https://prerender.searchtides.com/render" [[routes]] pattern = "www.yoursite.com/*" zone_name = "yoursite.com"
- Verify. Curl your URL as Googlebot and as a normal browser. Both should return fully-rendered HTML in <100ms after the first warm. View-source shows your full page content.
curl -A "GPTBot/1.0" https://www.yoursite.com/ | wc -c # should be much larger than your raw SPA shell
Cost
Browser Rendering is ~$0.09 / browser-hour on Workers Paid. Typical client site (~500 unique URLs, 24h cache TTL) renders 500 pages/day ≈ 60-90 browser-minutes, or roughly $2–$3 / month. KV reads and D1 logs are negligible on top.
What to do next
If you run a JS-heavy site and want to show up in AI search, this is the missing piece. Reach out to SearchTides and we’ll have your domain rendering in under an hour.