syted

syted blog

Shopify SEO Friendly URLs: What You Can Actually Edit

Search for "shopify seo friendly urls" in the United States and the page in position one is Shopify's own blog post about URL slugs. It is a competent article about slugs in general. It does not tell you that your store serves the same product at four different addresses, or which of those four Shopify will fix for you.

Below it sit three discussion threads: an r/TechSEO post asking what SEOs think of Shopify's URL structure, a Facebook group question about making Shopify links SEO friendly, and a Quora question asking whether long Shopify URLs are a problem. When forums take the second slot on a commercial query, the ranking articles are not answering the question.

This one is written for the person who runs the store. Everything below was measured on two live Shopify stores on 2026-10-11, with commands you can run against your own. Where Shopify or Google documents the behaviour, the documentation is quoted; where it does not, the measurement stands on its own.

Shopify gives you one editable segment, and keeps the rest

Every URL on a Shopify storefront has a fixed prefix and one part you control. That is the whole model, and most confusion about Shopify URLs comes from not knowing which part is which.

Surface URL shape What you can edit
Product /products/<handle> the handle
Collection /collections/<handle> the handle
Page /pages/<handle> the handle
Blog post /blogs/<blog>/<article> the blog handle and the article handle
Catalog /collections/all nothing
Search /search?q= nothing
Cart and checkout /cart, /checkout nothing

Shopify's SEO overview is explicit about what the admin exposes: "You can edit the title tags, meta descriptions, and URLs for the various pages on your site." It describes the intended hierarchy as "starting from the homepage at the top level, then collections pages below that," with product pages at the bottom.

What it does not say is that the /products/ and /collections/ segments are not yours. You cannot remove them, shorten them, or replace them with a category path of your own design. Advice to build /mens/shoes/wool-runners on Shopify is advice for a different platform.

The same applies to the blog. Shopify serves articles at /blogs/<blog>/<article>, which is two editable segments and a fixed prefix, and the prefix is the reason a Shopify store blog cannot sit at /blog/post-name. That constraint is worth understanding before you decide where the blog lives at all, because the path is one of the few things you cannot negotiate later.

The handle itself is generated once from the title and then stops following it. That mechanism has its own failure modes, and how Shopify builds the handle from the product title covers them. This article is about everything around the handle.

What the pages ranking for this query leave out

Ahrefs returned ten positions for this keyword in the US on 2026-10-11. Five were dedicated articles, all predicted as /Article/Tutorial_or_Guide, with no service pages in the set. There was no AI Overview.

Position Page DR US traffic
1 shopify.com/blog/seo-url 96 208
2 r/TechSEO thread n/a n/a
4 praella.com guide 64 16
5 r/SEO thread 95 14
6 tinyseo.com 72 78
8 candidinfo.com 27 7
10 gempages.net 79 55

Reading all of them produced one shared gap. Not one contains a command, a status code, or a measurement taken against a live store. The praella guide at position four runs about 850 words and names a paid app, which is the usual answer and rarely the one the measurement supports. The tinyseo page at six is the most accurate of the set and still asserts that both product URL shapes resolve with a canonical pointing at /products/, which is true on one of the two stores measured here and not the other.

The position-one page is the most interesting absence. It ranks for this keyword while being about slugs generically, and its Shopify-specific FAQ answer is three sentences long. The parent topic Ahrefs assigns to the keyword is url seo, which is the same observation from the other direction: the page winning this query is known for something broader.

The same product, four URL shapes, three different answers

A single product on a Shopify store is reachable at more addresses than you created. Here is the measurement on deathwishcoffee.com, one product, four shapes:

for u in \
  "/products/death-wish-coffee" \
  "/collections/coffee/products/death-wish-coffee" \
  "/collections/all/products/death-wish-coffee" \
  "/collections/nope-not-a-collection/products/death-wish-coffee" ; do
  echo "=== $u"
  curl -sI "https://www.deathwishcoffee.com$u" | grep -iE "^(HTTP/2 [0-9]|location)"
  curl -s "https://www.deathwishcoffee.com$u" \
    | grep -oiE "<link[^>]{0,160}canonical[^>]{0,160}>" | head -1
  sleep 5
done

The four answers, measured 2026-10-11:

Shape Status Canonical
/products/<handle> 200 itself
/collections/coffee/products/<handle> 200 /products/<handle>
/collections/all/products/<handle> 301 redirects to /products/<handle>
/collections/<nonexistent>/products/<handle> 301 redirects to /products/<handle>

Three different mechanisms for four addresses that name one product. A real collection in the path gets a 200 and a cross-canonical. The pseudo-collection all gets a 301. A collection handle that does not exist at all gets a 301 as well, which means the invented path is quietly repaired rather than returning a 404.

