Sitecore

XM Cloud Headless: Cache the Layout You Actually Ship

Headless fails in prod when preview cache and live cache disagree. I've shipped that.

The page looked fine in Experience Editor. The site showed last week's promo. I checked the wrong CDN.

Preview lied. The edge didn't.

The page looked fine in Experience Editor. The site showed last week's promo. I checked the wrong CDN for an hour. Layout Service was fine. Edge cache wasn't. Marketing refreshed like it would help. Refresh doesn't purge. Hope isn't a header.

I blamed XM Cloud because that's the brand on the invoice. The invoice doesn't purge cache. A key does. We didn't have a named purge key. We had folklore. Folklore fails on Fridays.

Layout JSON is a document

Treat it like one. Version it. Don't stitch fields in the front end 'just this once.' Once becomes a year. We shipped a component that read a field the Layout Service didn't return. Worked in a mock from March. Died on real JSON in August. I still get mad about March.

If the front end needs a field, put it in the rendering contents resolver. Don't scrape it client-side. Client-side scrape is how you get a CSS ticket for a data problem. I've filed that ticket. I'm not proud.

Cache like you mean it

Name the cache. TTL written down. Purge on publish. If marketing can publish, they need a button that clears what they see. If the button is a Slack message to me, I will be on a drive. The old promo will stay. That's the story of last week's banner.

Hit the layout URL with a cache buster. Then hit the site. If they disagree, I don't touch components yet. I look at TTL and purge keys. Components are innocent until the caches agree. I learned that after rewriting a hero that was fine.

  • Named purge key per site.
  • Publish ping that actually fires.
  • Layout hit as the site user, not admin.
  • Preview keys not mixed with prod.

Webhooks

Publish should ping the front. If it doesn't, people hard-refresh and blame Sitecore. I blamed Sitecore. It was me. I skipped a webhook because the ticket was 'just content.' Content is why the webhook exists.

Test the ping by publishing a harmless typo and watching the front. Then fix the typo. If nothing moves, your ping is theater. Theater is for keynotes.

Environments

Preview data in prod cache is how you get a lawsuit's worth of 'why is that still up.' Separate keys. I mixed them once. Once. That's enough for a career memory.

Hit layout as the site user. Not as admin. If a field vanishes, that's your ticket. Not a CSS ticket. Write 'field missing for anonymous' in the title so nobody 'tweaks spacing.'

A publish window that doesn't lie

Tell marketing the cache might lag by N minutes. Pick N from reality, not from a slide. If N is 15 and you said instant, you will get instant anger. I'd rather be boring and right.

If you can't measure N, you don't have a window. You have a wish. Measure once. Write it on the same sticky as the purge key.

Further reading

Sitecore Layout Service docs. Your CDN purge API docs. Read both. Then your pipeline. If the pipeline can't purge, the pipeline is incomplete. Incomplete pipelines make heroes from last week.

Checklist

Publish. Busted layout URL. Live URL. Compare. Purge. Compare again. If marketing can do steps 1 and 5 without me, we're grown. If they can't, I'm still the cache. I don't want to be the cache.

I wrote this after a real miss. Wrong cache. Old banner. That's enough reason to name the key.

Monday

Write the purge key on a sticky. Put it on the monitor that does deploys. Then fire a test publish of a draft nobody cares about. Watch the front. If you have to ping me to see the change, the sticky isn't done. The button isn't done. Do the button.

If You Only Do One Thing

Turn GraphQL off in preview for one template. Watch authors. If they don't notice, the query wasn't load-bearing. If they notice, you found the contract. Write that contract on a sticky. Then turn GraphQL back on for that template only.

I did this on a Thursday because Monday was already on fire. Thursday is a fine fire. Smaller.

What I Won't Do

I won't 'enable headless everywhere' as a slogan. Everywhere is how unpublished drafts leak. Template by template. Boring. That's the point.

The Query That Wasn't Load-Bearing

We turned GraphQL off on a promo template. Nobody noticed for two hours. Then an author asked where the 'new sidebar' went. The sidebar was a field they'd been filling by hand. GraphQL wasn't serving it. A rendering was. We had been scared of the wrong wire.

I wrote 'hand field' on a sticky and stuck it on the monitor. Ugly. Accurate.

The Query That Was

Product listing. Authors noticed in four minutes. That's a contract. We wrote the fields on a card: name, price, status. Status was the one that leaked unpublished. Status stays server-side. I will say that until I'm boring.

Thursday fire was smaller than Monday fire. I still prefer Thursday. Monday already has deploys.

What 'Everywhere' Would Have Done

Turned on a template with a draft bio. Partner site would have shown a nickname we use internally. I have seen that nickname. It is not partner-safe. Everywhere is how nicknames travel.