Schema markup for category pages: what belongs and what does not

Schema markup for category pages should describe the page as a listing, not as the things it lists. That means CollectionPage for the page type, an ItemList pointing to each product or post URL, and a BreadcrumbList. Product, Article and AggregateRating markup belong on the individual pages, not on the category. This guide explains why, gives three copy-paste JSON-LD examples, and shows how to validate the result.

Schema markup for category pages is a CollectionPage type, an ItemList of the pages it shows, and a BreadcrumbList. Nothing else. The mistake I see on most Indian Shopify and WooCommerce stores is the opposite: a theme or plugin stamps full Product markup, with prices and star ratings, onto a page that lists forty products. Google treats that as markup describing content that is not there, and at best ignores it, at worst files it under misleading structured data. This guide covers what to add, what to strip, and how to check the outcome.

I work on category pages more often than product pages, because for a small store or a clinic with several services, the category is usually the page that ranks for the money keyword. "Ayurvedic hair oil" lands on a collection, not on one bottle. Getting the structured data right on that collection is a small job that removes a whole class of Search Console warnings and makes it obvious to Google what the page is for. If you are new to structured data in general, start with my beginner's guide to schema markup and come back here for the category-specific rules.

What schema markup for category pages actually does

Start with the honest limitation. CollectionPage and ItemList do not produce a visible rich result in Google Search. There is no star, no carousel, no price shown under the blue link because you added them. If a plugin or an agency promises a rich snippet for your category page from this markup, they are wrong.

What the markup does is label the page correctly. Google's systems already try to work out whether a URL is a product, an article, a listing or a homepage. Structured data removes the guesswork. A page typed as CollectionPage with an ItemList of forty product URLs is unambiguous. That has three practical effects that I have seen on client sites.

First, discovery. The ItemList hands Google a clean set of child URLs with their order. On a store where the product grid is loaded by JavaScript, this is sometimes the most reliable list of product links Google gets from the page. If you have read my post on how crawling works, you will know that anything that makes URL discovery easier is worth doing on a small site with a limited crawl allowance.

Second, fewer false positives. Themes that inject Product markup on listing pages create "Product" items in Search Console that have no matching product page, and those show up as errors or warnings under Enhancements. Replacing that with CollectionPage clears the report.

Third, cleaner entity signals. When every listing on your site is marked as a listing and every item as an item, Google's picture of your site structure matches your internal linking and your breadcrumbs. Consistency across those three is what I aim for on every audit.

The four schema types that belong on a category page

Four types cover almost every category, collection, archive or tag page you will ever build. Use them together in separate script blocks or nested inside one graph. I prefer separate blocks because they are easier to debug in the validator.

CollectionPage

This is the page type. It is a subtype of WebPage, so anything valid on WebPage is valid here: name, description, url, and isPartOf pointing at your WebSite. Keep the name identical to the visible H1. Keep the description close to the meta description. Do not describe products inside CollectionPage; that is what the ItemList is for.

ItemList with ListItem entries

The ItemList is the heart of category page schema. Each ListItem carries a position, a name and a url. The url must be the absolute canonical URL of the child page, not a relative path and not a tracking URL. The order must match the order on the page. The set must match the set on the page. If your category shows 24 products and the ItemList shows 200, you have told Google the page contains things it does not contain.

You can set itemListOrder to ItemListOrderAscending for a fixed order or ItemListUnordered for a grid the user can re-sort. For most stores I use Ascending and let it mirror the default sort. Add numberOfItems so the count is explicit.

BreadcrumbList

The breadcrumb is the one part of category page markup that can affect how the page looks in results, because Google may show the breadcrumb path in place of the raw URL. Mirror your visible breadcrumb exactly. Home at position 1, the parent category if there is one, then the current category as the last item. Positions are integers starting at 1 and the item field holds the absolute URL.

WebPage and isPartOf

If you already output a WebSite schema sitewide, add isPartOf on the CollectionPage pointing to it. It is a small thing that ties the page to the site entity. If your site has a SearchAction on the WebSite type, that is where it stays; do not repeat it on the category page.

What must not go on a category page

