← Insights

Shopify sitemap: what the generated sitemap.xml lists, what it leaves out, and the lastmod it gets wrong

Shopify's sitemap index cannot be edited. What each child lists, what is absent, why every product lastmod is the request time, the locale children, submitting it.

11 min read

Contents — 8 sections

Shopify writes the sitemap for you, and the index is the only URL worth knowing

Every Shopify store answers /sitemap.xml with a sitemap index, not a sitemap. The sitemaps protocol defines the two shapes: a urlset lists pages, a sitemapindex lists other sitemaps, and a single file of either kind may hold up to 50,000 entries and 50 MB uncompressed. Google's page on sitemap index files adds the rule that shapes Shopify's layout: a child sitemap must sit in the same directory as the index or deeper, and the index can be submitted once on behalf of all of them.

Open yours and read the comment at the top. On 17 September 2026 it read the same on Shopify's demo stores for Dawn and Horizon and on a live store with 294 products: "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." Both halves are literally true. No admin field, theme file or Liquid object changes what the index contains; the sitemap Liquid object exists only inside robots.txt.liquid and holds the Sitemap: directive and the URL, nothing more. And the children are generated when requested, which is the fact behind the section on lastmod below.

The index on the Dawn demo store listed nine children, in this order: sitemap_agentic_discovery.xml, then sitemap_products_1.xml, sitemap_pages_1.xml, sitemap_collections_1.xml and sitemap_blogs_1.xml, then the same four again under /en-fr/. The product, page and collection children carry a query string — ?from=6920720777305&to=6920737783897 — that is a range of object IDs, and a child requested without it returns a 400. The child URLs are not addresses to bookmark or submit; they move as objects are created, and the index is the only stable thing. It carries no lastmod per child, which Google's page lists as optional.

Two places point at it. The default robots.txt ends with a single Sitemap: line naming the root index, and Shopify's robots.txt.liquid documentation shows how to add a second if you ever host another file. The managed /agents.md names it too, through the agents.sitemap_url field its template documentation lists; sitemap_agentic_discovery.xml, the first child in the index, is a one-entry sitemap whose only URL is /agents.md. What that file is and is not has its own page.

Each child lists one URL per object, one image per product, and nothing Google ranks on

ChildWhat it listslastmodImage
sitemap_products_1.xmlThe home page first, then one flat /products/handle URL per product published to the Online StoreOn products; absent on the home pageThe featured image only, with image:title and image:caption
sitemap_collections_1.xmlOne /collections/handle per collectionPresentThe collection image, where one is set
sitemap_pages_1.xmlOne /pages/handle per pagePresentNone
sitemap_blogs_1.xmlEach blog, then each articlePresentThe article's featured image
sitemap_metaobject_pages_1.xmlPages rendered from metaobjects, on stores that have anyPresentNone
sitemap_agentic_discovery.xml/agents.mdAbsentNone

Four details from the children are worth having exact.

The home page lives in the products file, first, without lastmod. Google's 2023 post on lastmod says that is the right call for a page that only aggregates others.

Every entry carries changefreq — daily for products and collections, weekly for pages and articles — and no entry carries priority. Google's build-and-submit page says it ignores both.

Each product gets exactly one image. On the Dawn demo store the first product has ten images and the sitemap lists one, and it is the one /products/handle.json returns as image: the featured image. The tags around it are image:loc, image:title and image:caption, and Google's image sitemap reference lists image:title and image:caption among the tags it has removed from its documentation. Google reads the location and nothing else. Your second to tenth images are found by crawling the page, which is the argument for alt text that describes them.

The URL is the flat one. Not one entry on the three stores carried ?variant= or a /collections/x/products/y path. That matches the canonical Shopify writes on every product page, and it is what Google's build page asks for: the canonical URL, not the variants that lead to the same content. On the demo store the products child held 32 products and /products.json returned 32; the Product.onlineStoreUrl field is null for a product not published to the Online Store channel, and a product with no URL has nothing to list.

What is absent is mostly absent on purpose, and the exceptions are yours to check

