Skip to main content

When to use this

Use this when a browser action needs a human decision on the exact values about to be submitted. The application enforces approval and a single attempt; the model cannot grant consent. The TypeScript version demonstrates an AI SDK tool loop. Python and Go use a direct CLI gate.

Goal and output

Fill the httpbin test form in a Browserbase cloud browser. Pause before the final act() that submits it. Answering n exits without submitting; answering y submits once and prints the destination URL. This is a local CLI approval example, not a persistent review service.

Agent prompt

Add an approval gate before Stagehand submits a form.

Prerequisites and inputs

Add BROWSERBASE_API_KEY and OPENAI_API_KEY to .env. Each language uses OpenAI for Stagehand; TypeScript also uses it for the AI SDK agent. See model configuration. TypeScript requires Node.js 22.18+ and pnpm, Python requires Python 3.11+ and uv, and Go requires Go 1.26+. The form uses test customer data. Change it with the form checks when adapting the job.

Check out and run

The source is packages/examples/cookbooks/approve-form-submission. Clone this folder with the overview command, then use one language:

How the job works

1

Fill the form

Launch Browserbase and create Stagehand. Keep both alive until the answer is received.
2

Review and approve

Fill the form with act() and %variable% placeholders. Check each result’s success field so a failed fill cannot proceed to approval.
3

Submit once

Present a single submit action. TypeScript separates fillForm and submitForm tools; generateText uses toolApproval: { submitForm: "user-approval" }. Python and Go read y or n from stdin before the submit call.
4

Verify the result

Submit at most once, print the result URL, and close both resources in finally or deferred cleanup.
Define the submit action as a tool, then require approval in the AI SDK loop:
TypeScript waits up to 60 seconds for an answer. A code guard freezes form values after filling and allows one approved submit attempt. Every language shows actual input values and rechecks them before Submit. Rejection returns immediately. out/approval.json records pending, approved, rejected, submission-attempted, or submitted state. An attempted state can mean the server accepted the form even if the browser call failed. Inspect the session before starting another run. This recipe keeps approval inside one process. The receipt is an audit record, not a resume token. To support approval across service restarts, persist the exact action and model messages in your application, bind the decision to that action, and reconcile ambiguous submits before retrying. Browser sessions expire after five minutes.
These excerpts show the approval flow. The runnable project also verifies form values and prevents repeated submission.

Expected result and failure checks

The filled page appears before Submit this form? [y/N]. n prints a rejection and never clicks Submit. y produces one submission and a URL. Missing keys fail before browser launch. A failed form action or submission exits with an error.

Adapt to your site

Change the form fields, input-value checks, and verified confirmation destination together. Keep the approval decision bound to the displayed values. Preserve the guard before the submit call and reconcile an ambiguous attempt before restarting. Distributed approval requires durable application state beyond this CLI receipt. Variables and actions, persisted login, and AI SDK integration.