This section is the reason the post exists. Three types show up on category pages constantly, and all three are wrong there.

Product with offers, price or rating

Google's Product structured data documentation is explicit that Product markup is for pages focused on a single product. A category page is not focused on a single product. When a theme loops through the grid and emits a Product block with price and availability for every card, you get a page whose markup claims to be forty products at once. In Search Console this appears as Product items with missing fields, or as an "unparsable" warning, and in the worst cases as a manual action for misleading structured data. I removed exactly this from a Pune furniture store's WooCommerce theme last year and the Product error count in their Enhancements report dropped from a few hundred to zero within two crawls.

The one exception: an ItemList whose items are Product objects with only name, url and image, and no offers, price, review or rating. This is valid and Google accepts it. It earns no rich result, so I usually skip it and keep plain ListItem entries, but it is not wrong.

Article or BlogPosting

Blog category and tag pages are listings of articles, not articles. Putting Article markup on the category page tells Google the category is a single piece of writing with a headline and a publish date. Some WordPress themes do this because the archive template reuses the single-post header. The fix is the same as for stores: CollectionPage plus ItemList of the post URLs. Each post keeps its own Article schema on its own URL.

AggregateRating

Aggregate ratings on a category page, computed across all products in the category, are a common trick to get stars on the listing. Google's guidelines say ratings must be about the specific thing the page is about, and a category is not a rateable thing. This one is more likely than the others to earn a manual action because it is obviously an attempt to game the display. Leave ratings on product pages and, if you want social proof on the category, put it in visible text and testimonials instead.

Three copy-paste examples

Each block below goes inside a <script type="application/ld+json"> tag in the head of the category page. Replace the URLs and names. Keep the structure. All three validate cleanly as of September 2026.

Example 1: Shopify or WooCommerce product category

This is for a collection page showing a grid of products. The ItemList lists the products on that page in grid order. Prices are deliberately absent.

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "CollectionPage",
      "@id": "https://example.in/collections/ayurvedic-hair-oil#page",
      "url": "https://example.in/collections/ayurvedic-hair-oil",
      "name": "Ayurvedic Hair Oil",
      "description": "Cold-pressed Ayurvedic hair oils made in Pune. Bhringraj, amla and coconut blends.",
      "isPartOf": { "@type": "WebSite", "url": "https://example.in/" }
    },
    {
      "@type": "ItemList",
      "itemListOrder": "https://schema.org/ItemListOrderAscending",
      "numberOfItems": 3,
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Bhringraj Hair Oil 200ml", "url": "https://example.in/products/bhringraj-hair-oil-200ml" },
        { "@type": "ListItem", "position": 2, "name": "Amla Coconut Hair Oil 200ml", "url": "https://example.in/products/amla-coconut-hair-oil-200ml" },
        { "@type": "ListItem", "position": 3, "name": "Neem Scalp Oil 100ml", "url": "https://example.in/products/neem-scalp-oil-100ml" }
      ]
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.in/" },
        { "@type": "ListItem", "position": 2, "name": "Hair Care", "item": "https://example.in/collections/hair-care" },
        { "@type": "ListItem", "position": 3, "name": "Ayurvedic Hair Oil", "item": "https://example.in/collections/ayurvedic-hair-oil" }
      ]
    }
  ]
}

Example 2: Blog category page

Same shape, different content. The ItemList points to individual posts. There is no Article type anywhere in this block; the posts carry their own.

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "CollectionPage",
      "url": "https://example.in/blog/local-seo/",
      "name": "Local SEO Guides",
      "description": "Every guide on ranking in Google Maps and local search for Indian businesses.",
      "isPartOf": { "@type": "WebSite", "url": "https://example.in/" }
    },
    {
      "@type": "ItemList",
      "itemListOrder": "https://schema.org/ItemListOrderDescending",
      "numberOfItems": 3,
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "How to Rank on Google Maps", "url": "https://example.in/blog/how-to-rank-on-google-maps/" },
        { "@type": "ListItem", "position": 2, "name": "Google Business Profile Optimization Guide", "url": "https://example.in/blog/google-business-profile-guide/" },
        { "@type": "ListItem", "position": 3, "name": "How to Get More Google Reviews", "url": "https://example.in/blog/get-more-google-reviews/" }
      ]
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.in/" },
        { "@type": "ListItem", "position": 2, "name": "Blog", "item": "https://example.in/blog/" },
        { "@type": "ListItem", "position": 3, "name": "Local SEO", "item": "https://example.in/blog/local-seo/" }
      ]
    }
  ]
}