Everything below returned 200 and appeared in none of the children.

  • /collections/all, /collections and /search. Routes the platform renders without an object behind them. /collections/all.json returns 404 on the demo store because no collection with that handle exists; on the live store one does, and /collections/all is in the collections child. Create a collection with the handle all and the page gets listed; leave it and Google reaches it only by links.
  • Policy pages. /policies/refund-policy returned 200 on the live store and was not in the pages child. Both reference themes link them from the footer, which is enough.
  • Filtered, sorted and paginated views. ?page=2, ?sort_by=, filter parameters, and the vendor and type collections at /collections/vendors?q=. The default robots.txt disallows sorted views and any view carrying two filters, and Google's ecommerce site structure guide says it infers importance from links, not lists. Page two is a link on Dawn and not on Horizon with auto-load on, which is the collection page problem; there the sitemap alone carries the products past the first twenty-four, and the same guide names it as the fallback for products you cannot link.
  • Blog tag pages. /blogs/news/tagged/x is not listed. The live store's blogs child held 82 entries, none with tagged in the path.
  • Variant URLs and collection-scoped product URLs. Both render, both canonicalise to the flat URL, neither is listed.
  • Draft, archived and unpublished products. Shopify's ProductStatus enum says a draft is unavailable on every sales channel, an archived product is no longer sold, and an active product is not automatically published to the Online Store. A product you expect to find and cannot is almost always on the wrong channel. The same enum carries an unlisted status from API version 2025-10 — active, reachable by direct link, hidden from search and collections — and does not say whether an unlisted product is in the sitemap; check yours before assuming.

Google's overview is candid about the file's weight: a sitemap helps discovery, it does not guarantee that a listed URL is crawled or indexed, and a properly linked site of about 500 pages or fewer may not need one. Most stores we open are under that line. The sitemap earns its keep on the products a menu does not reach.

The product lastmod is the time you asked, not the time you edited

Google's build page says it uses lastmod if the value is consistently and verifiably accurate, and the 2023 post is blunter: if a page changed seven years ago and the sitemap says yesterday, "eventually we're not going to believe you anymore". So we read the values. On the Dawn demo store, all 32 products carried the same lastmod, to the second. On the Horizon demo store, all 176. On the live store, all 294. And when we fetched the Dawn child three times at five-second intervals, the shared value moved with us — 09:39:04, 09:39:09, 09:39:14, in the store's time zone. The product lastmod is the request time, stamped on every product.

The other children behave. The collection bags on the demo store carries 2026-09-01T05:13:41-06:00 in the sitemap and the identical updated_at in /collections/bags.json. Pages date to 2021 and 2022, articles to 2022, and the live store's 1,346 collections carried 203 distinct dates. Those are dates a crawler can verify against the page, which is the condition Google sets. The products child is the one Google will learn to distrust, and by its own account it will then ignore the field there.

Even a truthful product value would not be the one Google wants. The Admin API's definition of updatedAt on the Product object says an order placed against a tracked product counts as an update; the 2023 post asks for the last significant change to the primary text, structured data or links. A bestseller's true modification date moves with every sale.

In practice: a price change, a rewritten description or a new schema snippet on a product page is not recrawled sooner because of the sitemap. Google returns at whatever cadence it has settled on for that URL. If a change matters this week, request indexing for that URL in Search Console and link to the product from the home page. The sitemap is not the lever.

Each locale gets its own children, and the alternates stay in the head

Publish a second language or give a market a subfolder, and the index grows by a full set. The Dawn demo store has an English presence in a French market at /en-fr/, so its index lists /en-fr/sitemap_products_1.xml, /en-fr/sitemap_pages_1.xml, /en-fr/sitemap_collections_1.xml and /en-fr/sitemap_blogs_1.xml after the four root children. Each holds the same objects on the locale's paths, with the locale root /en-fr in place of /, without a trailing slash, which is the URL the page's own canonical tag names. There is no /en-fr/sitemap.xml; it returns 404.

Google's localised versions page describes a sitemap method for hreflang — xhtml:link children under each loc, one per variant, not counted towards the URL limit — and Shopify does not use it. No locale child on any store we opened carried an xhtml:link. The alternates are in the HTML head, written from content_for_header, and the same Google page says the three methods are equivalent and that there is no benefit in Search to using more than one. Nothing is missing; Shopify hreflang reads the tags in full.

