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

# Browser Controls

> Complete reference of all browser actions available in sessions

<Tip>
  STOP. Do not read past this section until you have read and followed [/quickstart.md](/quickstart.md).

  Goal: produce a reliable SDK automation script. The intended authoring flow is generate then edit, not write browser automation from scratch.

  Do not hand-write SDK code with element IDs, selectors, or form fields from memory. Element IDs, selectors, and field mappings must come from a live `observe()` call, CLI `notte page observe` output, or generated workflow code. Guessed browser targets fail on real pages.

  Use the Notte skill and CLI to inspect the live site, validate actions/selectors, handle auth/session state, and export workflow code with `notte sessions workflow-code` before using SDK docs or SDK code.

  SDK reference pages are for understanding, running, or editing generated workflow code. They are not the starting point for manually authoring the initial browser automation. SDK-first code is guesswork on real-world pages with dynamic selectors, auth state, CAPTCHAs, and anti-bot behavior.
</Tip>

Sessions provide a comprehensive set of browser actions for interacting with web pages. All actions are executed through `session.execute()`.

## Navigation Actions

### Goto

Navigate to a URL.

{/* @sniptest testers/browser-controls/goto.py */}

```python goto.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
```

**Parameters:**

* `url` (str): The URL to navigate to

**Use for:** Opening pages, navigating between pages

***

### GotoNewTab

Open a URL in a new browser tab.

{/* @sniptest testers/browser-controls/goto_new_tab.py */}

```python goto_new_tab.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto_new_tab", url="https://example.com/products")
```

**Parameters:**

* `url` (str): The URL to open in a new tab

**Use for:** Opening multiple pages simultaneously, preserving context

***

### SwitchTab

Switch to a different browser tab.

{/* @sniptest testers/browser-controls/switch_tab.py */}

```python switch_tab.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    # Open multiple tabs
    session.execute(type="goto", url="https://example.com")
    session.execute(type="goto_new_tab", url="https://example.com/products")

    # Switch back to first tab
    session.execute(type="switch_tab", tab_index=0)
```

**Parameters:**

* `tab_index` (int): Zero-based index of the tab to switch to

**Use for:** Managing multiple tabs, comparing content across pages

***

### GoBack

Navigate back to the previous page.

{/* @sniptest testers/browser-controls/go_back.py */}

```python go_back.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    session.execute(type="goto", url="https://example.com/products")

    # Go back to homepage
    session.execute(type="go_back")
```

**Use for:** Browser back button functionality, returning to previous pages

***

### GoForward

Navigate forward in browser history.

{/* @sniptest testers/browser-controls/go_forward.py */}

```python go_forward.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    session.execute(type="goto", url="https://example.com/products")
    session.execute(type="go_back")
    # Now go forward again
    session.execute(type="go_forward")
```

**Use for:** Browser forward button functionality

***

### Reload

Reload the current page.

{/* @sniptest testers/browser-controls/reload.py */}

```python reload.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    session.execute(type="reload")
```

**Use for:** Refreshing page content, retrying after errors

***

## Interaction Actions

### Click

Click on an element.

{/* @sniptest testers/browser-controls/click.py */}

```python click.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Click by CSS selector
    session.execute(type="click", selector="button#submit")

    # Pseudo observe output: [B1] button "Submit"
    # Only use IDs that appear in your live observe() output.
    session.execute(type="click", id="B1")

    # Click by text selector
    session.execute(type="click", selector="button:has-text('Submit')")
```

**Parameters:**

* `selector` (str): CSS selector for the element
* `id` (str): Element ID
* `text` (str): Exact text content
* `aria_label` (str): ARIA label attribute
* `placeholder` (str): Placeholder text
* `title` (str): Title attribute

**Use for:** Clicking buttons, links, checkboxes, any clickable element

***

### Fill

Fill a text input or textarea.

{/* @sniptest testers/browser-controls/fill.py */}

```python fill.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Fill by selector
    session.execute(type="fill", selector="input[name='email']", value="user@example.com")

    # Pseudo observe output: [I1] input "Email"
    # Only use IDs that appear in your live observe() output.
    session.execute(type="fill", id="I1", value="user@example.com")

    # Fill by placeholder selector
    session.execute(type="fill", selector="input[placeholder='Enter your email']", value="user@example.com")
```

**Parameters:**

* `selector` (str): CSS selector for the input
* `id` (str): Element ID
* `placeholder` (str): Placeholder text
* `aria_label` (str): ARIA label
* `value` (str): The text to fill

**Use for:** Filling forms, search boxes, text inputs

***

### Check

Check or uncheck a checkbox.

{/* @sniptest testers/browser-controls/check.py */}

```python check.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Check a checkbox
    session.execute(type="check", selector="input[type='checkbox']#terms", value=True)

    # Uncheck a checkbox
    session.execute(type="check", selector="input[type='checkbox']#newsletter", value=False)
```

**Parameters:**

* `selector` (str): CSS selector for the checkbox
* `id` (str): Element ID
* `checked` (bool): True to check, False to uncheck

**Use for:** Toggling checkboxes, accepting terms, selecting options

***

### SelectDropdownOption

Select an option from a dropdown.

{/* @sniptest testers/browser-controls/select_dropdown_option.py */}

```python select_dropdown_option.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Select by visible text
    session.execute(type="select_dropdown_option", selector="select#country", value="United States")

    # Select by value attribute
    session.execute(type="select_dropdown_option", selector="select#country", value="us")
```

**Parameters:**

* `selector` (str): CSS selector for the select element
* `option_text` (str): Visible text of the option
* `option_value` (str): Value attribute of the option

**Use for:** Selecting from dropdowns, choosing options

***

### PressKey

Press a keyboard key.

{/* @sniptest testers/browser-controls/press_key.py */}

```python press_key.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Press Enter
    session.execute(type="press_key", key="Enter")

    # Press Escape
    session.execute(type="press_key", key="Escape")

    # Press Tab
    session.execute(type="press_key", key="Tab")
```

**Parameters:**

* `key` (str): Key name (e.g., "Enter", "Escape", "Tab", "ArrowDown")

**Use for:** Keyboard navigation, submitting forms, triggering shortcuts

**Common keys:** Enter, Escape, Tab, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Backspace, Delete

***

### EvaluateJs

Evaluate JavaScript code on the current page and return the result.

{/* @sniptest testers/browser-controls/eval_js.py */}

```python goto_new_tab.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://notte.cc/")
    session.execute(type="evaluate_js", code="document.title")
```

**Parameters:**

* `code` (str): The JavaScript code to evaluate on the page

**Use for:** Evaluating JavaScript code, extracting data from the page

***

## Scrolling Actions

### ScrollUp

Scroll up on the page.

{/* @sniptest testers/browser-controls/scroll_up.py */}

```python scroll_up.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    session.execute(type="scroll_up")
```

**Use for:** Scrolling to top of page, revealing content above

***

### ScrollDown

Scroll down on the page.

{/* @sniptest testers/browser-controls/scroll_down.py */}

```python scroll_down.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    session.execute(type="scroll_down")
```

**Use for:** Loading lazy content, revealing content below, pagination

***

## File Actions

### UploadFile

Upload a file to a file input.

{/* @sniptest testers/browser-controls/upload_file.py */}

```python upload_file.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com/upload")

    # Upload from local file
    session.execute(type="upload_file", selector="input[type='file']", file_path="/path/to/document.pdf")

    # Upload with ID
    session.execute(type="upload_file", id="file-upload", file_path="/path/to/image.jpg")
```

**Parameters:**

* `selector` (str): CSS selector for the file input
* `id` (str): Element ID
* `file_path` (str): Path to the file to upload

**Use for:** Uploading documents, images, any file input

***

### DownloadFile

Download a file from a link.

{/* @sniptest testers/browser-controls/download_file.py */}

```python download_file.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    result = session.execute(type="download_file", selector="a.download-link")
    print(f"Downloaded: {result}")
```

**Parameters:**

* `selector` (str): CSS selector for the download link
* `id` (str): Element ID

**Use for:** Downloading files, reports, documents

***

## Wait Action

### Wait

Pause execution for a specified duration.

{/* @sniptest testers/browser-controls/wait.py */}

```python wait.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Wait 2 seconds
    session.execute(type="wait", time_ms=2000)

    # Wait 5 seconds for page to load
    session.execute(type="wait", time_ms=5000)
```

**Parameters:**

* `duration` (int): Time to wait in milliseconds

**Use for:** Waiting for page loads, animations, dynamic content

<Note>
  **Tip:** Use sparingly. Notte automatically waits for page loads and element visibility. Only use Wait for specific timing requirements.
</Note>

***

## Data Extraction

### Scrape

Extract data from the current page.

{/* @sniptest testers/browser-controls/scrape.py */}

```python scrape.py theme={null}
from notte_sdk import NotteClient
from pydantic import BaseModel

client = NotteClient()


class Product(BaseModel):
    name: str
    price: float


with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Get page markdown
    markdown = session.scrape()

    # Extract with instructions
    data = session.scrape(instructions="Extract all product names and prices")

    # Structured extraction (wrap list in a model)
    products = session.scrape(response_format=Product, instructions="Extract all products")
```

**Parameters:**

* `instructions` (str): Natural language extraction instructions
* `response_format` (type\[BaseModel]): Pydantic model for structured output
* `only_main_content` (bool): Extract only main content, ignore headers/footers

**Use for:** Data extraction, web scraping, content analysis

See [Scraping](/concepts/scraping) for detailed documentation.

***

## Communication Actions

### SmsRead

Read SMS messages from a persona's phone number.

{/* @sniptest testers/browser-controls/sms_read.py */}

```python sms_read.py theme={null}
from collections.abc import Sequence

from notte_sdk import NotteClient
from notte_sdk.types import SMSResponse

client = NotteClient()


def extract_code(messages: Sequence[SMSResponse]) -> str:
    # Extract verification code from messages
    for msg in messages:
        if msg.body and "code" in msg.body.lower():
            return msg.body
    return ""


# Create persona with phone number
persona = client.Persona(create_phone_number=True)
phone_number = persona.info.phone_number

# Use in session
with client.Session() as session:
    # Trigger SMS (e.g., 2FA code)
    if phone_number:
        session.execute(type="fill", selector="input[name='phone']", value=phone_number)
        session.execute(type="click", selector="button.send-code")

        # Read SMS from persona
        messages = persona.sms()

        # Extract verification code
        code = extract_code(messages)
```

**Parameters:**

* `persona_id` (str): Persona ID with phone number

**Use for:** Reading 2FA codes, SMS verification, phone-based authentication

See [Personas](/concepts/personas) for details.

***

### EmailRead

Read emails from a persona's email address.

{/* @sniptest testers/browser-controls/email_read.py */}

```python email_read.py theme={null}
from collections.abc import Sequence

from notte_sdk import NotteClient
from notte_sdk.types import EmailResponse

client = NotteClient()


def extract_link(messages: Sequence[EmailResponse]) -> str:
    # Extract verification link from messages
    for msg in messages:
        if msg.text_content and "verify" in msg.text_content.lower():
            return msg.text_content
    return ""


# Create persona with email
persona = client.Persona()

# Use in session
with client.Session() as session:
    # Trigger email (e.g., verification email)
    session.execute(type="fill", selector="input[name='email']", value=persona.info.email)
    session.execute(type="click", selector="button.send-verification")

    # Read emails from persona
    messages = persona.emails()

    # Extract verification link
    link = extract_link(messages)
```

**Parameters:**

* `persona_id` (str): Persona ID with email address

**Use for:** Reading verification emails, email-based authentication

See [Personas](/concepts/personas) for details.

***

## Action Patterns

### Chaining Actions

Execute multiple actions in sequence:

{/* @sniptest testers/browser-controls/action_chaining.py */}

```python action_chaining.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    # Navigation
    session.execute(type="goto", url="https://example.com/login")

    # Form filling
    session.execute(type="fill", selector="input[name='email']", value="user@example.com")
    session.execute(type="fill", selector="input[name='password']", value="password123")

    # Submission
    session.execute(type="click", selector="button[type='submit']")

    # Wait for redirect
    session.execute(type="wait", time_ms=2000)

    # Verify success
    content = session.scrape()
    print(content)
```

### Error Handling

Handle action failures:

{/* @sniptest testers/browser-controls/error_handling.py */}

```python error_handling.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Don't raise on failure
    result = session.execute(type="click", selector="button.maybe-exists", raise_on_failure=False)

    if result.success:
        print("Button clicked successfully")
        session.execute(type="click", selector="button.next")
    else:
        print(f"Click failed: {result.message}")
        # Try alternative approach
        session.execute(type="click", selector="button.alternative")
```

### Conditional Actions

Execute actions based on conditions:

{/* @sniptest testers/browser-controls/conditional_actions.py */}

```python conditional_actions.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Check if element exists
    result = session.execute(type="click", selector="button.optional", raise_on_failure=False)

    if result.success:
        # Element was there and clicked
        session.execute(type="click", selector="button.next")
    else:
        # Element wasn't there, skip
        print("Optional button not found, continuing...")
```

## Selector Strategies

### CSS Selectors

Most flexible and commonly used:

{/* @sniptest testers/browser-controls/css_selectors.py */}

```python css_selectors.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # By ID
    session.execute(type="click", selector="#submit-button")

    # By class
    session.execute(type="click", selector=".btn-primary")

    # By attribute
    session.execute(type="click", selector="button[type='submit']")

    # By combination
    session.execute(type="click", selector="form#login button.submit")

    # By nth-child
    session.execute(type="click", selector="ul li:nth-child(2)")
```

### Direct Attributes

Use direct attribute parameters when available:

{/* @sniptest testers/browser-controls/direct_attributes.py */}

```python direct_attributes.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Pseudo observe output: [B1] button "Submit"
    # Only use IDs that appear in your live observe() output.
    session.execute(type="click", id="B1")

    # By selector
    session.execute(type="click", selector="button[type='submit']")

    # By placeholder selector
    session.execute(type="fill", selector="input[placeholder='Enter email']", value="user@example.com")

    # By ARIA label selector
    session.execute(type="click", selector="button[aria-label='Close dialog']")
```

### Best Practices

**Prefer stable selectors:**

{/* @sniptest testers/browser-controls/stable_selectors.py */}

```python stable_selectors.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Good - uses ID (stable)
    session.execute(type="click", id="submit-btn")

    # Good - uses data attribute
    session.execute(type="click", selector="button[data-testid='submit']")

    # Avoid - fragile position-based
    session.execute(type="click", selector="div > div > button:nth-child(3)")
```

**Use specific selectors:**

{/* @sniptest testers/browser-controls/specific_selectors.py */}

```python specific_selectors.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")

    # Good - specific
    session.execute(type="fill", selector="form#login input[name='email']", value="user@example.com")

    # Less specific - might match wrong element
    session.execute(type="fill", selector="input", value="user@example.com")
```

## Common Workflows

### Form Submission

{/* @sniptest testers/browser-controls/form_submission.py */}

```python form_submission.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com/contact")
    session.execute(type="fill", id="name", value="John Doe")
    session.execute(type="fill", id="email", value="john@example.com")
    session.execute(type="fill", id="message", value="Hello!")
    session.execute(type="click", selector="button[type='submit']")
```

### Search and Extract

{/* @sniptest testers/browser-controls/search_extract.py */}

```python search_extract.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    session.execute(type="fill", selector="input[name='search']", value="laptop")
    session.execute(type="press_key", key="Enter")
    session.execute(type="wait", time_ms=2000)

    results = session.scrape(instructions="Extract search results")
    print(results)
```

### Multi-Tab Workflow

{/* @sniptest testers/browser-controls/multi_tab.py */}

```python multi_tab.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()


def process_data(data):
    print(f"Processed: {data[:100]}...")


with client.Session() as session:
    # Open multiple tabs
    session.execute(type="goto", url="https://site1.com")
    session.execute(type="goto_new_tab", url="https://site2.com")
    session.execute(type="goto_new_tab", url="https://site3.com")

    # Extract from each tab
    for tab_index in range(3):
        session.execute(type="switch_tab", tab_index=tab_index)
        data = session.scrape()
        process_data(data)
```

### File Upload and Download

{/* @sniptest testers/browser-controls/file_upload_download.py */}

```python file_upload_download.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com/upload")

    # Upload file
    session.execute(type="upload_file", selector="input[type='file']", file_path="/path/to/document.pdf")
    session.execute(type="click", selector="button.submit")

    # Wait for processing
    session.execute(type="wait", time_ms=3000)

    # Download result
    result = session.execute(type="download_file", selector="a.download")
    print(f"Downloaded: {result}")
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Session Configuration" icon="sliders" href="/features/sessions/configuration">
    Configure session behavior
  </Card>

  <Card title="Session Lifecycle" icon="rotate" href="/features/sessions/lifecycle">
    Manage session states
  </Card>

  <Card title="SDK Actions Reference" icon="code" href="/sdk-reference/manual/session">
    Detailed API documentation
  </Card>

  <Card title="Agent Mode" icon="sparkles" href="/concepts/agents">
    Let AI handle actions automatically
  </Card>
</CardGroup>
