Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Build durable browser automation by keeping Temporal Workflow code deterministic and moving every Playwright browser action into Temporal Activities. The Workflow records decisions and progress in Event History; Activities perform navigation, clicks, extraction and screenshots, then return serializable results. If a worker or browser fails, Temporal can replay the Workflow and retry the Activity, while your code decides whether to retry, compensate, or request human intervention.

What Temporal is

Temporal is a workflow orchestration platform. A Workflow Definition is the code that defines the Workflow. Temporal records Workflow progress as an Event History. When a Worker needs to recover state, it replays deterministic Workflow code against that history; completed operations return their recorded results instead of running external work again.

This durability applies to orchestration state and decisions. It does not make a remote website reliable, preserve a browser process across a Worker restart, or make an arbitrary website action safe to repeat. Those boundaries determine how you design the browser side.

The durable browser architecture

Workflow: the coordinator

Use the Workflow to hold business state, schedule browser steps, apply timeouts and retry policies, and choose the next branch from recorded results. Inputs, Signals, Updates, Activity results and Temporal APIs can drive decisions. Live DOM reads, network calls, random values and wall-clock calls must not run in Workflow code because replay could produce a different result.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Activity: the browser boundary

Temporal describes Activities as operations that interact with the external world. Put Playwright page creation, navigation, authentication, clicks, screenshots, extraction and browser cleanup in Activities. Return compact, serializable results such as { status: "approved", orderId: "..." } rather than trying to place a Page or Browser object in Workflow state.

This Workflow–Activity split is an engineering composition of Temporal’s documented deterministic model and Playwright’s browser APIs; it is not a vendor-published Temporal–Playwright integration.

Context and page ownership

Playwright separates a BrowserContext from a Page. A context contains session-level state and can host several pages; a page represents a tab and can also be created for a popup. Decide which Activity owns the context, when it closes pages and contexts, and how a retry reacquires authentication. Process memory is not durable state, so do not assume a browser left running on one Worker will be available after that Worker is replaced.

A minimal TypeScript implementation

The following pattern uses the Temporal TypeScript SDK shape and Playwright. Keep the browser code in an Activity module and the Workflow module free of browser imports. Adapt package versions and your task-queue names to your deployment.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Activities

import { chromium } from "playwright";
import { heartbeat } from "@temporalio/activity";

export type CheckoutResult = {
  status: "submitted" | "already-submitted" | "blocked";
  reference?: string;
};

export async function submitCheckout(
  url: string,
  idempotencyKey: string
): Promise<CheckoutResult> {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext();
  const page = await context.newPage();
  try {
    await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30_000 });
    heartbeat({ stage: "loaded", idempotencyKey });

    // Probe first: a retry may follow an earlier successful submission.
    const existing = await page.locator(`[data-idempotency="${idempotencyKey}"]`).count();
    if (existing > 0) {
      return { status: "already-submitted", reference: idempotencyKey };
    }

    await page.getByRole("button", { name: "Submit" }).click();
    await page.waitForLoadState("domcontentloaded");
    heartbeat({ stage: "submitted", idempotencyKey });

    const reference = await page.locator("[data-reference]").getAttribute("data-reference");
    return { status: "submitted", reference: reference ?? idempotencyKey };
  } catch (error) {
    const text = error instanceof Error ? error.message : String(error);
    if (/captcha|bot check|access denied/i.test(text)) {
      return { status: "blocked" };
    }
    throw error;
  } finally {
    await context.close();
    await browser.close();
  }
}

The selector and URL are examples; replace them with your application’s contract. The important properties are the explicit cleanup, a heartbeat at meaningful checkpoints, and a state probe that can recognize a submission made before an interruption.

Workflow

import { proxyActivities } from "@temporalio/workflow";
import type * as activities from "./activities";

const { submitCheckout } = proxyActivities<typeof activities>({
  startToCloseTimeout: "5 minutes",
  heartbeatTimeout: "30 seconds",
  retry: {
    maximumAttempts: 3,
    initialInterval: "10 seconds",
    backoffCoefficient: 2
  }
});

