Pre-rendering for BigCommerce through Cloudflare
How BigCommerce pre-rendering works#
BigCommerce manages store hostnames through its own Cloudflare account (Cloudflare for SaaS). With BigCommerce's default DNS instructions, requests are handed straight to BigCommerce and never reach your Worker. A proxied CNAME in your own Cloudflare zone puts the Worker back in the path.
Crawler GET requests for HTML receive the rendered snapshot from Encited. Browser visits, assets, and any failed render calls continue through Cloudflare to BigCommerce unchanged.
Prerequisites#
- An Encited account and API key (Settings → API Keys).
- Your store's custom domain with DNS managed in a Cloudflare account (any plan).
- Your store served on www or a subdomain, not the bare apex domain.
Set up pre-rendering for BigCommerce#
1. Point your DNS at BigCommerce with a proxied CNAME#
In your Cloudflare zone, the store hostname (www or a subdomain) must be a CNAME to shops.mybigcommerce.com, set to Proxied (orange cloud). Cloudflare then routes traffic through your zone first, so your Worker runs before BigCommerce serves the page.
This only works for www and subdomains; an A record on the apex bypasses your Worker. If your store runs on the apex domain, redirect the apex to www and attach the Worker route to www.
2. Create a new Worker#
Open Cloudflare dashboard → choose a "Hello World" Worker → Deploy → Edit Code
3. Paste the snippet below into the Worker editor#
encited
// encited.js (Cloudflare Worker)
export default {
async fetch(req, env) {
// Only handle public GET navigations
if (req.method !== 'GET') return fetch(req);
// Treat missing/empty Accept and bare '*/*' as HTML so crawler tests
// (curl without -H, default fetch) still route through prerender.
// Asset requests from browsers send specific Accept (e.g. 'text/css,*/*;q=0.1')
// so they won't match.
const accept = (req.headers.get('accept') || '').trim();
const isHtmlRequest = !accept || accept === '*/*' || accept.includes('text/html');
if (!isHtmlRequest) return fetch(req);
const headers = new Headers();
// Add LOVABLEHTML_API_KEY as a secret: Worker -> Settings -> Variables and Secrets.
headers.set('x-lovablehtml-api-key', env.LOVABLEHTML_API_KEY);
headers.set('accept', 'text/html');
const forward = [
'accept-language',
'sec-fetch-mode',
'sec-fetch-site',
'sec-fetch-dest',
'sec-fetch-user',
'upgrade-insecure-requests',
'referer',
'user-agent',
];
for (const name of forward) {
const v = req.headers.get(name);
if (v) headers.set(name, v);
}
try {
const r = await fetch(
'https://encited.com/api/prerender/render?url=' + encodeURIComponent(req.url),
{ headers, redirect: 'manual' },
);
// 301 = configured redirect rule matched - forward to client
if (r.status === 301) {
const loc = r.headers.get('location');
if (loc) {
return new Response(null, {
status: 301,
headers: { location: loc, 'cache-control': 'no-store' },
});
}
}
// 304 = not pre-rendered, pass through to origin
if (r.status === 304) {
return fetch(req);
}
if (r.status === 200 && (r.headers.get('content-type') || '').includes('text/html')) {
const responseHeaders = new Headers(r.headers);
for (const name of ['content-encoding', 'content-length', 'transfer-encoding', 'connection', 'keep-alive']) {
responseHeaders.delete(name);
}
responseHeaders.set('content-type', 'text/html; charset=utf-8');
return new Response(r.body, { status: 200, headers: responseHeaders });
}
} catch {
// Prerender unreachable → fall through so visitors still get the site
}
return fetch(req);
},
};
4. Add a route to your Worker#
Go to your Worker → Settings → Domains & Routes → Add Route → enter www.yourdomain.com/*. If your site is reachable on both yourdomain.com and www.yourdomain.com, enter *yourdomain.com/* instead so both are covered.
5. Deploy the Worker#
It can take a couple of minutes to start working.
Common mistakes
- DNS record on the gray cloud. Routes only fire on proxied traffic. In DNS → Records, the A or CNAME record for
www.yourdomain.commust show the orange cloud (Proxied), not gray (DNS only). - Failure mode left on the default. Set the route's Failure mode to Fail open (proceed) so a Worker error sends requests straight to your origin instead of failing.
- Bot Fight Mode blocking crawlers. Bot Fight Mode and AI crawler blocking (Security → Bots) run before your Worker, so a blocked crawler never reaches it. Allow the crawlers you want pre-rendered.
Test the integration#
1. Send a crawler request
curl -sS -D - -o /dev/null \
-A "Googlebot" \
-H "Accept: text/html" \
"https://your-domain.com/"
Look for a successful HTML response and the x-lovablehtml-render-cache header.
2. Confirm browser passthrough
curl -sS -D - -o /dev/null \
-A "Mozilla/5.0" \
-H "Accept: text/html" \
-H "Accept-Language: en-US" \
-H "Sec-Fetch-Mode: navigate" \
-H "Sec-Fetch-Dest: document" \
-H "Upgrade-Insecure-Requests: 1" \
"https://your-domain.com/"
This request should come back from BigCommerce without an Encited render-cache header.
Common errors#
The render-cache header never appears
The DNS record is usually still an A record or not proxied, so traffic skips your zone. The store hostname must be a CNAME to shops.mybigcommerce.com set to Proxied (orange cloud).
The store runs on the apex domain
An A record on the apex bypasses your Worker. Redirect the apex to www and attach the Worker route to www instead.
Crawler requests return errors instead of rendered HTML
Confirm the Worker has a secret named LOVABLEHTML_API_KEY with a valid API key from your Encited dashboard, then redeploy the Worker.
Request and security behavior#
- Only crawler GET requests for public HTML pages are answered with pre-rendered snapshots.
- Along with the public page URL, only the API key and crawler-classification headers are sent to Encited.
- Cookie and Authorization headers are never forwarded to Encited.
- If Encited is unavailable or does not return rendered HTML, the request continues to BigCommerce unchanged.
If your zone runs bot protection or rate limiting, those rules block us before the Worker route helps. Set a render token and add the Cloudflare rule so renders and audit crawls get through.
Common questions#
Why doesn't the standard Cloudflare setup work for BigCommerce?#
BigCommerce uses Cloudflare for SaaS, so with its default DNS instructions Cloudflare hands requests directly to BigCommerce and your Worker never runs even with a route attached. The proxied CNAME routes traffic through your own zone first.
Does this work on the free Cloudflare plan?#
Yes. The proxied CNAME plus a Worker route works on any Cloudflare plan.
Does this affect checkout?#
No. Only crawler requests for HTML pages get pre-rendered snapshots. All browser traffic continues to BigCommerce unchanged.
