Why our own review schema won't earn Google stars
We shipped valid Review JSON-LD from our testimonials block. Google won't show stars for it. Here's what we learned about the limits of s...
The Blog
Metadata is the easiest thing to get wrong on a CMS-built site. Titles default to the site name, OG images fall back to a generic logo, and canonical URLs break the moment pages are nested. Here's how we generate all of it from the content model.
The problem
Most CMS-built sites have metadata that's technically present but practically wrong. The OG image is a generic company logo on every page. The meta description is blank or auto-generated from the first paragraph. The canonical URL is fine on top-level pages but breaks the moment you nest a page under a parent.
This matters because metadata controls how your pages appear everywhere except your own site, in Google results, in social media previews, in link unfurls on Slack and LinkedIn, and increasingly in AI tool citations. If the metadata doesn't accurately represent the page, every share and every search result is a missed opportunity.
The approach
We handle metadata as a content architecture concern in Payload CMS, not an afterthought bolted onto a page template.
Every page and post can have explicit meta titles and descriptions set by the editor. When they don't, which is most of the time, the system falls back to the document title and a generated description. The fallback is always better than blank, but editors can override it for pages where the default isn't ideal.
When media is uploaded to the CMS, Payload generates a dedicated 1200×630 crop specifically for Open Graph use. This means social previews are never a cropped version of a hero image or a stretched logo, they're a purpose-built asset at the exact dimensions social platforms expect. The OG image is selected from the page's meta fields, with a site-wide default as the fallback.
This is where nested pages get tricky. A page at /services/digital-platforms needs a canonical URL that reflects its full path, not just its slug. We derive canonicals from the document's breadcrumb trail for pages, and from a collection prefix map for posts and work items (/blog/{slug}, /work/{slug}). The homepage returns the base URL with no trailing path.
Every page gets summary_large_image as the Twitter card type and @littledash as the creator. These are set once at the root layout level and inherited by every page — no per-page configuration needed.
Why this matters
The investment in getting metadata right is small, a utility function, a media size configuration, a breadcrumb-based canonical resolver. But the payoff shows up on every social share, every search result, and every link preview.
Pages with accurate OG images get higher click-through rates on social media. Pages with correct canonical URLs don't compete with themselves in search. Pages with proper meta descriptions give Google and AI tools something useful to display instead of auto-generated noise.
This complements the structured data architecture we've built — structured data tells search engines what the content is, metadata tells them how to present it. Both need to be accurate, and both should generate from the content model rather than being maintained manually.