export async function durableCheckout(input: {
  url: string;
  orderId: string;
}) {
  const result = await submitCheckout(input.url, input.orderId);

  if (result.status === "blocked") {
    return { action: "human-review", orderId: input.orderId };
  }
  return { action: "complete", orderId: input.orderId, reference: result.reference };
}

Activity retry settings are separate from Workflow retry behavior. A transient Activity failure can produce another Activity attempt while the Workflow remains open. A Workflow Task failure can be retried automatically during the same execution; an application failure that propagates can close the Workflow Execution, after which a configured Workflow retry policy may start another run. Set each policy intentionally so an Activity retry multiplied by a Workflow retry does not create unexpected duplicate browser actions.

How to make recovery safe

Assume an interruption window

A Worker can lose its process after the website accepted an action but before Temporal recorded Activity completion. Temporal does not provide exactly-once execution for arbitrary browser side effects. On a retry, the site may already contain the result.

  • Use an idempotency key that the site or your own backend stores.
  • Probe current state before clicking or submitting again.
  • Record a durable business reference and treat “already done” as success.
  • Use a compensating action when the operation cannot be made idempotent.
  • Return a classified result such as blocked, not-found or needs-review instead of hiding every failure behind a retry.

Checkpoint long work

Heartbeats communicate progress for applicable long-running Activities and can carry checkpoint details. Store only small, serializable data, such as the current record number or workflow stage. On retry, read the checkpoint and resume from a known safe boundary rather than assuming in-memory progress survived.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose Activity granularity

One Activity containing an entire browser journey minimizes Event History entries but may repeat more work after a failure. Many small Activities improve observability and recovery boundaries but can make histories large and increase orchestration overhead. Group actions around recoverable business steps: for example, “open account,” “upload document,” and “confirm result,” rather than every mouse movement. Temporal recommends starting with one Workflow and Activities; use Child Workflows when an independent resource or service needs its own history and lifecycle.

Handle cancellation and cleanup

Make browser cleanup unconditional. If cancellation arrives during navigation or a wait, close the page, context and browser in the Activity’s cleanup path. If a remote browser service owns the session, explicitly release that session as part of cancellation handling and define what a later retry should reacquire.

Where should Playwright run?

Hosting the Temporal Service and hosting the browser runtime are separate decisions. Temporal Cloud is Temporal’s hosted service option; self-hosting means operating the Temporal Service and its database yourself. Independently, you can run browsers alongside Workers or use a separately managed browser such as AWS Bedrock AgentCore Browser, which AWS documents for Playwright.

Decision Option Evaluate
Temporal Service Self-hosted Temporal Service and database Operational ownership, deployment and upgrades, configuration, networking and cost.
Temporal Service Temporal Cloud Managed operations, service configuration, network access and current service terms.
Browser runtime Browser managed with your Workers Isolation, patching, concurrency, credentials, egress controls and session cleanup.
Browser runtime Separately managed browser, such as AWS Bedrock AgentCore Browser Session lifecycle, region, network path, supported features, security controls and cost.

AWS’s Playwright guide demonstrates Playwright connecting to AgentCore Browser; it does not establish a direct Temporal–AgentCore integration, and neither service is required by the other.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Deployment-safe Workflow evolution

Long-running executions may outlive the Worker revision that started them. A code change that alters command order, branching or timer behavior can make an existing Event History fail replay. Plan compatibility before deployment.

  • Use Temporal’s Worker Versioning or patching strategies for changes that affect existing histories.
  • Keep old behavior available until executions created by it have completed or migrated.
  • Test replay against representative histories before routing production executions to a new Worker build.
  • Do not place a live browser read or environment-dependent branch in Workflow code as a shortcut around versioning.

Temporal documentation identifies Worker Versioning as the recommended route and notes that earlier experimental behavior was scheduled for removal from Server in March 2026. Because that date has passed, follow the current versioning guidance for the Server release you operate rather than copying an older setup.

Troubleshooting durable browser runs

The Workflow keeps replaying or reports a nondeterminism error

Cause: browser, network, random or wall-clock code ran in the Workflow, or a deployed change altered replayed control flow. Fix: move the external call into an Activity, return a recorded result, and deploy the change with versioning or patching.

An Activity repeats a purchase or submission

Cause: the Worker failed after the site action but before completion was recorded. Fix: add an idempotency key, probe the site or your backend before acting, and map an existing result to success.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Retries stop while a browser is still working

Cause: the Activity exceeded its Start-to-Close or heartbeat timeout, or the browser stopped sending heartbeats. Fix: set timeouts for the site’s real behavior, heartbeat during meaningful long waits, and make the retry path safe to resume.

The selector works locally but fails in production

Cause: different authentication state, viewport, locale, popup timing, bot controls or page structure. Fix: create the required BrowserContext state explicitly, wait for a stable selector, classify bot checks separately, and capture diagnostic artifacts inside the Activity.

Histories become difficult to operate

Cause: every tiny browser action is represented as a separate Activity or one Activity runs for an unbounded duration. Fix: group actions by recoverable business step, checkpoint long operations, and consider Child Workflows for independently managed resources.

Performance, reliability and cost decisions

No published benchmark establishes latency or throughput for Temporal combined with Playwright, so size capacity from your own page load times, browser startup cost, concurrency limits and external rate limits. Reuse a browser only when its lifecycle and isolation are explicit; otherwise, creating and closing a context per Activity reduces leaked session state at the cost of startup work.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep credentials and authentication state in secure storage with narrowly scoped access. Do not put secrets, cookies or full page contents into Workflow history unless you have deliberately accepted that retention and access model. Pass references or redacted summaries where possible.

Durability is not a substitute for website reliability. Pages can change, authentication can expire, bot controls can intervene and network behavior can vary. Your Workflow should distinguish transient infrastructure failures from a deterministic “the site rejected this action” result and route the latter to an alternate path or human review.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup:

For screenshot steps that do not require you to operate a browser yourself, ScreenshotNeo provides a single HTTP request. It accepts consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and response headers identify the page verdict and billing status.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the full parameter list and response details in the ScreenshotNeo documentation. The API also supports full-page captures with lazy images loaded, CSS-selector element shots, dark mode, device presets and arbitrary viewports, retina scale, PDF output, custom CSS and JavaScript, pre-capture clicks, selector waits, delay or network-idle waits, request and resource blocking, headers, cookies, user agents, Authorization, timezone and geolocation, transparent backgrounds, resizing, configurable-TTL caching, signed image links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API and an OpenAPI specification. Parameter names used by other screenshot APIs are accepted to ease migration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Python

import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo also offers an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. The Free plan includes 1,000 shots per month with no card; paid plans start at $5 for 3,000 shots. Sign up free for ScreenshotNeo.

Best Value
Sale
PowerShell for Sysadmins: Workflow Automation Made Easy
  • Book - powershell for sysadmins: workflow automation made easy
  • Language: english
  • Binding: paperback

FAQ

Can Temporal keep a browser session alive for weeks?

Not by itself. Treat the browser as an external resource with an owner, expiration policy and reacquisition path. Persist only the session information your security model allows, then recreate or reconnect it in an Activity.

Should every browser action be its own Activity?

No. Choose boundaries based on safe repetition, diagnosis and history size. A business step that can be retried or compensated is usually a better boundary than an individual click.

When is a Child Workflow justified?

Use one when a browser journey or external resource needs an independent history, lifecycle or operational ownership. Keep related short steps in the parent Workflow when a separate history adds no value.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does using a managed browser remove the need for idempotency?

No. Moving the browser process to another service changes hosting and isolation, not the interruption window between a website side effect and recorded Activity completion.

Frequently Asked Questions

Can Temporal keep a browser session alive for weeks?

Not by itself. Treat the browser as an external resource with an owner, expiration policy and reacquisition path. Persist only the session information your security model allows, then recreate or reconnect it in an Activity.

Should every browser action be its own Activity?

No. Choose boundaries based on safe repetition, diagnosis and history size. A business step that can be retried or compensated is usually a better boundary than an individual click.

When is a Child Workflow justified?

Use one when a browser journey or external resource needs an independent history, lifecycle or operational ownership. Keep related short steps in the parent Workflow when a separate history adds no value.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Does using a managed browser remove the need for idempotency?

No. Moving the browser process to another service changes hosting and isolation, not the interruption window between a website side effect and recorded Activity completion.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.