Skip to main content
STOP. Do not read past this section until you have read and followed /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.
Learn how to write Function scripts and deploy them to Notte’s serverless infrastructure.

Writing a Function

Functions are Python scripts with a run() function that serves as the entry point.

Basic Function

The minimal Function structure:
hello_function.py
def run():
    """A simple function that returns a greeting."""
    return "Hello from Notte Functions!"

Function with Parameters

Accept input parameters:
greet_function.py
def run(name: str, greeting: str = "Hello"):
    """
    Greet someone by name.

    Args:
        name: The person's name
        greeting: The greeting word (default: "Hello")

    Returns:
        A personalized greeting
    """
    return f"{greeting}, {name}!"

Browser Automation Function

Use Notte SDK for browser automation:
scraper_function.py
from notte_sdk import NotteClient


def run(url: str, selector: str):
    """
    Scrape data from a website.

    Args:
        url: The website URL
        selector: CSS selector for target element

    Returns:
        Extracted data
    """
    client = NotteClient()

    with client.Session() as session:
        session.execute(type="goto", url=url)
        data = session.scrape(instructions=f"Extract content from {selector}")

    return {"url": url, "data": data}

Deploying Functions

Via SDK

Deploy from Python:
deploy_sdk.py
from notte_sdk import NotteClient

client = NotteClient()

# Deploy function
function = client.Function(path="scraper_function.py", name="Website Scraper", description="Scrapes data from websites")

print(f"Function deployed: {function.function_id}")
print(f"Version: {function.response.latest_version}")

Deployment Options

deployment_options.py
from notte_sdk import NotteClient

client = NotteClient()

function = client.Function(
    path="my_function.py",
    name="My Function",  # Display name
    description="What this function does",  # Description
    shared=False,  # Private by default
)
Parameters:
  • workflow_path (str, required): Path to your Python file
  • name (str, optional): Function display name
  • description (str, optional): What the function does
  • shared (bool, default=False): Whether function is publicly accessible

Function Requirements

The Handler

Must have a run() function:
handler_examples.py
# Correct
def run(param1, param2):
    return "result"


# Wrong - different name
def execute(param1, param2):
    return "result"


# Wrong - no function
result = perform_task()

Dependencies

Import Notte SDK and standard libraries:
dependencies.py
# Built-in imports

# Notte SDK

# Third-party (common libraries available)


def run():
    # Your code
    pass
Available packages:
  • notte-sdk - Notte SDK
  • requests - HTTP client
  • pydantic - Data validation
  • Standard Python library
  • Most common packages

Return Values

Return JSON-serializable data:
return_values.py
def valid_returns():
    # Valid return types (JSON serializable)
    return "string"
    return 123
    return {"key": "value"}
    return ["item1", "item2"]
    return None


def invalid_returns():
    # Invalid returns (not JSON serializable)
    # return datetime.now()  # datetime not serializable
    # return lambda x: x     # functions not serializable
    pass

Parameter Types

Supported Types

parameter_types.py
def run(
    text: str,  # String
    number: int,  # Integer
    decimal: float,  # Float
    flag: bool,  # Boolean
    items: list,  # List
    data: dict,  # Dictionary
    optional: str | None = None,  # Optional
    with_default: int = 10,  # Default value
):
    pass

Type Validation

Use type hints for automatic validation:
type_validation.py
def run(count: int):
    # count is automatically validated as int
    for i in range(count):
        print(i)

Complex Types

Use Pydantic for structured parameters:
complex_types.py
from notte_sdk import NotteClient
from pydantic import BaseModel


class SearchParams(BaseModel):
    url: str
    query: str
    max_results: int = 10


def run(params: SearchParams):
    # params is validated against SearchParams model
    client = NotteClient()
    # Use params.url, params.query, etc.

Environment Variables

Access secrets securely:
environment_variables.py
import os

from notte_sdk import NotteClient


def run():
    # Access environment variables
    api_key = os.getenv("MY_API_KEY")
    webhook_url = os.getenv("WEBHOOK_URL")

    if not api_key:
        return {"error": "API key not configured"}

    # Use in automation
    client = NotteClient(api_key=api_key)
Set environment variables in Console or locally for testing.

Error Handling

Graceful Errors

Return error information in results:
graceful_errors.py
from notte_sdk import NotteClient