Example 3: Services category page for a local business

A clinic, salon or agency often has a page that lists its services with a card each. That page is also a CollectionPage. The services themselves can be Service types on their own pages. If you want to name the business on the listing, reference the LocalBusiness by id rather than repeating the full business block.

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "CollectionPage",
      "url": "https://example.in/services/",
      "name": "Dental Services in Kothrud, Pune",
      "description": "Root canal, implants, aligners and cleaning at our Kothrud clinic.",
      "isPartOf": { "@type": "WebSite", "url": "https://example.in/" },
      "about": { "@id": "https://example.in/#business" }
    },
    {
      "@type": "ItemList",
      "itemListOrder": "https://schema.org/ItemListOrderAscending",
      "numberOfItems": 3,
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Root Canal Treatment", "url": "https://example.in/services/root-canal/" },
        { "@type": "ListItem", "position": 2, "name": "Dental Implants", "url": "https://example.in/services/dental-implants/" },
        { "@type": "ListItem", "position": 3, "name": "Clear Aligners", "url": "https://example.in/services/clear-aligners/" }
      ]
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://example.in/" },
        { "@type": "ListItem", "position": 2, "name": "Services", "item": "https://example.in/services/" }
      ]
    }
  ]
}

How to add schema markup to a category page

The sequence below is what I follow on every store or blog. It takes under an hour for a site with a handful of categories, and most of that hour is checking what the theme already emits.

Step 1: Confirm the page is a listing

Decide whether the URL is a category, collection, archive or tag page that lists other pages. If it is, the page type is CollectionPage. If the URL is really about one product or one article with a list of related items underneath, stop and use Product or Article instead. Mixed pages are rarer than people think; a product page with "you may also like" is still a product page.

Step 2: Check what your theme already outputs

Paste the category URL into the Schema Markup Validator at validator.schema.org and note every block present. Shopify themes such as Dawn add a basic CollectionPage in some versions. WooCommerce with Yoast adds CollectionPage on shop archives but usually no ItemList. Some themes inject Product blocks per card, which you will remove. Knowing the baseline stops you adding a second, conflicting block.

Step 3: Build the ItemList from the visible items

Write down every item shown on that page in grid order. Each ListItem needs position, name and the absolute URL of the child page. For paginated categories, include only the items on that page. If your grid loads more items on scroll, include only what is in the HTML on first load; Google compares the markup to the served HTML, not to what appears after scrolling.

Step 4: Add BreadcrumbList

Mirror the visible breadcrumb trail. Home first, then any parent category, then the current category last. If the theme already outputs a BreadcrumbList, keep the theme's version and do not add another; two breadcrumb blocks on one page is a common cause of the "duplicate field" warning.

Step 5: Insert the JSON-LD in the template head

On Shopify, edit the collection template Liquid file and use Liquid loops to generate the ItemList from the collection's products so it stays accurate as inventory changes. On WordPress, Rank Math and Yoast both let you attach a custom schema to archives; a header-and-footer snippet plugin also works. On a static site like this one, paste the script into the head of the category HTML file. One script block per type, or one graph, whichever your platform makes easier to maintain.

Step 6: Validate and monitor

Re-run the validator and Google's Rich Results Test. Expect the Rich Results Test to say no rich results were detected for CollectionPage and ItemList; that is the normal outcome, and a clean parse with zero errors is the goal. Then watch Enhancements and Page Indexing in Google Search Console over the next few weeks. If your site had Product errors from the old markup, they should fall away as the pages are recrawled. My technical SEO basics guide covers how to read those reports if they are new to you.

How to validate and what to expect

Two validators matter. The Schema Markup Validator checks that the JSON-LD is well formed and uses valid types and properties. The Rich Results Test checks whether Google would show a rich result. For category page markup you want a green pass on the first and a polite "no rich results detected" on the second. That combination means the markup is correct and Google is not being asked to display anything it should not.

