Measuring Preview Latency for Editors
Within DX & Developer Experience Metrics, this guide focuses on the metric editors notice most: the time between saving a change in the CMS and seeing it in the preview. It shows how to measure it with a synthetic probe and with real editor sessions, how to split it into layers, and what targets are realistic for live preview and for draft-mode page reloads.
Slow preview changes how people work. When a change takes ten seconds to appear, editors batch their edits, preview less often and publish mistakes they would have caught. When it appears in a second, they use preview as part of writing. Preview latency is therefore not a comfort metric; it directly affects content quality. It is also one of the easiest metrics to regress without noticing, because developers rarely use preview themselves.
The Problem
A news publisher’s editors complained that preview had become slow after a frontend redesign. Developers tested it and found it “fine”, about two seconds on their machines. Editors reported ten seconds or more. Both were right: developers previewed short test articles on a warm development server, while editors previewed long articles with many embedded elements through the production preview deployment, which had inherited the production data cache configuration and was revalidating instead of bypassing it.
How to Measure Preview Latency
Two complementary measurements give a complete picture.
A synthetic probe edits a dedicated test entry through the management API and polls the preview URL, or listens on the preview page, until the change appears. It runs on a schedule and gives a stable, comparable number and an alert when preview breaks entirely. Because it uses a fixed entry, it does not reflect the variety of real content.
Real editor sessions are measured in the preview frame itself. The preview page reports, for each update, the time between the CMS’s save event and the moment the updated content rendered. This reflects real articles, real networks and real devices, but needs a little code in the preview integration and consent from the editorial team.
For both, record timestamps at the boundaries: save acknowledged by the CMS, change notification received by the preview app, draft data fetched, render complete. The differences between them are the layer timings.
Implementation
In the preview page, wrap the update handler so every update reports its timing. The example assumes a preview integration where the CMS editor sends a message to the preview frame after each save, which most visual editing SDKs support; adapt the event name to your platform.
// app/preview/preview-timing.ts: loaded only in draft mode
type Timing = { entryId: string; saveToRenderMs: number; fetchMs: number; renderMs: number; contentSizeKb: number };
export function installPreviewTiming(refetch: (entryId: string) => Promise<{ sizeKb: number }>, rerender: () => Promise<void>) {
window.addEventListener("message", async (event: MessageEvent) => {
if (event.origin !== process.env.NEXT_PUBLIC_CMS_ORIGIN) return;
const data = event.data as { type?: string; entryId?: string; savedAt?: number };
if (data.type !== "entry-saved" || !data.entryId || !data.savedAt) return;
const fetchStart = performance.now();
const { sizeKb } = await refetch(data.entryId);
const renderStart = performance.now();
await rerender();
// Wait one frame so the measurement includes layout and paint of the new content.
await new Promise((r) => requestAnimationFrame(() => r(null)));
const done = Date.now();
const timing: Timing = {
entryId: data.entryId,
saveToRenderMs: done - data.savedAt,
fetchMs: renderStart - fetchStart,
renderMs: performance.now() - renderStart,
contentSizeKb: sizeKb,
};
navigator.sendBeacon("/api/preview-metrics", JSON.stringify(timing));
});
}
saveToRenderMs compares a timestamp from the CMS with the browser’s clock, so it includes clock skew between the two. For trends and comparisons that is acceptable; for precise layer timings, rely on fetchMs and renderMs, which are measured on one clock. Store the timings with the content size so slow previews of very long entries can be told apart from slow previews in general.
Targets
Live preview, where the frame updates in place, should reach a median under one second and a 90th percentile under two seconds for typical entries. Draft-mode previews that reload the page should reach a median under three seconds and a 90th percentile under five. Long entries and pages with many references will be slower; track them separately rather than letting them hide in averages.
Reading the results
Plot the editor timings as a distribution per day rather than a single average, and segment them by content type and content size. A median that stays flat while the 90th percentile climbs usually means that one kind of content, such as long live blogs or product pages with many variants, has become slow, and the fix belongs in that template rather than in the preview infrastructure. Compare the probe and the editor numbers too. When the probe is fast and editors are slow, the problem is in real content or in editors’ networks and devices; when both are slow, it is in the shared path, most often the draft fetch or a deploy that changed caching.
Share the chart with the editorial team. Seeing that preview is measured, and that regressions are noticed and fixed, builds trust in the tooling and makes editors more likely to report problems early and precisely, with the entry and time, which makes them much faster to investigate.
Configuration Reference
| Measurement | Source | Frequency | Alert |
|---|---|---|---|
| Probe latency | scheduled job, test entry | every 5 to 15 minutes | no update in 30 s, or above 2× baseline for an hour |
| Editor save-to-render | preview frame beacon | every update | p90 above target for a day |
| Fetch time | preview frame | every update | trend only |
| Render time | preview frame | every update | trend only |
| Content size | preview frame | every update | used to segment results |
Gotchas & Edge Cases
- Cached drafts. A preview that goes through the production data cache may show stale drafts or revalidate slowly. Draft requests should bypass caches entirely, as described in draft state management.
- Measuring the developer experience instead. Development servers compile on demand and behave differently from preview deployments. Always measure the deployment editors use.
- Personal data in metrics. Record entry ids and timings, not content or editor identities, unless the editorial team has agreed otherwise.
- Debounced saves. Some CMS editors save after a pause in typing. The save timestamp is then later than the keystroke, so reported latency understates what editors feel by the debounce interval. Note the interval next to the chart.
Worked Example
The publisher added the probe and the preview frame timing. The probe showed 9.8 seconds for a medium-length article; the frame timings split it into 0.4 seconds for notification, 6.1 seconds for the draft fetch and 3.1 seconds for rendering. The fetch was slow because the preview deployment used the production fetch configuration with a revalidation window; disabling the cache in draft mode brought it to 0.9 seconds. Rendering was slow because every embedded social post was re-initialized on each update; rendering placeholders for embeds in preview brought it to 0.6 seconds. Median preview latency fell to 1.9 seconds, and editors noticed within a day.
Rollout Checklist
- Create a test entry and a scheduled probe against the preview deployment.
- Add timing to the preview frame’s update handler and send it with a beacon.
- Record layer timings and content size, not content or identities.
- Set targets for live and draft-mode preview, and alert on sustained regressions.
- Review preview latency after every frontend release, since redesigns often regress it.
Frequently Asked Questions
Why not just ask editors how fast preview feels?
Ask them too, but perceptions vary with content and mood, and complaints arrive after the regression has been in place for a while. Measurements find regressions within a day and show which layer caused them.
Does live preview always beat draft-mode reloads?
For small changes, yes, because only the changed data is refetched and re-rendered in place. For structural changes, a full reload can be simpler and just as fast. Measure both if you offer both.
Should the probe run in production hours only?
Run it around the clock at a low frequency and more often during editorial hours. Preview problems caused by deploys or CMS incidents can start at any time.
How do we measure preview in static site setups?
The same way: the probe polls the preview URL, and the preview page reports timings. Static sites usually preview through a server-rendered draft route, so the layers are the same as in draft mode.
Can preview latency be too fast to matter?
Below about half a second, editors perceive updates as instant, and further gains bring little. At that point, spend effort on reliability, meaning previews that never fail or show stale data, rather than on shaving milliseconds.