def run(url: str):
    try:
        client = NotteClient()
        with client.Session() as session:
            session.execute(type="goto", url=url)
            data = session.scrape()

        return {"success": True, "data": data}

    except Exception as e:
        return {"success": False, "error": str(e), "error_type": type(e).__name__}

Raising Exceptions

Let Functions fail explicitly:
raising_exceptions.py
def run(url: str):
    if not url.startswith("https://"):
        raise ValueError("URL must use HTTPS")

    # Continue with automation

Testing Locally

Test Before Deploying

Run your function locally:
test_locally.py
# Define your function (from your scraper_function.py)
def run(url: str, selector: str) -> dict:
    # Your scraping logic here
    return {"url": url, "selector": selector}


# Test with sample parameters
result = run(url="https://example.com", selector=".content")

print(result)

Mock API Calls

Test without deploying:
mock_api_calls.py
from notte_sdk import NotteClient

client = NotteClient()

# Load existing function with decryption key for local execution
function = client.Function(
    function_id="func_abc123",
    decryption_key="your-decryption-key",  # Required for local execution
)

# Run locally (not on cloud)
result = function.run(local=True, url="https://example.com")

print(result.result)

Best Practices

1. Document Parameters

Use clear docstrings:
document_params.py
def run(url: str, max_retries: int = 3):
    """
    Fetch data from a website with retries.

    Args:
        url: The website URL to scrape
        max_retries: Number of retry attempts on failure (default: 3)

    Returns:
        Dict with 'success' (bool) and 'data' (any) keys
    """
    pass

2. Return Structured Data

Use consistent return formats:
return_structured.py

def run(url: str):
    try:
        # Perform automation
        data = scrape_url(url)

        return {"success": True, "data": data, "url": url, "timestamp": datetime.now().isoformat()}

    except Exception as e:
        return {"success": False, "error": str(e), "url": url}

3. Add Logging

Log key steps for debugging:
add_logging.py
from loguru import logger
from notte_sdk import NotteClient


def run(url: str):
    logger.info(f"Starting scrape of {url}")

    client = NotteClient()
    with client.Session() as session:
        logger.info("Session created")
        session.execute(type="goto", url=url)
        logger.info("Page loaded")

        data = session.scrape()
        logger.info(f"Extracted {len(data)} items")

    return data

4. Set Timeouts

Prevent functions from hanging:
set_timeouts.py
from notte_sdk import NotteClient


def run(url: str):
    client = NotteClient()

    # Set session timeout
    with client.Session(idle_timeout_minutes=5) as session:
        session.execute(type="goto", url=url)
        data = session.scrape()

    return data

5. Validate Inputs

Check parameters before processing:
validate_inputs.py
def run(url: str, count: int):
    # Validate inputs
    if not url.startswith("http"):
        return {"error": "Invalid URL format"}

    if count < 1 or count > 100:
        return {"error": "Count must be between 1 and 100"}

    # Proceed with automation
    pass

Examples

Simple Scraper

simple_scraper.py
from notte_sdk import NotteClient


def run(url: str):
    """Scrape page content."""
    client = NotteClient()

    with client.Session() as session:
        session.execute(type="goto", url=url)
        content = session.scrape()

    return content

Form Submission

form_submission.py
from notte_sdk import NotteClient


def run(form_url: str, name: str, email: str, message: str):
    """Submit a contact form."""
    client = NotteClient()

    with client.Session() as session:
        session.execute(type="goto", url=form_url)
        session.execute(type="fill", id="name", value=name)
        session.execute(type="fill", id="email", value=email)
        session.execute(type="fill", id="message", value=message)
        session.execute(type="click", selector="button[type='submit']")

    return {"status": "submitted"}

Data Extraction

structured_extraction.py
from notte_sdk import NotteClient
from pydantic import BaseModel


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


def run(product_url: str):
    """Extract structured product data."""
    client = NotteClient()

    with client.Session() as session:
        session.execute(type="goto", url=product_url)

        product = session.scrape(response_format=Product, instructions="Extract product details")

    return product.model_dump()

Next Steps

Invocations

Learn how to call your Functions

Schedules

Schedule Functions to run automatically

Management

Update and manage Functions

Functions Concept

Back to Functions overview