Shopify built this on purpose and documents the consequence. The Liquid within filter "Generates a product URL within the context of the provided collection," and the same page warns that the standard product page and the in-collection page "have the same content on separate URLs," so you "should consider the SEO implications." That is the platform telling you it ships a duplicate and handing you the decision.

The sleep 5 in the loop is not decoration. Probing these paths back to back returned 429 on the third request during this measurement, which is the same rate limiter that shows up when probing tag URLs. Space the requests out or you will measure Shopify's throttle instead of your store.

One practical note for anyone scripting this: Shopify renders the canonical with single quotes, as <link rel='canonical' href='...'>. A grep written for double quotes returns nothing and looks exactly like a missing canonical.

The obvious assumption is that collection-scoped product URLs only exist if your theme generates them. That assumption is wrong, and it is worth a measurement because it changes what you need to check.

The collection page on deathwishcoffee.com was fetched and its outbound product links counted:

curl -s "https://www.deathwishcoffee.com/collections/coffee" -o coll.html
grep -coE 'collections/[a-z0-9-]+/products/' coll.html   # 0
grep -oE 'href="/products/[^"]*"' coll.html | wc -l      # 26

Twenty-six bare product links, zero collection-scoped ones. The theme does not use the within filter anywhere on that page, and yet /collections/coffee/products/death-wish-coffee still answers 200 with a full product page on it.

So the duplicate is a routing property of the platform, not an output of your theme. Nothing on the store links to it, nothing in the store's robots.txt blocks it, and it is not in the sitemap. It becomes a live crawlable page the moment anyone links to it: a supplier page, an old affiliate post, a Reddit comment, or a previous version of your own theme.

That is why the canonical matters more here than in the usual duplicate-content discussion. It is the only thing standing between an externally linked path and a second indexed copy of your product page, and Google calls rel="canonical" "A strong signal that the specified URL should become canonical" rather than an instruction it must obey.

The place this surfaces is the Page Indexing report. "Alternate page with proper canonical tag" is the outcome you want, and Google's own description is reassuring: "This page correctly points to the canonical page, which is indexed, so there is nothing you need to do." The one to look for instead is "Duplicate, Google chose different canonical than user," which means "Google thinks another URL makes a better canonical." Finding collection-scoped paths under that reason string is the signal that the duplicate won.

The redirect tool refuses exactly the URLs you most want to redirect

Having found the duplicates, the natural next step is to redirect them. Shopify has a redirect tool built into the admin, under Content then Menus then URL Redirects, and it will not do this job.

Two documented limits explain why. The first: "You can redirect only from broken URLs." The help page spells out the failure mode, which is that "If the URL still loads a valid webpage, then the URL redirect won't work." A collection-scoped product URL loads a valid page, so it is not eligible.

The second limit is more direct. Shopify lists the paths that cannot be redirected at all:

  • Prefixes: /apps, /application, /cart, /carts, /orders, /services, /shop
  • Fixed Shopify paths: /products, /collections, /collections/all
  • Reserved paths: /collections/vendors, /collections/types, /apps/, /a/, /community/, /tools/

Every duplicate shape measured in the previous section begins with /collections. The tool is excluded from the problem by its own rules.

What the redirect tool is genuinely for is handle changes, which is the case where it works well and where skipping it is expensive. Change a product or collection handle and the old address becomes a 404, which is precisely the state the tool requires. The limit is 100,000 redirects on a standard plan and 20,000,000 on Plus, so the ceiling is not what will stop you.

Two operational details worth knowing before a migration. Redirects can be imported and exported as CSV from the URL Redirects list, which is the only sane way to handle more than a dozen. And Shopify warns that browsers and search engines cache 301s, so deleting a redirect does not take effect for customers immediately.

What Shopify handles for you, and the one case where it cannot

Not every URL variant is a problem. Several are handled automatically, and knowing which saves you from auditing things that are already fine.

Measured on deathwishcoffee.com, 2026-10-11:

URL Status Canonical
/products/<handle>?variant=39577099239479 200 /products/<handle>
/collections/coffee?sort_by=best-selling 200 /collections/coffee
/products/<handle>/ (trailing slash) 200 /products/<handle>
/Products/Death-Wish-Coffee (capitals) 404 /404
/collections/all 200 itself

The variant parameter is cross-canonicalled to the bare product URL, which matches what Google asks for and means the variant question on a Shopify store is already answered by the platform.

The trailing slash is the one that surprises people. There is no redirect: both /products/handle and /products/handle/ return 200, and only the canonical distinguishes them. Capitals, by contrast, hard 404, and the 404 page carries a canonical pointing at /404 rather than at itself.

