URL Reference
All URL patterns handled by the dispatch and theme workers. Use this as a single reference for routing behavior, debugging unexpected proxies, and understanding which endpoints are available.
Shopify storefront routes
Section titled “Shopify storefront routes”These are the standard storefront URLs that the theme worker can render. Each maps to a base template type via resolveBaseTemplateName().
| URL pattern | Template | Notes |
|---|---|---|
/ | index | Homepage |
/products/{handle} | product | Product detail page |
/collections/{handle}/products/{handle} | product | Product within collection context (SEO URL) |
/collections | list-collections | Collection listing page |
/collections/{handle} | collection | Collection detail page |
/cart | cart | Cart page |
/pages/{handle} | page | Static page |
/blogs/{blog}/{article} | article | Blog article (3+ path segments) |
/blogs/{blog} | blog | Blog listing |
/search | search | Search results |
Any path that doesn’t match the above resolves to index. If the path is not / and resolves to index, the worker treats it as unknown and proxies to Shopify (catches typos, /gift_card/..., /challenge/..., etc.).
Combined / SEO routes
Section titled “Combined / SEO routes”Shopify generates combined URLs for SEO and breadcrumb context. These look like nested resources but always render the “inner” resource.
/collections/{collection}/products/{product}
Renders the product page, not the collection. Shopify uses this pattern so that breadcrumbs can show Collection > Product. The collection handle is in the URL for context only — the product data is loaded from KV using the product handle (4th path segment).
/blogs/{blog}/{article}
Renders the article page, not the blog. Detected by path segment count: 3+ segments under /blogs/ = article, exactly 2 = blog listing. The blog handle identifies which blog the article belongs to.
Tagged collections
Section titled “Tagged collections”/collections/{handle}/{tag} — Shopify renders this as the collection page filtered by tag. Our router classifies it as collection (same as /collections/{handle}) because the tag is just a filter, not a separate resource.
Not currently implemented — tagged collection URLs proxy to Shopify. If we add support, the tag will need to be extracted from pathParts[2] and passed as currentTags to the template context.
Gotcha: A tagged collection URL like /collections/sale/new-arrivals has the same path structure as /collections/{handle}/{subpage}. The router doesn’t distinguish — it’s always collection. This is correct because Shopify treats both the same way.
Query parameter variants
Section titled “Query parameter variants”These don’t affect template resolution (only the pathname matters) but change rendering behavior:
| Parameter | Effect |
|---|---|
?view={suffix} | Overrides template suffix (e.g., ?view=modal → product.modal template) |
?variant={id} | Selects product variant (pre-selects options, updates price) |
?sort_by={key} | Collection sort order |
?filter.*={value} | Collection filtering (Shopify storefront filtering API) |
?page={n} | Pagination |
?q={query} | Search query |
?section_id={id} | Section Rendering API — returns only the named section’s HTML |
?sections={ids} | Proxied to Shopify (multi-section rendering) |
Always-proxied routes (Shopify)
Section titled “Always-proxied routes (Shopify)”These paths are always forwarded to Shopify, never rendered by the theme worker. Classified by classifyRoute().
Prefix matches
Section titled “Prefix matches”| Prefix | Purpose |
|---|---|
/admin | Shopify admin |
/checkout, /checkouts | Checkout flow |
/account | Customer account |
/services | Shopify services |
/apps | Shopify apps |
/.well-known/shopify | Shopify well-known endpoints |
/web-pixels | Shopify web pixels |
/cdn | Shopify CDN |
/password | Store password page |
/policies | Policy pages (privacy, refund, etc.) |
/recommendations | Product recommendations API |
/search/suggest | Search autocomplete API |
Exact matches
Section titled “Exact matches”| Path | Purpose |
|---|---|
/cart.js | Cart AJAX API |
/cart/add.js | Add to cart |
/cart/update.js | Update cart |
/cart/change.js | Change cart item |
/cart/clear.js | Clear cart |
Pattern matches
Section titled “Pattern matches”| Pattern | Purpose |
|---|---|
/cart/*.js | Any cart AJAX endpoint |
*.json (any path) | Shopify data API (e.g., /products/snowboard.json) |
/products/*.js, /collections/*.js | Shopify storefront JS endpoints |
Query parameter bypasses
Section titled “Query parameter bypasses”| Condition | Effect |
|---|---|
?sections={ids} | Multi-section rendering — proxied to Shopify |
?section_id={id} | Single section rendering — rendered by theme worker (not proxied) |
Worker internal routes
Section titled “Worker internal routes”Theme worker
Section titled “Theme worker”| Route | Method | Auth | Purpose |
|---|---|---|---|
/api/cache/purge | POST | Bearer CACHE_PURGE_TOKEN | Purge section cache, KV cache, D1 cache, embed scan state |
/api/diagnostics | GET | None | Returns component registry count |
/lk/sw.js | GET | None | Service worker script |
/lk/{filename} | GET | None | Client assets from R2 (immutable, 1-year cache) |
/localization | POST | None | Country/currency switcher (sets cookie, redirects) |
/__platform/app-block-section | GET | Client middleware | Fetches Shopify app-block HTML, caches to KV |
/__platform/app-block-promote | POST | Bearer debug_token | Promote/demote app blocks for inlining |
/__dev/health | GET | None | Health check ({ ok: true }) |
/__dev/seed | POST | Dev only | Seeds KV + D1 with config/template data |
/__dev/render-sections | GET | Dev only | Dev section rendering API |
/__dev/purge-events | GET | Debug token | Debug bar purge event polling |
All /__dev/* routes return 403 in production (gated by ENVIRONMENT !== "development").
Dispatch worker
Section titled “Dispatch worker”| Route | Method | Auth | Purpose |
|---|---|---|---|
/api/cache/purge | POST | Bearer CACHE_PURGE_TOKEN | Purge dispatch CDN cache, forwards to theme worker |
/cart/{action}.js | POST | None | Cart interception for AB test tracking (when AB enabled) |
/* (catch-all) | ALL | None | CDN cache + AB routing + failover to Shopify |
Debug / bypass parameters
Section titled “Debug / bypass parameters”| Parameter | Scope | Effect |
|---|---|---|
?lk-debug=1 | All layers | Enables debug mode (sets 1-day cookie), adds console output + window.lk API |
?lk-debug=0 | All layers | Disables debug mode (clears cookie) |
?lk-fresh=1 | All layers | Bypasses every cache layer (requires debug mode active) |
Gotchas
Section titled “Gotchas”Browser 301 cache — If a route previously returned a 301 redirect (e.g., proxied to Shopify before the template was enabled), Chrome caches it permanently. Users must clear site data for the domain or use incognito.
Unknown paths render as proxy, not 404 — Paths like /asdfasdf or /gift_card/123 resolve to index in the template mapper, but because the path is not /, the worker detects this as “unknown” and proxies to Shopify rather than rendering a broken homepage.
.json suffix always proxies — Any path ending in .json is routed to Shopify, regardless of template type. This means /products/snowboard.json always returns Shopify’s JSON API, never the rendered product page.
Tagged collections vs nested products — /collections/sale/new-arrivals (tagged collection) and /collections/sale/products/widget (nested product) look similar but route differently. The nested product pattern is detected by checking for a /products/ segment in the path. A tag that literally contains “products” (e.g., /collections/sale/products-on-clearance) does NOT trigger the nested product route because there’s no /products/ followed by another segment.
?section_id vs ?sections — Single section_id is rendered by the theme worker (renders the full page, extracts one section). Plural sections is proxied to Shopify.
D1 cache TTL — Template gating reads from D1 with a 60-second in-memory cache. After updating templates_json, changes propagate globally within 60 seconds without manual purge.
Key files
Section titled “Key files”| Concern | File |
|---|---|
| URL → template mapping | packages/cf-client-site/src/lib/template-resolution.ts |
| Route classification (proxy vs render) | packages/cf-client-site/src/middleware/routes.ts |
| Template gating + worker routing | packages/cf-client-site/src/worker.ts |
| Data loading + template rendering | packages/cf-client-site/src/render/handle-render.ts |
| Dispatch CDN + AB routing | packages/cf-client-dispatch/src/worker.ts |
| Tests | packages/cf-client-site/src/lib/template-resolution.test.ts, packages/cf-client-site/src/middleware/routes.test.ts |