Every audit tool I've built fetches HTML from a URL and parses it. That works for 70% of the web. It fails for React / Vue / Svelte / Angular apps that inject their content after JavaScript hydration. To those audits, a React SPA looks like an empty <div id="root"></div>.
The "right" fix is a serverless function running headless Chromium that renders the page, waits for JS, and returns the hydrated HTML. That works. It costs $30-100/month for the infrastructure. I don't want to build that.
The Rendered DOM Paste Audit is the pragmatic alternative: you paste the outerHTML from DevTools, the tool audits the post-hydration DOM, and optionally diffs against the server HTML.
What it does
- Optional: Enter the URL.
- Required: Paste the rendered
<html>outerHTML (from Chrome DevTools > Elements > right-click<html>> Copy > Copy outerHTML). - Click Run.
- Tool audits the rendered DOM for: title, meta description, H1 count + content, canonical, lang attribute, JSON-LD block count, images + alt coverage, main-content word count, internal link count.
- If you supplied the URL, the tool also fetches the server HTML, runs the same audits, and shows a diff table highlighting checks where rendered DOM differs from static HTML. Those items are what Googlebot first-crawl misses.
Why paste and not automate?
The paste is the trade-off. Automating means running a headless browser. That means one of:
- Serverless Chromium (Puppeteer + @sparticuz/chromium on Lambda / Netlify) — ~$30/mo at low volume, more at scale, requires a ~50MB bundle
- Browserless.io — hosted headless Chrome service, $0-99/mo depending on tier
- Prerender.io — $15-115/mo depending on page count
- Rendertron — self-hosted, requires a VM
- Your own CI — GitHub Actions running Playwright daily, free on public repos
The paste is free, immediate, and accurate because you're using YOUR actual browser to render — same engine Googlebot uses, same network conditions, same extensions disabled if you test in incognito.
The trade-off is: you can't automate. But for one-off SPA audits, paste is fine. For recurring monitoring, you'd need one of the automation paths above.
How to capture rendered HTML correctly
- Open Chrome (or any Chromium browser).
- Navigate to your SPA URL.
- Wait for the full UI to render. If it's a dashboard, scroll around. If it's a marketing page, wait for all lazy-loaded content. Googlebot waits ~5 seconds; match that.
- Open DevTools (F12 or Cmd+Opt+I).
- In the Elements panel, find the
<html>tag at the top. - Right-click it. Select Copy > Copy outerHTML.
- Paste into the tool.
If your SPA hydrates multiple states (e.g. a logged-out homepage that shifts to a logged-in state), capture the state you want Googlebot to see. Usually that's logged-out.
The diff output is the payoff
The interesting part isn't the rendered audit — it's the diff. When you supply the URL, the tool fetches what the server sent and audits that too. Then it shows you checks where the results differ.
Example output for a React SPA:
| Check | Static HTML | Rendered DOM |
|---|---|---|
<title> |
fail: (missing) | pass: "Our Product Page" |
| meta description | fail: (missing) | pass: "Our product does X..." |
| H1 count | fail: 0 H1s | pass: 1 H1: "Welcome" |
| Word count | fail: 0 words | pass: 1,340 words |
Every row in that diff is content Googlebot's first crawl doesn't see. Google's two-stage indexing DOES eventually get the rendered content, but the first pass is what sets initial rank. If every check fails on the first pass, you're starting indexing cold.
The fix is SSR (server-side rendering). Next.js, Nuxt, SvelteKit, Astro — all offer SSR modes. The Code-Diff Patch Generator can't fix SPA architecture for you, but this tool helps you see why you need to.
What to do after running it
If the diff shows mostly passes on both sides → your SSR is working. Nothing to fix here.
If the diff shows static fails + rendered passes → enable SSR in your framework. Priority:
- Next.js — use
getServerSidePropsor (App Router)export const dynamic = 'force-dynamic'for SSR per route. - Nuxt — SSR is the default (
ssr: truein nuxt.config). Verify it's not disabled. - SvelteKit — SSR enabled by default; check
+page.jsdoesn't setexport const ssr = false. - Astro —
output: 'server'in astro.config. Collections render server-side. - Gatsby — SSG by default; every page is pre-rendered at build time. Verify pages aren't using
windowat import time (that breaks SSG). - Vanilla React / Vue / Svelte — you need to add SSR: Vite has experimental SSR support; simpler path is migrate to Next/Nuxt/SvelteKit or use
react-snapfor pre-rendering.
How it pairs with the rest of the stack
- Prerender vs Hydration Parity Audit — fetches just the static HTML and infers what's missing without requiring paste. Use first for a quick automated check.
- Mega SEO Analyzer v2 — fetches static HTML only. If you're on an SPA, run this paste tool in parallel.
- Code-Diff Patch Generator — patches HTML issues the rendered DOM reveals.
- RUM Beacon Generator — paired release; captures real-user vitals once SSR is fixed.
When to actually invest in automation
If your site is primarily SPA-based AND rendered content differs materially from static, recurring monitoring becomes valuable. Options ranked by cost/effort:
- GitHub Actions + Playwright — free on public repos. One-time setup, daily cron, commits results to a JSON file the Trend Dashboard can ingest.
- Browserless.io free tier — 1000 renders/month free. Wire into a Netlify Function that calls their API and returns rendered HTML.
- Self-hosted Rendertron — on a $4/mo Hetzner / DO VPS. Fully controllable.
- Prerender.io — easiest drop-in, $15-115/mo.
For the one-off case that's 95% of use, the paste tool is enough.
Related reading
- RUM Beacon Snippet Generator — paired release
- Mega SEO Analyzer v2 — paid-tool parity
- Prerender vs Hydration Parity Audit
Fact-check notes and sources
- Google two-stage indexing: Google Search Central - JavaScript SEO basics.
- DevTools Copy outerHTML: Chrome DevTools Elements panel docs.
- Browserless.io free tier: browserless.io pricing.
- Prerender.io pricing: prerender.io/plans.
- Next.js / Nuxt / SvelteKit / Astro SSR docs: respective framework documentation.
This post is informational, not engineering advice. Mentions of Prerender.io, Browserless, Rendertron, Google, Next.js, Nuxt, SvelteKit, Astro, Gatsby, React, Vue, Svelte, and similar products are nominative fair use. No affiliation is implied.