> ## Documentation Index
> Fetch the complete documentation index at: https://docs.browserbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Automated testing

> Run reliable end-to-end browser tests at scale with Browserbase. Automate login flows, UI validation, and regression testing using Stagehand or Playwright.

Run end-to-end browser tests in consistent, isolated cloud environments. Browserbase gives you reliable infrastructure for automated testing workflows, whether you're using Stagehand or Playwright.

* Reduce flaky tests with predictable, isolated browser sessions
* Debug failures with built-in [session recordings](/platform/browser/observability/session-recording) and [screenshots](/platform/browser/files/screenshots)
* Scale test runs across [concurrent sessions](/optimizations/concurrency/overview) without managing infrastructure
* Test from different locations and viewports with [proxies](/platform/identity/proxies) and configurable browser settings

## Template

Get started quickly with a ready-to-use testing template.

<Card title="Website Link Tester" icon="rocket" href="https://www.browserbase.com/templates/website-link-tester">
  Clone, configure, and run in minutes
</Card>

## Example: Testing a login flow

To demonstrate automated testing with Browserbase, this example validates a login flow against a sample application.

### Code example

<Tabs>
  <Tab title="Node.js">
    <CodeGroup>
      ```typescript Stagehand theme={null}
      import { Stagehand } from "@browserbasehq/stagehand";
      import { z } from "zod";
      import dotenv from "dotenv";

      async function main() {
          dotenv.config();
          // initialize stagehand
          const stagehand = new Stagehand({
              env: "BROWSERBASE",
          });
          await stagehand.init();
          const page = stagehand.context.pages()[0];

          async function automatedLoginTest(inputs: any) {
              // Navigate to the form
              await page.goto("https://www.saucedemo.com/");

              await stagehand.act(`Input Username: ${inputs.username}`);
              await stagehand.act(`Input Password: ${inputs.password}`);
              await stagehand.act("Click Login Button");

              // take a screenshot of the page
              await page.screenshot({ path: "login_screenshot.png" });

              // log the url
              return page.url();
          }

          const response = await automatedLoginTest({
              username: "standard_user",
              password: "secret_sauce",
          });
          console.log(response);

          // close the stagehand session
          await stagehand.close();
      }

      main().catch(console.error);
      ```

      ```typescript Playwright theme={null}
      import { chromium } from "playwright-core";
      import Browserbase from "@browserbasehq/sdk";
      import { config } from "dotenv";
      config();

      async function createSession() {
          const bb = new Browserbase({ apiKey: process.env.BROWSERBASE_API_KEY! });
          const session = await bb.sessions.create({
              // Add configuration options here
          });
          return session;
      }

      async function automatedLoginTest(page: any, inputs: {url: string, username: string, password: string}) {
          // Navigate to page
          await page.goto(inputs.url);

          await page.locator('input[data-test="username"]').fill(inputs.username);
          await page.locator('input[data-test="password"]').fill(inputs.password);
          await page.locator('input[data-test="login-button"]').click();

          // take a screenshot of the page
          await page.screenshot({ path: "login_screenshot.png" });

          // log the url
          return page.url();
      }


      async function main() {
          const session = await createSession()
          const browser = await chromium.connectOverCDP(session.connectUrl);

          // Getting the default context to ensure the sessions are recorded.
          const defaultContext = browser.contexts()[0];
          const page = defaultContext?.pages()[0];

          console.log(`View session recording at https://browserbase.com/sessions/${session.id}`,);

          // Test login flow
          const loginResponse = await automatedLoginTest(page, {
              url: "https://www.saucedemo.com/",
              username: "standard_user",
              password: "secret_sauce",
          });
          console.log(loginResponse);

          console.log("Shutting down...");
          await page.close();
          await browser.close();
      }

      main();
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Python">
    <CodeGroup>
      ```python Stagehand theme={null}
      import os
      import asyncio
      from stagehand import AsyncStagehand
      from dotenv import load_dotenv

      load_dotenv()

      async def main():
          # initialize stagehand
          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 automated_login_test(inputs):
              # Navigate to the form
              await session.navigate(url="https://www.saucedemo.com/")

              await session.act(input=f"Input Username: {inputs['username']}")
              await session.act(input=f"Input Password: {inputs['password']}")
              await session.act(input="Click Login Button")

          await automated_login_test({
              "username": "standard_user",
              "password": "secret_sauce",
          })

          # close the stagehand session
          await session.end()

      if __name__ == "__main__":
          asyncio.run(main())
      ```

      ```python Playwright theme={null}
      import os
      from playwright.async_api import async_playwright
      from browserbase import Browserbase
      from dotenv import load_dotenv
      import asyncio

      load_dotenv()

      async def create_session():
          """Creates a Browserbase session."""
          bb = Browserbase(api_key=os.environ["BROWSERBASE_API_KEY"])
          session = bb.sessions.create(
              # Add configuration options here if needed
          )
          return session

      async def automated_login_test(page, inputs):
          """Automates login test, takes a screenshot, and returns the final URL."""
          await page.goto(inputs["url"])

          await page.locator('input[data-test="username"]').fill(inputs["username"])
          await page.locator('input[data-test="password"]').fill(inputs["password"])
          await page.locator('input[data-test="login-button"]').click()

          # Take a screenshot
          await page.screenshot(path="login_screenshot.png")

          return page.url


      async def main():
          async with async_playwright() as p:
              session = await create_session()
              print(f"View session recording at https://browserbase.com/sessions/{session.id}")
              browser = await p.chromium.connect_over_cdp(session.connectUrl)

              # Get the first context & page to ensure session recording
              context = browser.contexts[0]
              page = context.pages[0]

              # Run login automation
              login_response = await automated_login_test(page, {
                  "url": "https://www.saucedemo.com/",
                  "username": "standard_user",
                  "password": "secret_sauce",
              })
              print(f"Final URL after login: {login_response}")

              # Take a screenshot of the page
              await page.screenshot(path="login_screenshot.png")

              # Add a wait for 5 seconds
              await asyncio.sleep(5)

              print("Shutting down...")
              await page.close()
              await browser.close()

      if __name__ == "__main__":
          asyncio.run(main())
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Configuration options

### Set up a consistent environment

Test in a predictable environment with the same Chrome version every time.

<Tabs>
  <Tab title="Node.js">
    ```typescript SDK theme={null}
    // Create a standardized session
    const session = await bb.sessions.create({
      // Optional: Configure viewport size (desktop, mobile)
      browserSettings: {
        viewport: {
          width: 1280,
          height: 720
        }
      }
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python SDK theme={null}
    # Create a standardized session
    session = bb.sessions.create(
        # Optional: Configure viewport size (desktop, mobile)
        browser_settings={
          "viewport": {
            "width": 1280, 
            "height": 720
          }
        }
    )
    ```
  </Tab>
</Tabs>

### Test from different locations

Test how your app behaves from different locations:

<Tabs>
  <Tab title="Node.js">
    ```typescript SDK theme={null}
    // Create a session with proxy support
    const session = await bb.sessions.create({
      proxies: [
          {
          type: "browserbase",
          geolocation: {
              city: "New York",
              state: "NY",
              country: "US"
              }
          }
      ]
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python SDK theme={null}
    # Create a session with proxy support
    session = bb.sessions.create(
        proxies=[
            {"type": "browserbase", 
            "geolocation": {
                "city": "New York", 
                "state": "NY", 
                "country": "US"
            }
        }
        ]
    ) 
    ```
  </Tab>
</Tabs>

### Complete configuration options

Set the viewport, operating system, and [full list of configuration options](/reference/api/create-a-session) to customize your test environment.

## Best practices

### Record sessions

Every session is automatically recorded and available in the Browserbase dashboard. With [Session Recording](/platform/browser/observability/session-recording), you can watch the exact session execution to debug failures efficiently.

<Tabs>
  <Tab title="Node.js">
    ```typescript theme={null}
    console.log(`View session recording at https://browserbase.com/sessions/${session.id}`);
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    print(f"View session recording at https://browserbase.com/sessions/{session.id}")
    ```
  </Tab>
</Tabs>

**No extra setup required**—session recording happens automatically, allowing
you to diagnose flaky tests and failures with ease.

### Use metadata to organize tests

Add metadata for easier organization:

<Tabs>
  <Tab title="Node.js">
    ```typescript SDK theme={null}
    const session = await bb.sessions.create({
      userMetadata: {
          testName: "login_flow",
          suite: "authentication"
      }
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python SDK theme={null}
    session = bb.sessions.create(
        user_metadata={
          "testName": "login_flow",
          "suite": "authentication"
        }
    )
    ```
  </Tab>
</Tabs>

### Capture screenshots

Capture screenshots at critical points for easier debugging.

<Tabs>
  <Tab title="Node.js">
    ```typescript theme={null}
    // Take a screenshot
    await page.screenshot({ path: "login_screenshot.png" });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    # Take a screenshot
    await page.screenshot(path="login_screenshot.png")
    ```
  </Tab>
</Tabs>

## Next steps

<CardGroup cols={2}>
  <Card title="Session Inspector" icon="magnifying-glass" href="/platform/browser/observability/observability">
    Learn how to use the Session Inspector to debug test failures
  </Card>

  <Card title="Session Metadata" icon="tag" href="/platform/browser/core-features/session-metadata">
    Organize and query your test sessions effectively
  </Card>

  <Card title="Proxies" icon="globe" href="/platform/identity/proxies">
    Test your application from different geographic locations
  </Card>

  <Card title="Screenshots and PDFs" icon="camera" href="/platform/browser/files/screenshots">
    Capture visual evidence during test execution
  </Card>
</CardGroup>
