Skip to main content
If you only need the result, use runs.wait_for_completion() in Python or runs.waitForCompletion() in TypeScript. It polls the lightweight status endpoint instead of downloading every event. For a custom UI, poll runs.events() with the previous cursor. Read status before fetching events so that the final fetch happens after you observe a terminal state, and drain all hasMore pages before stopping:
A run writes ordered events. Your loop reads a page of events after a cursor, passes nextAfter as the next after value, and keeps reading while hasMore is true. A run writes ordered events. Your loop reads a page of events after a cursor, passes nextAfter as the next after value, and keeps reading while hasMore is true. Events cover run lifecycle, model calls, browser readiness, tool activity, artifacts, and completion. See Get run events for the complete response shape.

Browser events

browser.released status is kept_alive (the browser is still open for follow-ups), already_stopped, no_browser or browser_not_found. With kept_alive, timeout_at is the browser’s 4-hour hard limit, not when it stops: an idle browser stops about 2 minutes after the session’s last run, or after the run’s keepAlive seconds. For browser HTTP request metadata, attach your own live CDP observer with Capture browser network events. This two-second interval is an example for one stream, not a safe default for an unbounded batch. Event reads share the project’s general request bucket. Use a shared rate limiter and stagger polling across runs. Keep the cursor when backing off after a 429, and resume from it rather than rereading history. See Concurrency and rate limits for capacity, request budgets, retries, and the separate per-session message queue.