notte-cli
Browser automation in your terminal
Documentation
Notte CLI - Browser automation in your terminal
What is Notte CLI?
The Notte CLI brings the full power of notte.cc to your terminal — letting you drive browser sessions and web scraping pipelines from the command line. Pair it with shell scripts, CI/CD pipelines, or AI coding assistants for repeatable, scriptable web automation.
Features
- Browser sessions - remote Chromium/Chrome with full control
- Files - upload and download files to notte.cc
- Output formats - human-readable text or JSON for scripting
- Personas - create and manage digital identities with email, phone, and SMS
- Secure credentials - system keyring for API keys, vaults for website passwords
- Web scraping - structured data extraction with custom schemas
- Functions - schedule and execute repeatable automation tasks
Installation
Homebrew
brew tap nottelabs/notte-cli https://github.com/nottelabs/notte-cli.git
brew install notteGo Install
go install github.com/nottelabs/notte-cli/cmd/notte@latestBuild from Source
git clone https://github.com/nottelabs/notte-cli.git
cd notte-cli
make buildQuick Start
1. Authenticate
Specify the API key using one of three methods (checked in priority order):
# 1. Via environment variable (recommended for CI/CD)
export NOTTE_API_KEY="your-api-key"
# 2. Via system keyring (recommended for local development)
notte auth login
# 3. Via config file (~/.notte/cli/config.json)
# create ~/.notte/cli/config.json and add your API key
notte auth status2. Start a Browser Session
notte sessions startWatch the session live through the `ViewerUrl` in the output.
Commands
Authentication
notte auth login # Store API key in system keychain
notte auth logout # Remove API key from keychain
notte auth status # Show authentication statusWeb Search
notte search # Search the web for a query
notte search --depth fast|standard|deep # Tune search depth (default: standard)
notte search --output-type sourcedAnswer # Get an LLM answer with sourcesThe query may be quoted (`notte search "what is anthropic"`) or passed as separate
words (`notte search what is anthropic`). Use `--output json` to get the raw API
response for scripting.
Browser Sessions
notte sessions list [--page N] [--page-size N] [-a|--all] # List running sessions (-a includes stopped)
notte sessions start [flags] # Start a new session
notte sessions status # Get current session status
notte sessions stop # Stop current session
notte sessions cookies # Get all cookies from current session
notte sessions cookies-set --file cookies.json # Set cookies in current session
notte sessions network # View network activity logs
notte sessions replay # Get session replay data
notte sessions workflow-code # Export session steps as Python code
notte sessions viewer # Open session viewer in browser
notte sessions code # Get Python script for session stepsNote: When you start a session, it automatically becomes the "current" session. All subsequent commands use this session by default. Use `--session-id ` only when you need to manage multiple sessions simultaneously or reference a specific session.
Session Start Options
notte sessions start \
--browser-type chromium|chrome # Browser type (default: chromium)
--idle-timeout-minutes # Idle timeout (default: 3)
--max-duration-minutes # Maximum session lifetime (default: 15)
--user-agent # Custom user agent
--viewport-width # Viewport width
--viewport-height # Viewport height
--proxy # Use default proxy rotation
--proxy-country # Proxy with specific country (e.g. us, gb, fr)
--no-solve-captchas # Turn OFF captcha solving (on by default)
--no-file-storage # Detach FileStorage (attached by default).
# Disables page download and files --from session
--advanced-stealth # Highest-fidelity browser for sites with
# sophisticated bot detection (approved workspaces)
--cdp-url # CDP URL of remote session provider
--profile-id # Profile ID to use for session
--profile-persist # Save browser state to profile on close
--vault-id # Vault used to resolve credential fields
--screenshot-type # Screenshot type (raw, full, last_action)
--chrome-args # Chrome instance arguments (repeatable)Page Actions
Interact with pages using simplified commands (requires an active session). Start
the session with `--vault-id ` before using `page fill --vault-field`:
notte page observe # Get page state and available actions
notte page scrape --instructions "..." # Scrape content from the page
notte page click "@B3" # Click an element by ID
notte page fill "@I1" "text" # Fill an input field
notte page fill "#email" --vault-field email # Fill from the session vault
notte page fill "#password" --vault-field password # Supports email, username, password, and mfa
notte page goto "https://example.com" # Navigate to a URL
notte page back # Go back in history
notte page forward # Go forward in history
notte page scroll-down [amount] # Scroll down the page
notte page scroll-up [amount] # Scroll up
notte page press "Enter" # Press a key
notte page screenshot # Take a screenshot
notte page select "option" # Select dropdown option
notte page check # Check/uncheck checkbox
notte page upload --file # Fill a file input. is a file in your
# uploads store, not a local path - send it with
# `notte files upload` first
notte page download # Download by clicking. The file lands in the
# session store; retrieve it with
# `notte files download --from session`
notte page new-tab # Open URL in new tab
notte page switch-tab # Switch to tab by index
notte page close-tab # Close current tab
notte page reload # Reload page
notte page wait # Wait for duration
notte page captcha-solve # Solve captcha
notte page eval-js "document.title" # Evaluate JavaScript in the pageEvaluating JavaScript
`page eval-js` prints the evaluated value alone on stdout — objects and
arrays as JSON, a JS `null` as `null` — with the status line on stderr, so it
captures and pipes without post-processing:
title=$(notte page eval-js "document.title")
notte page eval-js "JSON.stringify([...document.querySelectorAll('a')].map(a => a.href))" | jq lengthReturn `JSON.stringify(...)` when the answer is structured. `console.log` output
is discarded — only the returned value comes back. A failing script exits
non-zero and reports the actual JavaScript error; use `-o json` to get the full
execution result instead of the bare value.
Functions
notte functions list [--page N] [--page-size N] [--include-deleted] # List functions
notte functions create --file workflow.py # Create a new function
notte functions show # View current function details
notte functions show --function-id # View specific function details (different from current function)
notte functions download workflow.py [--version ] # Download current function code to disk
notte functions create --file workflow.py --response-format @schema.json # ... with its response documented
notte functions update --file workflow.py # Update current function code
notte functions update --file workflow.py --response-format @schema.json # ... and re-document its response
notte functions configure --run-instructions "..." --self-healing # Set usage notes and self-healing
notte functions configure --response-format @schema.json # Document run()'s return schema without re-upload
notte functions rollback --version # Restore an earlier version (see `versions` in show)
notte functions health # Runtime health: Python version, installed packages, reachability
notte functions delete # Delete current function
notte functions fork # Fork current function to new version
notte functions run # Execute current function
notte functions run --no-stream # ... returning only the final response, without streamed logs
notte functions runs [--page N] [--page-size N] [--running] # List runs for current function (--running = in-flight only)
notte functions run-stop --run-id # Stop a running function execution
notte functions run-metadata --run-id # Get run logs and results
notte functions schedule --cron "0 12 ? * * *" # Schedule current function (six-field cron: daily at noon UTC)
notte functions unschedule # Remove schedule from current functionPersonas, Profiles and Usage
notte personas update --persona-id --name "checkout tester" # Rename a persona
notte profiles cookies --profile-id # Read a profile's cookies
notte profiles cookies-set --profile-id --file cookies.json # Import cookies into a profile
notte usage logs [--endpoint /sessions/start] [--page N] # List API requests made with your key`profiles cookies-set` takes either a bare array of cookies — what Playwright's
`storageState` and the browser extensions export — or an object with a `cookies`
key. Add `--source-format chrome` if they came from Chrome, and `--mode append`
to add to the profile's cookies rather than replace them.
`--response-format` takes a JSON Schema describing what `run()` returns, as
inline JSON, `@file.json`, or `-` for stdin. The API never derives it, so a
function created without it has no documented response — which is what the
console reads to show callers the shape they will get back. From a pydantic
return model:
python -c 'import json, typing, client; print(json.dumps(typing.get_type_hints(client.run)["return"].model_json_schema()))' > schema.json
notte functions create --file client.py --response-format @schema.json
# Or document it later without re-uploading the code:
notte functions configure --response-format @schema.json`--run-instructions` is documentation for whoever *calls* the function — how long a
run takes, what each variable is for, which sites it trips over:
notte functions configure --run-instructions "Takes ~3 min, so call it async. \
Hits a captcha on the login page every few runs. \
\`query\` is the search term; \`max_items\` caps the results."It is not input to the self-healing agent, which is the separate
`--self-healing` flag.
`configure` sends only the flags you pass, so setting `--run-instructions` leaves
self-healing untouched. Disable self-healing with `--self-healing=false`: the
API treats an absent field as "leave it alone" rather than "off". Note that it
can only be enabled on functions an agent built — a CLI-created function has no
thread for the healer to resume, and the API rejects it.
Note: When you create a function, it automatically becomes the "current" function. All subsequent commands use this function by default. Use `--function-id ` only when you need to manage multiple functions simultaneously or reference a specific function.
Vaults
notte vaults list [--page N] [--page-size N] [--include-deleted] # List all vaults
notte vaults create # Create a new vault
notte vaults update --vault-id # Update vault metadata
notte vaults delete --vault-id # Delete a vault
notte vaults credentials list --vault-id # List all credentials
notte vaults credentials add --vault-id # Add credentials
notte vaults credentials get --vault-id # Get credentials for URL
notte vaults credentials delete --vault-id # Delete credentialsPersonas
notte personas list [--page N] [--page-size N] [--include-deleted] # List all personas
notte personas create # Create a new persona
notte personas show --persona-id # View persona details
notte personas delete --persona-id # Delete a persona
notte personas emails --persona-id # List emails
notte personas sms --persona-id # List SMS messagesProfiles
notte profiles list [--page N] [--page-size N] [--name "..."] [--include-deleted] # List all profiles
notte profiles create # Create a new profile
notte profiles show --profile-id # View profile details
notte profiles delete --profile-id # Delete a profileFiles
notte files upload # Upload a persistent input file
notte files list --from uploads # List persistent input files
notte files download --from uploads # Download a persistent input file
notte files list --from session [--session-id ] # List files produced by a session
notte files download [--session-id ] # Download a file produced by a sessionUtilities
notte usage # View API usage statistics
notte health # Check API health status
notte version # Show CLI versionOutput Formats
Text
Human-readable tables with colors and formatting:
$ notte sessions list
ID STATUS BROWSER CREATED
ses_abc123def456 ACTIVE chromium 2024-01-15 10:30:00
ses_xyz789uvw012 STOPPED chrome 2024-01-15 09:15:00JSON
Machine-readable output:
$ notte sessions list --output json
{
"sessions": [
{
"id": "ses_abc123def456",
"status": "ACTIVE",
"browser": "chromium",
"created_at": "2024-01-15T10:30:00Z"
}
]
}Data goes to stdout, errors and progress to stderr for clean piping.
Examples
Automated Web Scraping Pipeline
# Start session (automatically becomes the current session)
notte sessions start
# Navigate to page
notte page goto "https://news.ycombinator.com"
# Extract structured data
notte page scrape --instructions "Extract top 10 stories with title and URL"
# Cleanup
notte sessions stopRunning a Workflow
# List functions to find ID
notte functions list
# Run workflow
notte functions run --function-id func_abc123Managing Credentials Securely
# Create a vault for production credentials
VAULT_ID=$(notte vaults create --name "Production Sites" -o json | jq -r '.id')
# Add website credentials
notte vaults credentials add --vault-id $VAULT_ID \
--username "admin@example.com" \
--password "$SECURE_PASSWORD" \
--url "https://app.example.com"
# List stored credentials
notte vaults credentials list --vault-id $VAULT_IDMulti-Step Browser Automation
# Start browser with specific configuration
notte sessions start \
--browser-type chrome \
--viewport-width 1920 \
--viewport-height 1080
# Navigate and interact
notte page goto "https://example.com"
notte page click "#login-button"
notte page fill "#username" "user@example.com"
# Get current page state with available actions
notte page observe
# Stop when done
notte sessions stopJQ Filtering
# Get only active sessions (using built-in filter)
notte sessions list --all
# Paginate through results
notte sessions list --page 2 --page-size 5
# Extract session IDs with jq
notte sessions list --output json | jq -r '.sessions[].id'Usage with AI Agents
Just Ask the Agent
The simplest approach - just tell your agent to use it:
> Use notte to test the login flow. Run `notte --help` to see available commands.
The `--help` output is comprehensive and most agents can figure it out from there.
AI Coding Assistants
Add the skill to your AI coding assistant for richer context:
npx skills add nottelabs/notte-skillsThis works with Claude Code, Cursor, Windsurf, and other MCP-compatible assistants.
AGENTS.md / CLAUDE.md
For more consistent results, add to your project or global instructions file:
## Browser Automation
Use `notte` for web automation. Run `notte --help` for all commands.
Core workflow:
1. `notte sessions start` - Start a browser session
2. `notte page goto ` - Navigate to a URL
3. `notte page observe` - Get interactive elements with IDs (@B1, @B2)
4. `notte page click "@B1"` / `notte page fill "@I1" "text"` - Interact using element IDs
5. `notte page scrape --instructions "..."` - Extract structured data
6. `notte sessions stop` - Clean up when doneTips
- Viewing sessions: When you start a session, the output includes a `ViewerUrl` - open it to watch the browser live
- Session lifetime: sessions close after 3 minutes idle or 15 minutes total by default. Raise `--idle-timeout-minutes`/`--max-duration-minutes` for anything slow, or the next command fails with `Session closed`
- Element selectors: If element IDs from `observe` (like `@B1`) don't work, use Playwright selectors: `#id`, `.class`, `button:has-text('Submit')`
- Multiple matches: Use `>> nth=0` suffix to select the first match: `button:has-text('OK') >> nth=0`
- Closing modals: `notte page press "Escape"` reliably dismisses most dialogs
Skills Documentation
For comprehensive documentation including templates and reference guides, see the notte-skills/plugins/notte-cli/skills/notte-browser folder (vendored as a submodule from nottelabs/notte-skills).
Security
Credential Storage
API keys are stored securely in your system's keychain:
- macOS: Keychain Access
- Linux: Secret Service (GNOME Keyring, KWallet)
- Windows: Credential Manager
Best Practices
- Never pass API keys on the command line
- Use vaults for website passwords and payment cards
- Rotate API keys regularly from notte.cc dashboard
- Use `notte auth logout` to remove stored keys
Shell Completions
Generate shell completions for your preferred shell:
Bash
# macOS (Homebrew):
notte completion bash > $(brew --prefix)/etc/bash_completion.d/notte
# Linux:
notte completion bash > /etc/bash_completion.d/notte
# Or source directly:
source "${fpath[1]}/_notte"Fish
notte completion fish > ~/.config/fish/completions/notte.fishPowerShell
notte completion powershell | Out-String | Invoke-ExpressionDevelopment
After cloning, install git hooks:
make setupThis installs lefthook pre-commit and pre-push hooks for linting and testing.
License
This project is licensed under the MIT License.
Links
Copyright © 2025 Notte Labs, Inc.
Coverage guards
Two checks keep the CLI in step with what surrounds it. Both read a live source
of truth, so both need the network; `make` runs them with `-strict`, where an
unreachable source is a failure. The pre-commit hooks run them without it, so an
offline commit warns and proceeds.
make check-endpoints # every API endpoint is reachable or recorded as skipped
make check-skills # every command is documented in nottelabs/notte-skills
make check-coverage # both`check-endpoints` compares the API's OpenAPI spec against the commands. An
endpoint is covered when a command calls its generated client method; anything
else has to be listed in `scripts/endpoint-coverage.txt`
with a reason, as `manual` (a command builds the request itself) or `skip` (not
exposed on purpose). A line whose endpoint the API no longer serves fails too,
so the file cannot rot the way the flag generator's endpoint map did.
`check-skills` walks the cobra tree and requires every non-hidden command to be
mentioned somewhere under `plugins/notte/skills/` in the skills repository. Pass
`-skills-dir ` to check against a working copy before pushing it:
go run ./scripts/checkcoverage -check skills -skills-dir ../notte-skills -strictFrequently asked questions
What is notte-cli?
notte-cli is Browser automation in your terminal
How do I install notte-cli?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is notte-cli open source?
Yes — it is hosted on GitHub at https://github.com/nottelabs/notte-cli and has 22 stars.
Related MCP tools
Cloud browser infrastructure and web automation platform for your AI and coding agents
Automate browser based workflows with AI
eBPF-powered network observability for Kubernetes. Indexes L4/L7 traffic with full K8s context, decrypts TLS without keys. Queryable by AI agents via MCP and humans via dashboard.
GOWA - WhatsApp REST API with support for UI, Multi Account, Webhooks, and MCP, and Chatwoot. Built with Golang for efficient memory use.
The missing open-source Kubernetes UI with a built-in MCP server for AI agents. See what's broken, why, and what changed. Issues, Topology, event timeline, Helm, GitOps, live service traffic, and cluster audits - all in one Go binary.
mcp-language-server gives MCP enabled clients access semantic tools like get definition, references, rename, and diagnostics.
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP