Recover from a bad step · TypeScript
Checkpoint prepared browser state, discard a later edit, and reconnect to the restored page.
Imagine an automation that has loaded a page and prepared important browser state. The next step changes that state, but the workflow decides it needs to go back. Rewind restores the captured browser instead of making the application rebuild it from the beginning.
The story
- Open the page and write a value that represents prepared application state.
- Capture a checkpoint between actions.
- Write a different value after the checkpoint.
- Rewind to the checkpoint.
- Reconnect with Playwright and verify the original value returned.
1. Capture a safe point
The checkpoint comes after the state you care about is ready—not before the page is loaded and not halfway through an action.
// A checkpoint is an application-chosen safe point. Prepare the browser
// state first, then capture it between actions.
await page.goto(url);
await page.evaluate(
([key, value]: readonly [string, string]) =>
localStorage.setItem(key, value),
[markerKey, "checkpointed"] as const,
);
const checkpoint = await brawsr.createCheckpoint(session.id, {
label: "before-edit",
});2. Make the change, then rewind it
The later value exists only to prove that rewind is doing real work. Passing the returned checkpoint object keeps the call explicit and typed.
// This later state is intentionally discarded by rewind.
await page.evaluate(
([key, value]: readonly [string, string]) =>
localStorage.setItem(key, value),
[markerKey, "edited-after-checkpoint"] as const,
);
const restored = await brawsr.rewind(session.id, checkpoint);
rewindOperationId = restored.operationId;3. Reconnect and verify
Rewind replaces the browser process. The old browser, context, page,
locator, and element handles are stale, so the workflow creates a fresh CDP
connection from the rewind result.
// Rewind replaces the browser process. Every old Playwright handle is stale,
// so reconnect from the returned result and rediscover the page.
const restoredConnection = brawsr.connectCDP(restored);
const restoredBrowser = await chromium.connectOverCDP(
restoredConnection.endpointUrl,
{ headers: restoredConnection.headers },
);
const restoredPage = restoredBrowser.contexts()[0]?.pages()[0];
if (!restoredPage) throw new Error("rewind restored no browser page");
const value = await restoredPage.evaluate(
(key: string) => localStorage.getItem(key),
markerKey,
);
if (value !== "checkpointed") throw new Error("rewind lost browser state");4. Sequence the next lifecycle mutation
The rewind result is ready for CDP work before its operation necessarily becomes terminal. Browser automation may continue immediately. Closing, checkpointing, forking, or rewinding the same session again must wait.
// A rewind result can be CDP-usable before its operation is terminal. Wait
// before close, which is another lifecycle mutation on the same session.
try {
if (rewindOperationId) await brawsr.waitRewind(rewindOperationId);
} finally {
await brawsr.closeSession(session.id);
}Successful output contains "rewound":true and
"value":"checkpointed".