In Search Console, the useful report is Enhancements, which lists structured data types Google found and any errors. After you clean up a store that had Product blocks on listings, the Product report should shrink to the true number of product pages. The Breadcrumbs report should show every category with valid items. There is no CollectionPage or ItemList report, because those types do not drive an enhancement, so the absence of a report is not a problem.

One more check I run: view the page source and confirm the ItemList URLs match the canonical URLs of the child pages exactly. Trailing slashes, http versus https and www versus non-www all count. If your product pages canonicalise to one form and the ItemList uses another, you have created a small duplicate signal for every item. My post on canonical URLs explains why that matters more than it looks.

Seven common mistakes with category page schema

Product markup on the listing. Covered above and still the number one issue on Indian Shopify stores. Strip it from the collection template.

ItemList that does not match the page. Listing the whole catalogue on page 1, or listing items that are out of stock and hidden. Match the visible grid.

Relative URLs in ListItem. Use absolute URLs. The validator accepts relative paths, but Google resolves them against the page URL and any inconsistency creates noise.

Two BreadcrumbList blocks. One from the theme, one from a plugin. Pick one.

CollectionPage name that differs from the H1. The name in the markup should be the same words as the visible heading. A different name is a small trust hit for no gain.

Adding FAQPage to a category to get a snippet. FAQ markup belongs where visible questions and answers exist on the page. A hidden FAQ on a product grid is the kind of thing Google tightened rules around in 2023 and 2024. If you want FAQ rich results, put real FAQs on a page that answers them, and read my post on FAQ schema and AI Overviews before you do.

Forgetting the meta tags. Structured data does not replace a good title and description. The category page still needs a title that names the category and the location or intent, and a description that reads like an offer. My meta tags guide covers what still matters in 2026, and the free meta tag generator will build the block for you.

Frequently asked questions

Should I put Product schema on my category page?

No. Google's Product structured data guidelines say Product markup with offers, price or ratings belongs on a page about a single product. A category page lists many products, so full Product markup there is a mismatch and can be flagged as misleading structured data. Use CollectionPage plus an ItemList whose ListItem entries point to each product URL. Keep the price, availability and rating markup on the individual product pages.

Does ItemList on a category page give a rich result?

Not on its own. ItemList and CollectionPage do not trigger a visible rich result in Google Search the way FAQ or Product markup can. What they do is tell Google clearly that the page is a listing, which pages it lists and in what order. That helps discovery of the child URLs and reduces ambiguity about what the page is for. Treat it as clean labelling, not a snippet feature.

How many items should the ItemList include?

Every item that is actually visible on that page, in the same order. If the category is paginated, page 2 should list only the items shown on page 2, not the whole catalogue. Do not list items that are hidden behind a Load More button unless they are present in the HTML on load. Google compares the markup to what a visitor sees, and a mismatch is the most common reason category schema gets ignored.

Do I need CollectionPage on a blog category page?

Yes, the same rules apply. A blog category or tag page is a listing, so mark it up as CollectionPage with an ItemList of the post URLs and a BreadcrumbList. Do not put Article or BlogPosting schema on the category page itself, because Article markup describes a single piece of writing. The Article schema belongs on each individual post.

Will Shopify or WooCommerce add category schema automatically?

Only partly, and it depends on the theme. Shopify themes usually add Product markup on product pages and sometimes a basic CollectionPage on collection pages. WooCommerce with Yoast or Rank Math adds CollectionPage on shop archives but often skips the ItemList. Run your category URL through the Schema Markup Validator to see exactly what your theme outputs, then add only what is missing so you do not end up with two conflicting blocks.

Related guides

Your next step

Pick your single most important category page, paste its URL into the Schema Markup Validator, and read what comes back. If you see Product or Article on a listing, that is your first fix. Then copy the matching example above, swap in your URLs, and validate again. Once the categories are clean, run the whole site through the free website SEO checker to catch the on-page issues that structured data cannot fix.

Follow Shreyas in Google

Get new guides in your Google Search & Discover feed.