Skip to content
LogoLogo

About server-side rendering

Why does a Page need a snapshot, when the SDK can fetch its content in the browser? Because the reader that matters most does not run JavaScript.

The constraint

A crawler and a social preview read the HTML your server returns, and they do not wait for the browser to fetch anything. If the content of a Page arrives after the first response, those readers never see it.

So the content has to be in the HTML. That means your server has to know, before it answers, which experiences match this URL and what their content is.

What the snapshot is for

serialize() answers that question on the server. It registers your project configuration and evaluates each experience condition against the URL. It then reads the content for each experience that matches, and returns a PickedSnapshot as plain JSON.

projectConfig (Delivery API)
  -> serialize(client, params) on the server -> PickedSnapshot
  -> embed snapshot in HTML
  -> client seeds from snapshot -> renders the same markup -> hydrates

The snapshot carries the exact options the server chose with, and the condition results it reached. The first render in the browser therefore reuses the decisions of the server. It does not evaluate them a second time.

That last point is the whole reason the snapshot holds condition results and not only content. A browser that evaluates the conditions itself can reach a different answer. A different URL shape, a different time, or a different flag value each give a different result. The markup then does not match what the server sent, and hydration discards the server HTML. That failure is the one server-side rendering exists to prevent.

Why a slot instead of a selector

A browser-rendered flow points at a DOM selector, and the SDK inserts the component next to the element that it finds. That cannot work on a server, because a server has no DOM to search.

A slot reverses that. <ExperienceSlot name="page" /> is a mount point that you place in your own markup. An experience joins it when its target selector is .picked-slot-<name>. Your component tree decides where the content goes, so the server renders it in one pass.

Why placements have an order

More than one experience can point at the same slot, so the slot needs a rule. The order is:

replace -> before -> prepend -> append -> after

replace wins: an active experience with that placement renders alone. Every other active experience renders in the order above.

The rule exists so the outcome does not depend on which experience came first. Two editors can add an experience to the same slot on the same day. The result then follows from the placements, and not from the database.