Automate form submissions at scale with Browserbase. Handle logins, registrations, data entry, and checkouts using Stagehand or Playwright in reliable cloud browsers.
Automate form submissions using cloud browsers that handle dynamic content, authentication, and bot protection. Browserbase gives you reliable infrastructure for form filling workflows, whether you’re using Stagehand or Playwright.
Scale form automation across concurrent sessions without managing infrastructure
Looking to deploy form automation as an API?Functions let you package form automation workflows as cloud functions that can be invoked via webhook or API call—perfect for integrating form submissions into your applications.
To demonstrate how to automate form submissions using Browserbase, you can use a sample Google Form designed specifically for this tutorial: Google FormThis form collects responses in various formats:
import { Stagehand } from "@browserbasehq/stagehand";import { z } from "zod";import dotenv from "dotenv";dotenv.config();async function main() { const stagehand = new Stagehand({ env: "BROWSERBASE", verbose: 0, }); await stagehand.init(); const page = stagehand.context.pages()[0]; async function fillForm(inputs: any) { // Navigate to the form await page.goto("https://forms.gle/f4yNQqZKBFCbCr6j7"); // Select the superpower radio button await stagehand.act(`Select the superpower: ${inputs.superpower}`); // Select the features used checkboxes await stagehand.act("Select the features used: " + inputs.features_used.join(", ")); // Fill in the coolest build text field await stagehand.act("Fill in the coolest_build field with the following value: " + inputs.coolest_build); // Submit the form await stagehand.act("Click the submit button"); await page.waitForTimeout(5000); // Extract to log the status of the form const status = await stagehand.extract({instruction: "Extract the status of the form", schema: z.object({status: z.string()})}); console.log(status); await stagehand.close(); } const inputs = { "superpower": "Invisibility", "features_used": [ "Verified", "Proxies", "Session Replay" ], "coolest_build": "A bot that automates form submissions across multiple sites.", } await fillForm(inputs);}main().catch(console.error);
import osimport asynciofrom stagehand import AsyncStagehandfrom dotenv import load_dotenvload_dotenv()async def main(): client = AsyncStagehand( browserbase_api_key=os.environ["BROWSERBASE_API_KEY"], model_api_key=os.environ["MODEL_API_KEY"], ) session = await client.sessions.create(model_name="google/gemini-2.5-flash") async def fill_form(inputs): # Navigate to the form await session.navigate(url="https://forms.gle/f4yNQqZKBFCbCr6j7") # Select the superpower radio button await session.act(input=f"Select the superpower: {inputs['superpower']}") # Select the features used checkboxes await session.act(input="Select the features used: " + ", ".join(inputs["features_used"])) # Fill in the coolest build text field await session.act(input="Fill in the coolest_build field with the following value: " + inputs["coolest_build"]) # Submit the form await session.act(input="Click the submit button") await fill_form({ "superpower": "Invisibility", "features_used": [ "Verified", "Proxies", "Session Replay" ], "coolest_build": "A bot that automates form submissions across multiple sites.", }) await session.end()if __name__ == "__main__": asyncio.run(main())
This example form is for testing purposes - feel free to submit responses multiple times while experimenting.
Target specific form elements with waitForSelector rather than using arbitrary timeouts. This ensures your automation proceeds only when the form is ready.
Node.js
Python
// Wait for a specific input field to appearawait page.waitForSelector('input[name="email"]', { timeout: 10000 });await page.fill('input[name="email"]', "user@example.com");
# Wait for a specific input field to appearpage.wait_for_selector('input[name="email"]', timeout=10000)page.fill('input[name="email"]', "user@example.com")
Forms that reveal fields based on previous selections need sequential interaction. Wait for each new section to render before continuing.
Node.js
Python
// Select an option that reveals additional fieldsawait page.selectOption('select[name="account_type"]', "business");// Wait for the dynamically revealed fieldsawait page.waitForSelector('input[name="company_name"]', { state: "visible" });await page.fill('input[name="company_name"]', "Acme Corp");
# Select an option that reveals additional fieldspage.select_option('select[name="account_type"]', "business")# Wait for the dynamically revealed fieldspage.wait_for_selector('input[name="company_name"]', state="visible")page.fill('input[name="company_name"]', "Acme Corp")
Check for confirmation messages, URL changes, or response status after submitting a form.
Node.js
Python
await page.click('button[type="submit"]');// Check for a success message or URL changeawait page.waitForSelector("text=Your response has been recorded.");const currentUrl = page.url();console.log(`Submission complete. Redirected to: ${currentUrl}`);
page.click('button[type="submit"]')# Check for a success message or URL changepage.wait_for_selector("text=Your response has been recorded.")current_url = page.urlprint(f"Submission complete. Redirected to: {current_url}")