Generate programmatic SEO landing pages for your Shopify store using Cloudflare Workers as a reverse proxy in front of Shopify.
Customer Request → Cloudflare Worker → [/services/*] → Edge-rendered page
→ [everything else] → Shopify origin
Shopify handles your store. Cloudflare handles the programmatic pages. Same domain, seamless experience.
If your Shopify store uses a custom domain:
- Add your domain to Cloudflare (free plan works)
- Update nameservers at your registrar to Cloudflare's
- In Cloudflare DNS, add a CNAME record:
- Name:
@(orwww) - Target:
shops.myshopify.com - Proxy status: Proxied (orange cloud)
- Name:
- Go to Cloudflare Dashboard → Workers & Pages → Create
- Name it
seo-pages-proxy - Deploy the worker code below
Create worker.js:
// Cloudflare Worker: Reverse proxy for programmatic SEO pages
// Routes /services/* and /ecommerce/* to edge-rendered pages
// Everything else passes through to Shopify
const SHOPIFY_ORIGIN = 'your-store.myshopify.com';
// Import your generated edge function
import { onRequest as servicesHandler } from './functions/services/catchall';
import { onRequest as ecommerceHandler } from './functions/ecommerce/catchall';
export default {
async fetch(request, env) {
const url = new URL(request.url);
// Route programmatic pages to edge functions
if (url.pathname.startsWith('/services/')) {
return servicesHandler({ request, env });
}
if (url.pathname.startsWith('/ecommerce/')) {
return ecommerceHandler({ request, env });
}
// Serve sitemap.xml from edge
if (url.pathname === '/sitemap.xml' || url.pathname.startsWith('/sitemaps/')) {
return env.ASSETS.fetch(request);
}
// Everything else → Shopify
const shopifyUrl = new URL(url.pathname + url.search, `https://${SHOPIFY_ORIGIN}`);
const response = await fetch(shopifyUrl.toString(), {
method: request.method,
headers: request.headers,
body: request.body,
});
return new Response(response.body, {
status: response.status,
headers: response.headers,
});
},
};In Cloudflare Dashboard → Workers → Routes:
yourdomain.com/services/* → seo-pages-proxy
yourdomain.com/ecommerce/* → seo-pages-proxy
yourdomain.com/sitemap.xml → seo-pages-proxy
yourdomain.com/sitemaps/* → seo-pages-proxy
If you prefer not to use Cloudflare as a reverse proxy, you can use Shopify's App Proxy feature:
- Create a Shopify app (or use a custom app in your store admin)
- Set up an App Proxy:
- Subpath prefix:
services - Proxy URL:
https://your-cloudflare-pages-project.pages.dev/services/
- Subpath prefix:
- This routes
yourdomain.com/services/*to your Cloudflare Pages project
In config.js, set:
module.exports = {
domain: 'https://yourdomain.com',
brandName: 'Your Shopify Store',
// ... rest of config
};node generate.js
npx wrangler pages deploy . --project-name=my-seo-pagesAdd links in your Shopify theme to your service pages:
<nav>
{{ content_for_header }}
<a href="/services/">Services</a>
<a href="/ecommerce/">Industries</a>
</nav><p>We offer <a href="/services/new-york-ny/plumber/">plumbing services in New York</a>
and <a href="/services/los-angeles-ca/electrician/">electrical services in Los Angeles</a>.</p>Shopify has its own sitemap at /sitemap.xml. Your programmatic pages have a separate sitemap.
Option A: Add your sitemap URL to Google Search Console separately.
Option B: Use the Worker to merge sitemaps:
if (url.pathname === '/sitemap.xml') {
// Return a sitemap index that references both
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap><loc>https://${url.hostname}/shopify-sitemap.xml</loc></sitemap>
<sitemap><loc>https://${url.hostname}/sitemaps/sitemap-services-1.xml</loc></sitemap>
</sitemapindex>`;
return new Response(xml, {
headers: { 'Content-Type': 'application/xml' },
});
}- Shopify's
robots.txtis not editable. Submit your sitemap directly in Google Search Console. - Use consistent internal linking between Shopify pages and programmatic pages for crawl equity.
- Programmatic pages are rendered at the edge (< 50ms) — faster than Shopify's Liquid rendering.