The rule that does bind is the location rule. Google's page says a sitemap can only contain descendant URLs of the directory it is hosted from; Shopify's /en-fr/ children contain only /en-fr/ URLs, and the root index may reference them because they sit below it. A market on its own domain is a different case: it answers its own /sitemap.xml, its own robots.txt names that one, and Search Console treats it as a separate property to verify and submit. A subfolder market rides under the primary domain's index and needs nothing.

The cost is scale. Every market with a web presence adds a set of children and a locale's worth of URLs, whether or not anyone buys there.

Submit the root index once, then read the report per child

Google's build page lists the ways it learns about a sitemap: the Sitemaps report in Search Console, the Search Console API, and a Sitemap: line in robots.txt. The ping endpoint that older tools still call was retired in the 2023 post and answers 404. Submitting is a hint; it does not guarantee that Google downloads the file or crawls from it.

Shopify has already done the third. The Sitemap: line is in the default robots.txt, so Google finds the index the next time it reads that file, on every store, without anyone submitting anything. The reason to submit in Search Console anyway is the report: when Googlebot last read the index, each child with the number of URLs discovered, and parse errors per child. That per-child count is where you see that the products child holds fewer URLs than the admin counts as active — the difference being products on the wrong channel.

Submit the root index on your primary domain, /sitemap.xml, and nothing else. Not a child, because its query string changes. Not the .myshopify.com address, because once a primary domain is set it redirects there and the property you verified is the primary domain. One index per domain: a market with its own domain gets its own property and its own submission.

Check it in five minutes, from a terminal

With $STORE set to your primary domain including the scheme:

curl -sL "$STORE/sitemap.xml" | grep -o '<loc>[^<]*' | sed 's/<loc>//'

That is the list of children. Then, with $CHILD set to the full URL of the products child, query string included:

curl -sL "$CHILD" > /tmp/products.xml
grep -c '<url>' /tmp/products.xml
grep -c 'variant=' /tmp/products.xml
grep -o '<lastmod>[^<]*' /tmp/products.xml | sort -u | wc -l

Three numbers. The first is products plus one for the home page; if it is lower than the admin's count of active products, the difference is products not published to the Online Store. The second should be zero. The third should be one, which confirms what we found above; if it is not, the platform has changed since 17 September 2026 and this page needs an update.

Then the Sitemaps report in Search Console, and the row for /sitemap.xml. Read the discovered count per child against the numbers above; a child that fails to parse names the line. Submitting changes neither the file nor the crawl, but the report is the only view of the file from Google's side.

Last, robots.txt. Count the Sitemap: lines. One is the default. Two means a custom robots.txt.liquid or an app added one, and the second file is either a duplicate of the first, which does no harm, or a list of URLs the platform's own file would not include, which is worth reading.

In this order, each measurable before the next:

  1. Products missing from the file. Two minutes each. The products child count against the admin; every gap is a product not published to the Online Store, and the fix is the sales channel panel on the product.
  2. Products past the first batch on Horizon. Five minutes: switch off auto-load in the collection template so page two is a link. The sitemap has been carrying those products alone, and a link from the category page is what the site structure guide asks for.
  3. The submission. Ten minutes, once. Root index, primary domain, then read the per-child counts on the day and again a week later.
  4. Markets nobody buys from. An afternoon, and the same afternoon the hreflang page describes. Every retired market removes a set of children from the index and a locale's worth of URLs Google was asked to crawl.
  5. Nothing else. The only field in the products child worth improving is lastmod, and nothing outside the platform knows a product's last significant edit better than the platform that stored it. A second sitemap is a second thing to keep in agreement with the first.

If you would rather have the whole crawl side read for you — sitemap, canonicals, robots, hreflang and the links between them — ranked against everything else the store is leaving on the table, it is the Store Teardown: €750, five days, and the document is yours whatever you decide afterwards.

Own your growth.Start with the teardown.

Start with a Teardown. Read it, then decide whether you want us to fix what it finds.