Enable SEO: crawler pre-rendering
New to SEO? Start with Get found on Google.
Why Google may see an empty page
Most Emergent apps ship as a single-page app (SPA): the HTML your server sends is a nearly empty shell, and your content is drawn by JavaScript once it loads in the browser. That works fine for people. It is a problem for search engines, because a crawler that reads only the HTML sees the same near-empty shell, and the same generic homepage title, on every route of your site.
Turn on Enable SEO
Enable SEO switches on a pre-rendering layer that fixes this. You'll find it under:
Re-publish → Manage Publishing → Domain tab → Enable SEO
The setting applies per published app and persists across re-publishes. Changing it takes effect within about a minute; you do not need to re-publish for the change itself to apply.
Current naming
If you have seen older guidance mention "Publish / Re-publish → Domain", that wording is out of date. Use the current path above.
How it works: dynamic rendering
When Enable SEO is on:
A request arrives
The platform checks the request's User-Agent.
A crawler is detected
If it matches a known crawler (Googlebot, Bingbot, and other search and social crawlers), the request is handed to a headless Chrome browser that loads the page, waits for your JavaScript to finish, and captures the fully-rendered HTML.
The crawler gets real HTML
It receives that rendered HTML, with real per-route titles, meta tags, and structured data, instead of the shell.
The result is cached
The next crawler request hitting the same URL is served from the cache until it expires or you re-publish.
Regular visitors are unaffected; their browsers keep receiving the normal SPA, exactly as before. This technique is called dynamic rendering.
Should you turn it on?
- A standard Emergent app (React/SPA) you want indexed by Google: On. Without it, crawlers see the homepage on every route.
- An app that already server-renders or pre-renders real HTML per route (Next.js SSR/SSG, a committed pre-render build, or similar): Off. You do not need it, and leaving it on adds the limitations below.
- A private app, internal tool, or staging environment with nothing to index: Off.
- You need crawlers to receive your redirects and 404s correctly (site migration, retiring URLs, consolidating duplicates): Off, see "Status codes" below. This is the one case where the toggle can actively work against you.
How to check whether it's on
Request a deep route with a crawler User-Agent and look at the response headers:
curl -sI -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://yourdomain.com/some/deep/route
: On, rendered fresh just now.x-rendered-by: crawler-renderer
: On, served from the pre-render cache.x-rendered-by: crawler-cache- No
header : Off, the crawler gets the same response your visitors get.x-rendered-by
Pre-rendered responses are sent with
cache-control: public, max-age=3600. As a companion check, fetch the same URL without the crawler User-Agent and compare the two <title> tags. If the crawler version shows the correct page title and the plain version shows your homepage title, the layer is doing its job and your app is relying on it.
Limitations to know about
Status codes are not passed through (most important)
When the pre-render layer answers a crawler, it returns
200 OK, even for URLs your app answers with a redirect or an error. So if your origin returns 301 for a moved page, or 404 / 410 for a retired one, a crawler with SEO enabled still sees 200 plus rendered content. Consequences: redirects do not pass ranking signals (Google never sees the 301), and retired pages stay indexed (a 410 crawlers never receive will not remove the URL). If you are migrating a site, consolidating duplicate URLs, or removing pages from the index, turn Enable SEO off for the duration. It is not currently possible to keep pre-rendering while preserving origin status codes.
Per-route meta tags can be captured too early
The renderer waits for the page to settle, then snapshots it. If a route sets its title and meta tags after an async data fetch (for example
<Helmet> behind a loading skeleton), the snapshot can be taken before those tags apply, and the crawler gets your homepage title and canonical on that route. Routes that set meta tags synchronously on render are captured correctly, so the symptom is usually inconsistent across routes. Fix: set each route's <title>, canonical link, and OG tags on first render, outside any data-loading guard; fill in dynamic details once data arrives.
Not every bot is covered
The layer recognises major search and social crawlers. Less common bots, including some AI assistant and research crawlers, are not on the list and get the plain SPA shell even with the toggle on. If a specific crawler needs pre-rendered HTML, contact support with its exact User-Agent string. A validation tool fetching with its own User-Agent may report an empty shell while Googlebot itself is served correctly.
The cache holds for up to 30 days
Pre-rendered pages are cached per URL. Publishing new content does not immediately flush the cached copy for crawlers, and there is no self-serve purge; contact support to clear a cached page (for example a broken page captured during an outage). Turning the toggle off stops cached pages from being served but does not erase them; turning it back on can serve previously cached responses right away.
The toggle is the single source of truth
If support disables the layer during a ticket, switching Enable SEO back on in the Domain tab re-enables it. If your app was configured with SEO deliberately off, leave the toggle alone.
Turning it off safely
If you are turning it off because you have your own pre-rendering, verify your own output is live first (build-time pre-render steps can fail silently while this layer covers for them):
Request deep routes without a crawler
Request 2 to 3 deep routes without a crawler User-Agent.
Check the HTML
Confirm the HTML already contains the correct per-route
<title>, canonical link, and structured data.Only then turn it off
Only if it does, turn the toggle off.
Re-check with a crawler
Both plain and crawler requests should now return the same real content, and
x-rendered-by should be gone.If step 2 returns your homepage title or an empty shell, the platform layer is the only source of per-route content for search engines; turning it off typically loses indexed pages. Fix your own rendering first.
Is this cloaking? Will it hurt my rankings?
No. Cloaking means showing search engines different content to manipulate rankings. Dynamic rendering shows the same content, rendered server-side for clients that cannot run JavaScript well; Google documents it as an accepted workaround. If you are investigating a ranking drop where crawler and browser responses match, check instead for: bot protection challenging Googlebot; broken pages cached during a past outage; or the status-code behaviour above undermining redirects.
Getting help
Contact support with your custom domain and the affected routes, the
curl -I output with and without the crawler User-Agent, and what you expected. Mention if you run your own pre-rendering, are mid-migration needing redirects honoured, or need a specific crawler User-Agent recognised.
