Skip to main content

Yutori Python SDK & CLI

PyPI version Python 3.9+

The official Python SDK and CLI for the Yutori API — build web agents that autonomously execute tasks on the web.

The SDK offers sync and async clients with full type annotations, plus a yutori CLI for authentication and managing resources from the terminal.

AI agent install (recommended)

Paste this into Claude Code, Codex, Cursor, Windsurf, or another coding agent:

Use https://yutori.com/api/llms.txt and set up Yutori for me.

Manual install

On macOS or Linux, the recommended setup is the one-line installer:

curl -fsSL https://yutori.com/install.sh | bash

Installs the global yutori CLI via uv tool install and prompts to add the SDK to your project, run yutori auth login, register the MCP server, install workflow skills, and verify with a browsing task.

Python 3.9+ is required for the SDK.

Non-interactive install (CI, pipe, AI coding agent)

The SDK install, auth, and verification steps are skipped — auth needs a browser, verification needs an API key. MCP server and workflow skills install automatically without prompts.

To scope the MCP install to one coding agent, set YUTORI_INSTALL_CLIENT=<slug> (e.g. claude-code, codex, cursor). Unset, it registers for claude-code, codex, cursor, and gemini-cli. Run npx add-mcp list-agents for the full slug list.

Uninstall the CLI later
curl -fsSL https://yutori.com/uninstall.sh | bash

Removes the global yutori CLI. Saved credentials at ~/.yutori/ are left in place so they survive reinstalls — rm -rf ~/.yutori manually if you want a clean slate. Set YUTORI_UNINSTALL_ASSUME_YES=1 for scripted runs.

Install the package manually
pip install yutori

Or add it to an existing project with uv:

uv add yutori
Authenticate manually

Run this once to save your API key:

yutori auth login

This opens your browser to log in with your Yutori account and saves an API key to ~/.yutori/config.json. The SDK and CLI automatically pick it up.

If you installed the package with uv add, run uv run yutori auth login instead.

Or use an env var / pass the key explicitly:

from yutori import YutoriClient

client = YutoriClient()                  # Uses saved credentials or YUTORI_API_KEY
client = YutoriClient(api_key="yt-...")  # Or pass explicitly

Resolution order: explicit api_key > YUTORI_API_KEY env var > ~/.yutori/config.json.

Configure MCP server and skills manually

The installer sets these up automatically when Node.js is available. To do it manually:

npx add-mcp "uvx yutori-mcp"
npx skills add yutori-ai/yutori-mcp -g

The first command registers the Yutori MCP server with your editor. The second installs workflow skills for Claude Code and compatible agents.

API Overview

The Yutori API provides four main capabilities:

API Description SDK Namespace
Navigator Browser- and computer-use models (Navigator n1, n1.5, n2 preview) client.chat
Browsing One-time browser automation tasks client.browsing
Research Deep web research using 100+ tools client.research
Scouting Continuous web monitoring on a schedule client.scouts

Navigator API

The Navigator API hosts Yutori's visual-control models. Navigator n1 (n1-latest) and Navigator n1.5 (n1.5-latest) control browsers; the gated Navigator n2 preview (n2-preview) controls a complete desktop. Capture a screenshot, send it to the model, and execute the returned tool calls. The endpoint follows the OpenAI Chat Completions interface, so client.chat is a drop-in OpenAI-compatible client:

from yutori import AsyncYutoriClient
from yutori.navigator import aplaywright_screenshot_to_data_url
from playwright.async_api import async_playwright

async with AsyncYutoriClient() as client, async_playwright() as p:
    browser = await p.chromium.launch()
    page = await browser.new_page()
    await page.goto("https://www.yutori.com")

    image_url = await aplaywright_screenshot_to_data_url(page)

    response = await client.chat.completions.create(
        messages=[
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "List the team member names."},
                    {"type": "image_url", "image_url": {"url": image_url}},
                ],
            }
        ],
    )

    message = response.choices[0].message
    print(message.content)  # Model's thoughts
    for tool_call in message.tool_calls or []:
        # Execute the requested browser action on `page`, append the tool
        # result to the conversation, capture a fresh screenshot, and call
        # the model again...
        ...

This snippet shows a single model call. In practice, you'll usually run an agent loop: execute the returned actions on the page, capture a fresh screenshot, and call the model again until it emits stop. Complete agent loops live in examples/.

The SDK defaults to Navigator n1.5 (n1.5-latest). Navigator n1 (n1-latest) is still supported for callers that want the older model. Navigator n1.5 adds selectable tool sets, disable_tools, and structured JSON output via json_schema (returned as response.parsed_json). See the Navigator n1.5 reference and Navigator n1 reference for model IDs, parameters, and the full action space.

