brawsrdocsv0.6
Examples

Compare primary and fallback routes

Evaluate two routes from the same prepared browser state and keep selection in application policy.

Your automation has reached a useful state, but the next route is uncertain. Perhaps a primary checkout and a fallback checkout must both be tested, or two navigation strategies need the same authenticated browser. Running them sequentially lets the first attempt influence the second. Fork gives both routes the same isolated starting point.

The story

  1. Prepare one source browser and checkpoint it.
  2. Fork two children: primary and fallback.
  3. Navigate both children concurrently.
  4. Treat a visible, non-empty <h1> as this example's acceptance rule.
  5. Let application code select the first acceptable result.

The default fallback is the example URL with ?route=fallback. Set BRAWSR_FALLBACK_URL to compare a real alternate route.

1. Name the alternatives

Routes are explicit data. Their array order maps to the stable order of fork children, so the branch-to-route relationship is easy to inspect.

const { brawsr, url } = configuration();
const routes = [
  { name: "primary", url },
  {
    name: "fallback",
    url: process.env.BRAWSR_FALLBACK_URL ?? `${url}?route=fallback`,
  },
] as const;

2. Capture the state both routes need

The marker represents shared setup such as authentication, loaded data, or a partially completed workflow. A later source edit proves the children come from the checkpoint rather than the source's current state.

await sourcePage.goto(url);
await sourcePage.evaluate(
  ([key, value]: readonly [string, string]) =>
    localStorage.setItem(key, value),
  [markerKey, "prepared-for-route-comparison"] as const,
);
const checkpoint = await brawsr.createCheckpoint(session.id, {
  label: "before-route-choice",
});
await sourcePage.evaluate(
  ([key, value]: readonly [string, string]) =>
    localStorage.setItem(key, value),
  [markerKey, "source-after-checkpoint"] as const,
);

3. Give each child one route

The source plus two children fits the default three-session limit. Each child is paired with one route by array order.

// Each route starts from the same prepared browser state. The source plus
// these two children fits the default three-session organization quota.
forked = await brawsr.fork(session.id, checkpoint, { n: routes.length });
const alternatives = await Promise.all(
  forked.children.map(async (child, index) => {
    const route = routes[index];
    if (!route) throw new Error(`branch ${child.branchIndex} has no route`);

4. Verify inheritance, then evaluate

After connecting to the child's browser, the workflow verifies its shared starting state. It then visits the assigned URL and returns only the information the selection policy needs.

const inherited = await page.evaluate(
  (key: string) => localStorage.getItem(key),
  markerKey,
);
if (inherited !== "prepared-for-route-comparison")
  throw new Error(`branch ${child.branchIndex} lost prepared state`);
await page.goto(route.url);
const heading = (await page.locator("h1").first().textContent())?.trim();
return {
  branch: child.branchIndex,
  route: route.name,
  acceptable: Boolean(heading),
  heading,
};

5. Keep selection in your application

brawsr creates peer sessions; it cannot know what “best” means for your workflow. This story uses a heading as a simple acceptance rule. Production code can validate page content, compare prices, score results, or retain every branch instead.

// Selection is application policy. Here the first route with the expected
// heading wins; a real workflow can apply its own validation or scoring.
const selected = alternatives.find((candidate) => candidate.acceptable);
if (!selected) throw new Error("neither route rendered the expected heading");
console.log(JSON.stringify({ selected, evaluated: alternatives.length }));

The output names the selected route and reports that two alternatives were evaluated. There is no automatic winner, state merge, or sibling cleanup.

View the complete speculative branching example (opens in a new tab)

On this page