Where they started
A DTC cosmetics brand with a deep catalog, most products sold in six to twelve shades. The theme generated a near-duplicate PDP for every shade, so a single lipstick existed as nine competing URLs, none canonicalized. Worse, the theme’s “upgrade” had quietly broken the Product markup: offers pointed at a price field that no longer existed, and the review block emitted JSON-LD that failed validation on every page. Google saw thin duplication and zero eligible rich results across the whole store. Rankings were flat but not tanking, which is exactly the trap. Nothing looked broken enough to explain the ceiling.
What we did
- Canonicalized shade variants to one PDP each. Collapsed nine duplicate URLs per product to a single indexable page with in-page shade selection. Crawl budget stopped draining into duplicates and consolidated signals onto the pages that could actually rank.
- Rebuilt Product/Offer/Review schema so it validates. Fixed the price mapping, restored aggregateRating, and got every product page eligible for review-star rich results. This is what moved CTR before anything moved position.
- Rewrote PDP titles into buyer language. Swapped internal SKU-style titles for how people actually search (finish, skin type, shade family), which lifted CTR further on the same positions.
- Built 18 editorial links to hero categories. Beauty and ingredient-science placements only, aimed at the category pages feeding the PDPs.
The sequence is the whole story. CTR rose first, on pages that hadn’t moved a position. The stars and better titles earned more clicks at the same rank. Google reads that preference, and rankings caught up from month two onward. DR barely moved; this was a technical and on-page win, not a link-volume one.