Navigator n2 is a gated, non-streaming preview and does not change the SDK default. Pass an explicit dated tool_set; computer_use_tools-20260815 is the current macOS surface with nested batches, screenshots, local bash, and atomic click modifiers. n2 rejects caller-provided tools, disable_tools, json_schema, response_format, and non-auto tool_choice. The server preserves every screenshot in the two newest image-bearing messages (text-only messages do not consume a slot), strips older image parts while preserving other history, and inserts [Earlier screenshot omitted.] only when n2 pruning empties a message.

The Navigator API enforces a 10,000,000-byte complete-body limit. SDK trimming helpers use a separate 9,500,000-byte serialized-messages budget, reserving 500,000 bytes for the rest of the request. See the n2 Cua cookbooks for local macOS and disposable sandbox loops.

For direct macOS use, install the pinned driver extra and prepare the optional overlay before task startup:

python -m pip install 'yutori[macos]==0.9.0'
cua-driver permissions grant
python -c 'from yutori.navigator.macos import prepare_macos_overlay; prepare_macos_overlay()'

MacOSComputer then owns the persistent driver session, capture/input, shell lifecycle, cancellation, recovery, and presentation. Local shell execution remains disabled unless the caller passes allow_local_shell=True. The yutori-mcp computer-use setup command is the supported all-in-one installer and readiness flow.

Agent-loop helpers

The yutori.navigator subpackage exposes optional helpers for typical agent loops:

Helper Purpose
aplaywright_screenshot_to_data_url(page) Capture a Playwright screenshot as a Navigator-optimized WebP data URL.
denormalize_coordinates(coords, width, height) Map the Navigator 1000×1000 coordinate space to viewport pixels.
format_task_with_context(task, ...) Append location, timezone, and current date to a task message.
format_stop_and_summarize(task) Ask the model to summarize when hitting max steps or an error.
trimmed_messages_to_fit(messages, max_bytes, keep_recent) Drop older screenshots to stay under the serialized-messages budget.
map_key_to_playwright(key) / map_keys_individual(keys) Convert Navigator n1.5's lowercase key names to Playwright format.
yutori.navigator.tools Packaged JS reference implementations for the Navigator n1.5 expanded tools (extract_elements, find, set_element_value, execute_js).

Full helper reference: api.md.

If you'd rather not manage browser infrastructure, use the Browsing API below, which runs the Navigator on Yutori's cloud browser.

Browsing API

Run one-time browser automation tasks on Yutori's cloud browser (or on Yutori Local with the user's logged-in desktop sessions):

task = client.browsing.create(
    task="Give me a list of all employees (names and titles) of Yutori.",
    start_url="https://yutori.com",
)

# Poll for completion
import time
while True:
    result = client.browsing.get(task["task_id"])
    if result["status"] in ("succeeded", "failed"):
        break
    time.sleep(5)

print(result)

Common options: require_auth=True for login flows, browser="local" for Yutori Local, webhook_url=... for async completion notifications. Failed tasks may include a rejection_reason.

client.browsing.list() enumerates your browsing tasks — omit limit to get them all, or pass status (running/succeeded/failed) and cursor to filter and paginate.

Structured output

Define the output structure with a JSON Schema dict or a Pydantic model:

from pydantic import BaseModel  # optional dependency

class Employee(BaseModel):
    name: str
    title: str

task = client.browsing.create(
    task="Give me a list of all employees (names and titles) of Yutori.",
    start_url="https://yutori.com",
    output_schema=Employee,  # Auto-converted to JSON Schema
    webhook_url="https://example.com/webhook",
)

The same output_schema pattern applies to client.research.create and client.scouts.create.

Research API

Perform deep web research using 100+ MCP tools (search engines, APIs, data sources):

task = client.research.create(
    query="What are the latest developments in quantum computing from the past week?",
    user_timezone="America/Los_Angeles",
)

# Poll for results
while True:
    result = client.research.get(task["task_id"])
    if result["status"] in ("succeeded", "failed"):
        break
    time.sleep(5)

Failed tasks may include a rejection_reason.

client.research.list() enumerates your research tasks — handy for exporting or recovering task IDs from a large batch. Omit limit to get them all, or pass status / cursor to filter and paginate:

completed = client.research.list(status="succeeded")
for t in completed["tasks"]:
    print(t["task_id"], t["created_at"])

Scouting API

Scouts run on a schedule to monitor the web and notify you when relevant updates occur:

scout = client.scouts.create(
    query="News, product updates, and announcements about Yutori AI",
    output_interval=86400,  # Daily (seconds, min 1800)
    webhook_url="https://example.com/webhook",
)

# Manage scouts
scouts = client.scouts.list(status="active")
client.scouts.update(scout["id"], status="paused")
client.scouts.update(scout["id"], status="active")
updates = client.scouts.get_updates(scout["id"], limit=20)
client.scouts.delete(scout["id"])

Async Usage

AsyncYutoriClient mirrors YutoriClient with async methods:

import asyncio
from yutori import AsyncYutoriClient

async def main():
    async with AsyncYutoriClient() as client:
        usage = await client.get_usage()
        scouts = await client.scouts.list()
        print(usage, scouts)

asyncio.run(main())

Error Handling

from yutori import YutoriClient, APIError, APIConnectionError, AuthenticationError

try:
    client.get_usage()
except AuthenticationError as e:
    print(f"Invalid API key: {e}")
except APIConnectionError as e:
    print(f"Connection failed: {e}")
except APIError as e:
    print(f"API error (status {e.status_code}): {e.message}")

CLI

# Authentication
yutori auth login      # Log in via browser
yutori auth status     # Show current auth status
yutori auth logout     # Remove saved credentials

# Scouts
yutori scouts list
yutori scouts create -q "monitor for news"
yutori scouts create -q "monitor for news" -i daily -tz America/New_York
yutori scouts get SCOUT_ID
yutori scouts delete SCOUT_ID

# Browsing
yutori browse list
yutori browse list --limit 20 --status succeeded
yutori browse run "extract all prices" https://example.com/products
yutori browse run "log in and continue" https://example.com/login --require-auth
yutori browse run "export dashboard data" https://example.com/dashboard --browser local
yutori browse get TASK_ID

# Research
yutori research list
yutori research list --limit 10 --status running
yutori research run "latest developments in quantum computing" -tz America/Los_Angeles
yutori research get TASK_ID

# Usage
yutori usage

Run yutori --help or yutori <command> --help for full options.

Examples

See examples/ for complete working examples, including Navigator n1/n1.5 browser loops and gated Navigator n2 desktop cookbooks.

Contributing

See CONTRIBUTING.md for development setup.

Documentation

License

Apache 2.0 — see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

yutori-0.9.0.tar.gz (309.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

yutori-0.9.0-py3-none-any.whl (250.5 kB view details)

Uploaded Python 3

File details

Details for the file yutori-0.9.0.tar.gz.

File metadata

  • Download URL: yutori-0.9.0.tar.gz
  • Upload date:
  • Size: 309.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.14

File hashes

Hashes for yutori-0.9.0.tar.gz
Algorithm Hash digest
SHA256 37d76bcc28de1a2bf1ad0953ab5fa30239bd92c172a25b17470bad4b28c3d6bb
MD5 5c2c148b80f9f7961cef1b470491f1d8
BLAKE2b-256 9b778c49f2df87252479f67c68011c89d4fd2a2fd3754fe9c3912d036f4fc478

See more details on using hashes here.

File details

Details for the file yutori-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: yutori-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 250.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.12.14

File hashes

Hashes for yutori-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4f224ea294b49e0d638a2c3d4d2c5e997b2e3b6acb241ee86caba49325adf7cd
MD5 b8fdcd33df7418c9430ad19b1d46c741
BLAKE2b-256 e506c4b7bdd7dba14fd91d21af3baae6c8df4318c170b58aac680e4c8fa7d3cf

See more details on using hashes here.

Release history Release notifications | RSS feed

0.9.14

2 files

0.9.13

2 files

0.9.12

2 files

0.9.11

2 files

0.9.10

2 files

0.9.9

2 files

0.9.8

2 files

0.9.7

2 files

0.9.6

2 files

0.9.5

2 files

0.9.4

2 files

0.9.3

2 files

0.9.2

2 files

0.9.1

2 files

This release

0.9.0 This release

2 files

0.8.1

2 files

0.8.0

2 files

0.7.9

2 files

0.7.8

2 files

0.7.7

2 files

0.7.6

2 files

0.7.5

2 files

0.7.4

2 files

0.7.3

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

0.6.1

2 files

0.6.0

2 files

0.5.0

2 files

0.4.10

2 files

0.4.9

2 files

0.4.8

2 files

0.4.7

2 files

0.4.5

2 files

0.4.4

2 files

0.4.3

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.5

2 files

0.3.4

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page