Documentation Index Fetch the complete documentation index at: https://notte-experiment-visibility-md-links.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Functions are serverless deployments of your browser automations that can be invoked via API, scheduled to run automatically, or triggered by events.
What are Functions?
Functions turn your automation scripts into:
API endpoints you can call with HTTP requests
Scheduled jobs that run on a cron schedule
Reusable workflows accessible from anywhere
Shareable automations for your team
Unlike running scripts locally, Functions:
✅ Run on Notte’s infrastructure (no servers to manage)
✅ Scale automatically based on demand
✅ Provide built-in logging and monitoring
✅ Can be invoked from any platform (Python, JavaScript, cURL, etc.)
✅ Support scheduling and automation
How Functions Work
1. Write Your Script
Create a Python file with a run() function:
from notte_sdk import NotteClient
client = NotteClient()
def run ( url : str , search_query : str ):
"""Search a website url and extract results."""
with client.Session() as session:
# Navigate to site
session.execute( type = "goto" , url = url)
# Search
session.execute( type = "fill" , selector = "input[name='search']" , value = search_query)
session.execute( type = "press_key" , key = "Enter" )
# Extract results
results = session.scrape( instructions = "Extract search results" )
return results
2. Deploy to Notte
Upload your script to create a Function:
from notte_sdk import NotteClient
client = NotteClient()
# Deploy function
function = client.Function(
path = "my_automation.py" , name = "Search Automation" , description = "Searches a website and extracts results"
)
print ( f "Function deployed: { function.function_id } " )
print ( f "Version: { function.response.latest_version } " )
3. Invoke the Function
Call your Function as an API:
# Via SDK
result = function.run( url = "https://example.com" , search_query = "laptop" )
print (result.result)
# Via cURL
curl -X POST https://api.notte.cc/functions/{function_id}/runs/start \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"function_id": "workflow_123",
"variables": {
"url": "https://example.com",
"search_query": "laptop"
}
}'
Function Structure
The Handler Function
Functions must have a run() function that serves as the entry point:
def run ( param1 : str , param2 : int = 10 ):
"""
Function docstring explains what it does.
Args:
param1: Description of param1
param2: Description of param2 (optional)
Returns:
Description of return value
"""
# Your automation code
result = perform_automation(param1, param2)
return result
Key points:
Named run() - this is the entry point
Can accept parameters (passed as variables when invoked)
Should have type hints for clarity
Should include docstring documentation
Returns a value (any JSON-serializable type)
Parameters
Define parameters as arguments to the run function:
from notte_sdk import NotteClient
def run ( email : str , password : str , product_id : str ):
client = NotteClient()
with client.Session() as session:
session.execute( type = "fill" , id = "email" , value = email)
session.execute( type = "fill" , id = "password" , value = password)
session.execute( type = "goto" , url = f "https://example.com/product/ { product_id } " )
Pass values when invoking the function:
function.run( email = "user@example.com" , password = "secret" , product_id = "123" )
Return Values
Functions can return any JSON-serializable data:
from pydantic import BaseModel
# Return string
def run_string ():
return "Task completed successfully"
# Return dict
def run_dict ():
extracted_data = [ "item1" , "item2" ]
return { "status" : "success" , "data" : extracted_data, "count" : len (extracted_data)}
# Return list
def run_list ():
return [ "item1" , "item2" , "item3" ]
# Return Pydantic model (serialized)
class Result ( BaseModel ):
success: bool
data: list[ str ]
def run ():
return Result( success = True , data = [ "a" , "b" ]).model_dump()
Use Cases
1. Scheduled Scraping
Extract data on a schedule:
# price_monitor.py
def run ( product_urls : list[ str ]):
run_client = NotteClient()
prices = []
for url in product_urls:
with run_client.Session() as session:
session.execute( type = "goto" , url = url)
price = session.scrape( instructions = "Extract product price" )
prices.append({ "url" : url, "price" : price})
return prices
# Deploy and schedule to run daily
Schedule: 0 9 * * * (Every day at 9 AM)
2. API Endpoints
Expose automation as an API:
from notte_sdk import NotteClient
# contact_extractor.py
def run ( company_url : str ):
client = NotteClient()
with client.Session() as session:
session.execute( type = "goto" , url = company_url)
contact_info = session.scrape( instructions = "Extract contact email and phone" )
return contact_info
# Now callable from any service
# GET /functions/{id}/runs/start?variables={"company_url": "..."}
3. Webhooks
Trigger automations from external events:
from notte_sdk import NotteClient
# order_processor.py
def run ( order_id : str , action : str ):
client = NotteClient()
with client.Session() as session:
# Login to admin panel
session.execute( type = "goto" , url = "https://admin.example.com" )
# Process order
if action == "fulfill" :
session.execute( type = "click" , selector = f "button[data-order=' { order_id } '].fulfill" )
elif action == "refund" :
session.execute( type = "click" , selector = f "button[data-order=' { order_id } '].refund" )
return { "order_id" : order_id, "action" : action, "status" : "completed" }
# Called via webhook from your e-commerce platform
4. Batch Processing
Process multiple items in parallel:
from concurrent.futures import ThreadPoolExecutor
from notte_sdk import NotteClient
# bulk_data_extract.py
def run ( urls : list[ str ], max_workers : int = 5 ):
client = NotteClient()
def extract_from_url ( url ):
with client.Session() as session:
session.execute( type = "goto" , url = url)
data = session.scrape()
return { "url" : url, "data" : data}
with ThreadPoolExecutor( max_workers = max_workers) as executor:
results = list (executor.map(extract_from_url, urls))
return results
How Functions Fit In
Functions are a deployment layer - they turn any automation into a reusable API.
┌─────────────────────────────────────────────────────┐
│ Function │
│ (Deployment & Scheduling) │
├─────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Scripted │ or │ Agent │ │
│ │ Automation │ │ (AI-driven) │ │
│ └────────┬────────┘ └────────┬────────┘ │
│ │ │ │
│ └──────────┬───────────┘ │
│ │ │
│ ┌────────▼────────┐ │
│ │ Session │ │
│ │ (Cloud Browser) │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
Session - The cloud browser that runs everything
Scripted Automation vs Agent - How you control the session
Function - Deploys your automation as an API with scheduling, versioning, and sharing
Use Functions when:
You need to run automation repeatedly
You want to expose automation as an API
You need scheduling capabilities
You want to share automation with team or customers
Functions can contain either scripted automation or agents - they’re not mutually exclusive.
Function Lifecycle
Write - Create Python script with run() function
Deploy - Upload to Notte (creates function ID)
Version - Notte tracks versions automatically
Invoke - Call via API, schedule, or webhook
Execute - Runs on Notte infrastructure
Monitor - View logs, replays, and results
Best Practices
1. Use Clear Parameters
Define parameters with type hints and descriptions:
def run ( target_url : str , max_results : int = 10 , timeout_seconds : int = 30 ):
"""
Extract data from a website.
Args:
target_url: The URL to scrape
max_results: Maximum number of results to extract
timeout_seconds: Session timeout
"""
pass
2. Return Structured Data
Always return JSON-serializable data:
from datetime import datetime
def my_function ():
results = [] # your data
# Good - return JSON-serializable dict
return { "success" : True , "data" : results, "count" : len (results), "timestamp" : datetime.now().isoformat()}
# Bad - not JSON serializable
# return datetime.now() # Can't serialize datetime directly
3. Handle Errors Gracefully
Catch exceptions and return meaningful errors:
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__ }
4. Add Logging
Log important steps for debugging:
from loguru import logger
from notte_sdk import NotteClient
def run ( url : str ):
logger.info( f "Starting automation for { url } " )
client = NotteClient()
with client.Session() as session:
logger.info( "Session started" )
session.execute( type = "goto" , url = url)
logger.info( "Navigation complete" )
data = session.scrape()
logger.info( f "Extracted { len (data) } items" )
return data
Next Steps
Creating Functions Learn how to write and deploy Functions
Invocations Call Functions via API, SDK, or cURL
Schedules Schedule Functions with cron
Management Update, version, and monitor Functions