Then there is the sort parameter, which is where two mechanisms collide. The URL is cross-canonicalled to the clean collection, and the default robots.txt also carries Disallow: /collections/*sort_by*. Google's duplicate-URL guidance is blunt about that combination: "Don't use the robots.txt file for canonicalization purposes," and "Google may still index URLs that are disallowed in robots.txt without their content." A crawler that obeys the disallow never fetches the page and therefore never reads the canonical you put on it. Belt and braces, in this one case, means the braces are never seen.

The sitemap you cannot edit, and the empty files inside it

Shopify generates your sitemap and says so in a comment inside the file itself: "This is the parent sitemap linking to additional sitemaps for products, collections and pages as shown below. The sitemap can not be edited manually, but is kept up to date in real time."

That second clause is the one to sit with. You cannot remove an entry. Here is what the index actually contained on allbirds.com:

curl -s https://www.allbirds.com/sitemap.xml -o ab.xml
grep -c "<loc>" ab.xml        # 174
grep -c "metaobject" ab.xml   # 167

Of 174 sitemaps listed in the index, 167 are sitemap_metaobject_pages_N.xml. Three of them were sampled at random, numbers 1, 50 and 167. All three returned HTTP 200 with a body of 172 bytes containing an empty <urlset> element and nothing else.

This is not one store's quirk. deathwishcoffee.com's index carries 62 entries, 55 of them metaobject page sitemaps. On both stores, the large majority of the sitemap index points at files with no URLs in them, and on both stores the owner has no way to prune it.

The index also returns something newer. sitemap_agentic_discovery.xml contains exactly one URL, /agents.md, with changefreq weekly, which is Shopify advertising a machine-readable file to crawlers through the sitemap. What that file is and what Shopify puts in it is a separate matter, but the sitemap entry is new and it is generated whether you asked for it or not.

One more finding came out of reading the collections sitemap. The first entry on allbirds.com is /collections/shoes, and that URL returned HTTP 500 on two separate attempts spaced twelve seconds apart. A server error on a collection page, declared in a sitemap that is "kept up to date in real time" and cannot be edited, is a good illustration of why the sitemap is a reporting surface rather than a lever. Running the same check on your own store takes one command per URL and is the cheapest item on an ecommerce SEO audit.

robots.txt is the one file you can edit, which is why it breaks

Shopify lets you override robots.txt through robots.txt.liquid in the theme. It is the only crawl-control file on the platform that is genuinely yours, and both measured stores show what happens next.

The first discovery is that there is no single Shopify default. The User-agent: * block differs substantially between the two stores. deathwishcoffee.com serves 116 lines organised under comment headings, including one that did not exist in older defaults:

# AJAX surfaces: agents should use UCP/MCP instead
Disallow: /cart.js
Disallow: /*/cart.js
Disallow: /recommendations/products

Shopify is now writing crawl rules addressed at AI agents and explaining itself in a comment. If you copied a "Shopify robots.txt" from a blog post, you copied a snapshot of a file that has since changed.

allbirds.com serves 163 lines across seven user-agent blocks, with named rules for AhrefsBot, AhrefsSiteAudit, Nutch, MJ12bot and Pinterest. It also carries three defects, all of them consequences of hand-editing:

  • Line 46 contains two directives glued together. It ends ...-remoteDisallow: /collections/*-loop, with no newline between them. The intended /collections/*-loop rule does not exist as far as any parser is concerned, and the rule it is attached to is corrupted.
  • Lines 47 to 49 are indented. Three Disallow: lines begin with four spaces.
  • The Sitemap: directive is glued onto the end of a Disallow: line in two blocks, at lines 113 and 158. One valid standalone Sitemap: line survives at line 50, so the sitemap is still declared, but two of the three declarations are inside a disallow value.

This is a DR 96 store. The lesson is not that someone was careless; it is that the one file Shopify hands you is the one place where a missing newline silently deletes a rule. Diff your rendered robots.txt against the default before and after any edit, and read the result rather than the Liquid.

Worth noting what differs beyond the defects. allbirds disallows /search and /policies/; deathwishcoffee disallows neither. Both block the filter and sort traps. Neither blocks /collections/*/products/* in general, which is consistent with the measurement above: the duplicate path is left to the canonical.

Market prefixes give every URL a second address

If you sell into more than one market or language, Shopify adds a path prefix, and that prefix multiplies every URL shape in this article. The default robots.txt already anticipates it: almost every rule appears twice, once as /collections/... and once as /*/collections/....

On allbirds.com the prefixed paths are live and they do not behave like the unprefixed ones. /en-ca/products/mens-wool-runners returned a 301 to /en-ca/collections/mens, and /fr/products/mens-wool-runners returned a 301 to /fr/collections/mens. The product path exists in both markets and resolves to a collection rather than to the equivalent product, which is what a store does when an item is not sold in that market.

