browserlayer / docsPrivate alphaDashboard ↗
Build integrationsMarkdown

Checkpoints and deletions

Keep these three positions separate:

PositionOwnerPurpose
Execution journalBrowserlayerResume completed steps within a run
Source checkpointYour syncContinue fetching the website's dataset
Consumer cursorYour appContinue applying published changes

Incremental publication

Inside a sync with a checkpoint schema such as z.object({ next: z.string() }):

ts
const checkpoint = await ctx.getCheckpoint(); // null on the first run
// Fetch the next page through your connector using checkpoint?.next.
await ctx.publish("page", records, {
  checkpoint: { next: nextPageToken },
  deleted: deletedIds,
});

records, nextPageToken and deletedIds come from the upstream page you fetched. Publication commits records, checkpoint and notification intent atomically.

Full snapshots

ts
await ctx.publish("snapshot", records, {
  checkpoint: null,
  scan,
  completeScan: true,
});

Use one unique scan ID for every page in a snapshot. Generate it in a durable step. Only mark the final successful page completeScan: true.

CaseResult
Complete snapshot omits an old recordPublish a deletion
Complete snapshot is emptyDelete all old records and publish an update notification
Partial scan failsAlready published batches remain; missing records are not deleted
Scan continues across runsCarry its scan ID in the checkpoint

Model changes need a new sync identity or an explicit development dataset reset. Renaming a sync starts a different stream.