Common

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:

1

A request arrives

The platform checks the request's User-Agent.

2

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.

3

The crawler gets real HTML

It receives that rendered HTML, with real per-route titles, meta tags, and structured data, instead of the shell.

4

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:

Bash
curl -sI -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://yourdomain.com/some/deep/route
  • x-rendered-by: crawler-renderer
    : On, rendered fresh just now.
  • x-rendered-by: crawler-cache
    : On, served from the pre-render cache.
  • No
    x-rendered-by
    header : Off, the crawler gets the same response your visitors get.

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):

1

Request deep routes without a crawler

Request 2 to 3 deep routes without a crawler User-Agent.

2

Check the HTML

Confirm the HTML already contains the correct per-route

<title>
, canonical link, and structured data.

3

Only then turn it off

Only if it does, turn the toggle off.

4

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.

Was this page helpful?

Related pages