Mastering Shopify URL Prefixes: A Cloudflare Worker Deep Dive for Multilingual Stores

Hey everyone! As a Shopify migration expert, I often see store owners grappling with the nuances of internationalization. One of the most common questions, especially for those in non-English speaking markets, revolves around customizing Shopify's core URL prefixes. You know, those standard bits like /products, /collections, or /pages that Shopify uses by default.

Recently, a fantastic discussion popped up in the Shopify community, initiated by Kostas (venomkv13), who was looking to translate these prefixes into Greek for his e-shop. He wanted /collections to become /συλλογές, for instance, and had started down the path of using a Cloudflare Worker. This is a brilliant example of a common challenge, and the community really rallied to provide some deep insights.

The Shopify URL Prefix Challenge: Why It's Tricky

First off, let's address the elephant in the room: Shopify doesn't natively offer an option to change these core URL prefixes. As Hardeep and clawmama pointed out in the thread, this is due to Shopify's fundamental URL routing system. So, if you're aiming for a fully localized URL structure where even /products is translated, you're venturing into custom development territory.

Kostas's idea of using a Cloudflare Worker is indeed the most common workaround for this. A Worker essentially acts as a proxy, intercepting requests to your domain before they reach Shopify, and then modifying them. But as the community discussion revealed, it's not as simple as just dropping in a bit of code.

The Cloudflare Worker Approach: Getting the Direction Right

Kostas shared his initial Worker code, which looked something like this:

export default {
  async fetch(request) {
    const url = new URL(request.url);

    const routes = {
      "/products": "/προϊόντα",
      "/collections": "/συλλογές",
      "/pages": "/σελίδες",
      "/blogs": "/ιστολόγιο",
      "/articles": "/αρθρά"
    };

    for (const [el, en] of Object.entries(routes)) {
      if (
        url.pathname === el ||
        url.pathname.startsWith(el + "/")
      ) {
        url.pathname = url.pathname.replace(el, en);
        return fetch(new Request(url.toString(), request));
      }
    }

    return fetch(request);
  }
};

The core issue, as both VikashJ and clawmama quickly identified, was that the mapping was running in the opposite direction. Kostas's code was trying to convert English paths to Greek paths *before* sending them to Shopify. But Shopify only understands its native English prefixes. What's actually needed is for the Worker to intercept a *Greek* URL (e.g., /συλλογές/my-product) from a visitor, convert it internally to the *English* equivalent (/collections/my-product), and *then* send that to Shopify.

VikashJ provided a corrected version of the Worker code that handles this crucial reversal:

export default {
  async fetch(request) {
    const url = new URL(request.url);
    const routes = {
      "/προϊόντα": "/products",
      "/συλλογές": "/collections",
      "/σελίδες": "/pages",
      "/ιστολόγιο": "/blogs",
      "/αρθρά": "/articles"
    };

    for (const [gr, en] of Object.entries(routes)) {
      if (url.pathname === gr || url.pathname.startsWith(gr + "/")) {
        url.pathname = url.pathname.replace(gr, en);
        return fetch(new Request(url.toString(), request));
      }
    }
    return fetch(request);
  }
};

This code correctly takes an incoming Greek URL segment (like /συλλογές) and rewrites it to its English counterpart (/collections) before forwarding the request to Shopify. This is the first, critical step.

Beyond the Request: Rewriting Shopify's HTML Output

However, as VikashJ and clawmama both emphasized, simply rewriting the incoming request isn't enough for a truly localized experience. Shopify's response HTML will still contain internal links, navigation menus, canonical tags, and pagination links that use the original English prefixes (e.g., /products). If a visitor lands on your Greek URL and then clicks any internal link, they'll be bounced right back to an English path, which isn't ideal for user experience or SEO.

To fully localize, your Cloudflare Worker needs a second stage: it must intercept the HTML response from Shopify and rewrite all matching href attributes before sending the HTML back to the browser. This requires using Cloudflare's native HTMLRewriter feature, which adds another layer of complexity to your Worker setup.

Essential Cloudflare Worker Setup Checklist

Before any of this code can work, the infrastructure needs to be correctly wired up. Steve and Hardeep provided a great checklist:

  1. Worker Route: Ensure your Worker is attached to the correct route, typically yourdomain.com/*, to catch all relevant traffic.
  2. DNS Record: In Cloudflare, your domain's DNS record for Shopify must be set to Proxied (orange cloud), not DNS-only. This ensures traffic flows through Cloudflare's network and, critically, through your Worker.
  3. Verify Worker Trigger: Add a temporary console.log or return a test header within your Worker to confirm that requests are actually hitting it. This helps debug if the Worker isn't being applied at all.
  4. Custom Domain: Confirm you're using a Custom Domain for the Worker, not just a deployed Worker without a route.

Weighing the Alternatives: Shopify Markets vs. Custom Proxies

While a Cloudflare Worker can achieve this URL localization, it's important to consider the long-term implications and alternatives. As clawmama and VikashJ wisely noted, a full proxy solution like this becomes your team's permanent responsibility. Every time your theme changes, or you add new apps, or Shopify updates its routing, you'll need to regression test and potentially update your Worker. This includes handling:

  • HTML link rewriting (as discussed)
  • Canonical tags
  • Redirects
  • Cart and checkout transitions (these can be particularly tricky as they often involve different subdomains or third-party scripts)
  • App routes
  • Sitemaps

For many merchants, especially those just starting their journey with Shopify, the maintenance burden can outweigh the benefits of fully localized prefixes. Hardeep and clawmama both suggested considering Shopify Markets. Shopify Markets provides a native solution for multilingual content, allowing you to offer your store in multiple languages and currencies. While it keeps the fixed English URL prefixes (e.g., /collections), it handles content translation, currency conversion, and international SEO much more seamlessly with less custom development overhead.

Another, more radical alternative mentioned is building a headless storefront. This gives you complete control over every route and every piece of content, but it's a significant undertaking, requiring a dedicated development team and much higher initial investment.

Ultimately, the decision comes down to your specific business needs, technical resources, and long-term vision. If fully localized URL prefixes are a critical business requirement and you have the technical expertise to maintain a robust Cloudflare Worker setup (including the necessary HTML rewriting), then it's a viable path. Otherwise, leveraging Shopify Markets for content localization while accepting the fixed URL prefixes might be a more sustainable and less complex solution for your international growth.

It's great to see the community diving into these complex issues and sharing such detailed, actionable advice. This kind of collaborative problem-solving is what makes the Shopify ecosystem so powerful!

Share:

Use cases

Explore use cases

Agencies, store owners, enterprise — find the migration path that fits.

Explore use cases