That is a reasonable behaviour and a redirect you did not write. Before assuming your market URLs mirror your primary ones, run the same four-shape test with the prefix in place. Shopify also notes that a resource's handle can differ per language, so any hreflang implementation that hardcodes handles will drift.

What to check on your own store, in order

Everything above reduces to a short sequence. It costs a few minutes and no tooling beyond curl and Search Console.

  1. Pick one product and run the four shapes. Use the loop from earlier in this article, with the sleep. You are looking for which shapes 200, which 301, and whether every 200 carries a canonical pointing at the bare /products/ URL.
  2. Grep your collection template for within. If your theme generates collection-scoped product links, you are feeding the duplicate internally, and that is a theme fix rather than a redirect.
  3. Open Page Indexing and filter by /collections/. "Alternate page with proper canonical tag" is fine. "Duplicate, Google chose different canonical than user" on a collection-scoped path means the duplicate is winning, and the next step is reading the reason strings properly.
  4. Fetch your own robots.txt and count lines and user-agent blocks. If anyone has touched robots.txt.liquid, look for glued directives and leading whitespace before you look for anything clever.
  5. Walk the first page of your products and collections sitemaps with curl -sI. Any status other than a single 200 on a URL Shopify declared is a finding, and you cannot fix it by editing the sitemap. Record the output somewhere, because this list is the spine of any later content audit on the store.
  6. Before changing any handle, create the redirect first. The old URL has to be broken for the tool to accept it, so the order is: change the handle, confirm the 404, add the redirect, confirm the 301.

What none of this does is move you up the results page by itself. URL hygiene removes a way to lose, which is not the same as a way to win, and no one can guarantee a ranking outcome from a URL change. Google's own guidance on URLs is modest in exactly this way: it recommends "a simple URL structure" and says "the words in URLs may help Google better understand the page." Helping Google understand a page is a long way from a position.

The reason to do it anyway is that the alternative is unbounded. A store with unresolved duplicate paths, a hand-broken robots.txt and 500s in its sitemap spends its crawl budget on copies of itself, and every new product inherits the same shape. Fixing the shape once means the next hundred products arrive clean, which is the point at which the content you publish starts compounding instead of competing with the catalog.

FAQ

Which URL is SEO friendly?

The one a person can read and guess the content of before clicking. Google's URL structure guidance asks for "a simple URL structure" and recommends you "use readable words rather than long ID numbers in your URLs," with words "in your audience's language." On Shopify that means the handle carries the product's real name in lowercase with hyphens, because the prefix in front of it is not yours to optimise. /products/cold-brew-concentrate is as friendly as a Shopify product URL gets.

What is the best URL structure for SEO?

Shallow, stable and descriptive, in that order of importance. Shallow because Google warns that "Overly complex URLs, especially those containing multiple parameters, can cause problems for crawlers." Stable because every change costs you a redirect and the authority that flowed through the old address. Descriptive because the words help, modestly. On Shopify you only control the last segment, so "best structure" collapses into "a good handle you never have to change."

Is Shopify SEO friendly?

For URLs specifically, it is adequate and opinionated. It fixes the prefixes and refuses nested categories, which costs you flexibility, and in exchange it cross-canonicals variant parameters, sort parameters and collection-scoped product paths without you configuring anything. The real weak spots measured here are a sitemap you cannot prune, a redirect tool that excludes the fixed paths, and a robots.txt that is easy to break by hand.

Can you remove /products/ or /collections/ from a Shopify URL?

No. They are fixed path segments, and Shopify's redirect documentation lists /products, /collections and /collections/all among the "fixed Shopify paths" that cannot even be redirected. Any guide showing you a Shopify store serving /mens/shoes/wool-runners is either describing a headless build on a different frontend or describing another platform.

How do I create a URL redirect in Shopify?

In the admin, go to Content, then Menus, then View URL Redirects, then Create URL redirect. Put the old address in "Redirect from" and the new one in "Redirect to," and it takes effect immediately. The one condition that catches people is that the source has to be broken already: "You can redirect only from broken URLs," and "If the URL still loads a valid webpage, then the URL redirect won't work." For bulk work, import a CSV from the same screen.

Does changing a collection handle break the product URLs inside it?

No, because the canonical product URL never contained the collection handle. /products/<handle> is unaffected by anything you do to collections. What does break is any collection-scoped link anyone built to /collections/<old-handle>/products/<product>, and since that path begins with /collections, you cannot redirect it. Pick collection handles you can live with, and check for inbound links to the old nested shape before renaming.

Get cited by ChatGPT. Rank on Google.

You found this article through search. That is the whole product.

  • One researched article a day
  • Published on your own domain
  • Keywords checked against live results
Start writing

Get cited by ChatGPT. Rank on Google.

You found this article through search. That is the whole product.

  • One researched article a day
  • Published on your own domain
  • Keywords checked against live results
Start writing