Browser-Nutzung mit dem SDK-Toolset
Führe das Browser-Use-Tool aus dem Python- oder TypeScript-SDK aus. Das SDK führt die Schleife sowie die von dir konfigurierten URL-, Datei- und Genehmigungsprüfungen aus, und du stellst den Browser bereit.
Die Python- und TypeScript-SDKs enthalten eine Klasse für das Browser-Use-Tool. Du leitest eine Unterklasse davon ab und schreibst pro „member tool" (Member-Tool), etwa navigate oder left_click, eine Methode gegen deine eigene Browser-Automatisierung. Das SDK leitet jeden Aufruf weiter, prüft URLs und Dateipfade, fragt deinen Genehmigungs-Callback ab und erstellt jedes tool_result.
Das SDK enthält keinen Browser, keinen fertigen „driver" (Treiber) und keine „denylist" (Sperrliste). Beispiel-Treiber für Playwright und das Chrome DevTools Protocol in Python und TypeScript findest du im Ordner browser-toolset des claude-quickstarts-Repositorys.
Schnellstart
Ein Treiber ist deine Unterklasse von BetaAbstractBrowserToolset20260801. Dieser hier implementiert navigate, screenshot und left_click sowie _browser_state (browserState in TypeScript), den Zustandsbericht, den jeder Treiber benötigt. Im Beispiel steht backend für deinen eigenen Wrapper um eine Browser-Automatisierungsbibliothek wie Playwright.
from anthropic import Anthropic
from anthropic.tools.browser import (
BetaAbstractBrowserToolset20260801,
BetaBrowserNavigateResult,
BetaBrowserScreenshotResult,
BrowserState,
ToolsetCallContext,
)
from anthropic.types.beta import (
BetaBrowserLeftClickInput,
BetaBrowserNavigateInput,
BetaBrowserScreenshotInput,
BetaBrowserStateTabEntryParam,
)
class MyBrowser(BetaAbstractBrowserToolset20260801):
def __init__(self, backend, **options):
super().__init__(**options)
self.backend = backend
def _browser_state(self, context: ToolsetCallContext) -> BrowserState:
return BrowserState(
tabs=[
BetaBrowserStateTabEntryParam(
tab_id=tab.id,
title=tab.title,
url=tab.url,
active=tab.id == self.backend.active,
)
for tab in self.backend.tabs()
],
state_changes=self.backend.drain_changes(),
)
def navigate(
self, context: ToolsetCallContext, input: BetaBrowserNavigateInput
) -> BetaBrowserNavigateResult:
# input.url ist eine URL, die die URL-Richtlinie bestanden hat, oder "back", "forward",
# oder "reload". Das SDK ergänzt https://, wenn Claude das Schema weglässt.
page = self.backend.goto(input.url, input.tab_id)
return BetaBrowserNavigateResult(
url=page.url, status=page.status, title=page.title
)
def screenshot(
self, context: ToolsetCallContext, input: BetaBrowserScreenshotInput
) -> BetaBrowserScreenshotResult:
data = self.backend.png_base64(input.tab_id)
return BetaBrowserScreenshotResult(data=data, media_type="image/png")
def left_click(
self, context: ToolsetCallContext, input: BetaBrowserLeftClickInput
) -> None:
# Kein Rückgabewert nötig: Claude liest "Clicked."
self.backend.click(input.target, input.tab_id)
def close(self) -> None:
super().close() # first, so no call is still using the browser when it closes
if not self.backend.closed:
self.backend.close()
client = Anthropic()
with MyBrowser(backend, allowed_domains=["example.com", "iana.org"]) as browser:
runner = client.beta.messages.tool_runner(
model="claude-opus-5-5",
max_tokens=1024,
tools=[browser],
messages=[
{
"role": "user",
"content": "Open example.com and tell me the page heading.",
}
],
)
for message in runner:
print(message)Übergib die Treiber-Instanz selbst als tools-Eintrag. Ein Member, das du nicht implementierst, wird als deaktiviert an die API gesendet. Wenn Claude es trotzdem aufruft, gibt das SDK einen Fehler zurück, und der Lauf wird fortgesetzt. Das Überschreiben von execute ändert, welche Member als deaktiviert gesendet werden (Vorher- und Nachher-Hooks hinzufügen). Der Runner schließt das Toolset nie, sodass eine Instanz mehrere Läufe bedienen kann. Schließe es, wenn du fertig bist.
Einen Treiber anpassen
Member aktivieren oder deaktivieren
configs nimmt die Einstellungen pro Member entgegen, die unter Das Toolset konfigurieren beschrieben sind. Liste nur die Member auf, die du änderst:
# Ein MyBrowser, der zusätzlich read_console implementiert
browser = MyBrowser(
backend, configs={"read_console": {"enabled": True}, "navigate": {"enabled": False}}
)Das SDK lehnt einen Aufruf eines deaktivierten Members ab, bevor dein Code ausgeführt wird. Ein Member zu aktivieren, das deine Klasse nicht implementiert, ist ein Konfigurationsfehler, es sei denn, die Klasse überschreibt execute.
Vorher- und Nachher-Hooks hinzufügen
Überschreibe execute und rufe das execute der Elternklasse auf. Code vor diesem Aufruf läuft nach der URL-Prüfung (URL-Richtlinie festlegen) und confirm (Folgenreiche Member absichern), und er kann die Eingabe ändern. Das SDK prüft die geänderte Eingabe nicht erneut. Code nach dem Aufruf erhält das Ergebnis und kann es ändern. Löse ToolError aus (in TypeScript mit throw), um den Aufruf abzulehnen.
Das Überschreiben von execute ändert, welche Member Claude angeboten werden. Das SDK zählt jedes Member als implementiert, sodass Claude jedes standardmäßig aktivierte Member angeboten wird. Das MyBrowser aus dem Schnellstart bedient drei Member, daher bietet das folgende TracedBrowser Claude Member an, die es nicht bedienen kann. Deaktiviere diese Member mit configs, bevor du es verwendest.
import time
class TracedBrowser(MyBrowser):
def execute(self, context, name, input):
started = time.monotonic()
result = super().execute(context, name, input)
elapsed_ms = (time.monotonic() - started) * 1000
call_id = context.tool_use.id if context.tool_use else "-"
log.info("%s %s %.0fms", call_id, name, elapsed_ms)
return redact(result) if name == "get_page_text" else resultEinen Treiber implementieren
Überschreibe die Member, die dein Browser unterstützt. Jedes Member erhält den Aufrufkontext und die Eingabe des Members als typisiertes Objekt, etwa BetaBrowserNavigateInput. Die Eingabetypen stammen aus anthropic.types.beta (@anthropic-ai/sdk/resources/beta in TypeScript). Member-Tools listet die Felder jeder Eingabe auf.
Schreibe Member in TypeScript als Methoden, nicht als Arrow-Function-Felder, da das SDK sie auf dem Prototyp findet. Schreibe das Member type in TypeScript als type_. In Python heißt es type.
Ergebnisse zurückgeben
Was ein Member zurückgibt, bestimmt, was Claude liest. Ein erfolgreiches Ergebnis endet mit einem browser_state-Block, der aus deinem Zustandsbericht erstellt wird. Ein Fehlerergebnis enthält keinen Block.
| Member | Gibt zurück | Claude liest |
|---|---|---|
screenshot, zoom | BetaBrowserScreenshotResult | Einen Bildblock |
navigate | BetaBrowserNavigateResult | Navigated to {url} — {title} (HTTP {status}) |
new_tab, switch_tab, list_tabs, close_tab | Einen Tab-Eintrag (new_tab, switch_tab), eine Liste von Tab-Einträgen (list_tabs) oder nichts (close_tab) | Nur den browser_state-Block |
read_page, get_page_text, find, read_console, read_network, javascript_exec | Einen String | Den String |
| Jedes andere Member | Nichts oder eine Textzeile | Eine kurze Bestätigung wie Clicked., dann die zurückgegebene Zeile in einem eigenen Textblock |
Browserzustand melden
Das SDK ruft _browser_state (die Option browserState in TypeScript) nach jedem Aufruf auf, einschließlich abgelehnter und fehlgeschlagener Aufrufe. Gib jeden geöffneten Tab zurück und was sich seit dem letzten Bericht geändert hat:
- Geöffnete Tabs und Download-Ereignisse.
- Ein
NavigationRefusedfür jede Navigation, die dein „request hook" (Anfrage-Hook) blockiert hat. - Ein
DialogDismissedfür jeden nativen Dialog, den dein Treiber geschlossen hat.
Lege all diese in state_changes ab. In Python stammen NavigationRefused(url=...) und DialogDismissed(kind=..., message=...) aus anthropic.tools.browser. In TypeScript sind es { type: "navigation_refused", url } und { type: "dialog_dismissed", kind, message }.
Die letzten beiden sind keine API-Zustandsänderungen. Das SDK meldet sie Claude als Text außerhalb des browser_state-Blocks: eine Zeile für alle abgelehnten Navigationen, die keine URL nennt, und eine Zeile für jeden der ersten drei geschlossenen Dialoge, gefolgt von der Anzahl aller weiteren.
Wenn mindestens ein Tab geöffnet ist, muss genau einer aktiv sein. Jedes Member, das eine tab_id entgegennimmt, muss auf den Tab wirken, den sie benennt. Das SDK verwendet den Bericht, um zu bestimmen, von welcher Seite ein Ergebnis stammt. Die Grenzen der API für den Bericht sind unter Tabs mit browser_state verfolgen aufgeführt.
Fehler behandeln
| Ausgelöst von einem Member oder dem SDK | Claude liest | Der Lauf |
|---|---|---|
ToolError | Seine Nachricht, als Fehlerergebnis | Wird fortgesetzt |
| Jede andere Exception | Ihren Text, als Fehlerergebnis | Wird fortgesetzt |
ToolsetUsageError, bei einem Konfigurationsfehler, einer Fehlverwendung des SDK während eines Aufrufs oder einem Aufruf nach close | Nichts | Wird beendet |
Bevor Claude den Fehlertext eines Members, die Zeile, die eine Aktion wie left_click zurückgibt, den Fehler eines fehlgeschlagenen Downloads oder die Nachricht eines geschlossenen Dialogs liest, ersetzt das SDK jede URL, die die Richtlinie ablehnt, durch (blocked). Es ersetzt jeden lokalen Pfad, den die Datei-Richtlinie nicht offenlegt, durch (path hidden). Die Prüfung kann einige URLs und Pfade übersehen. Ein ToolError aus deiner URL-Richtlinie, deiner Datei-Richtlinie oder deinem confirm-Callable erreicht Claude so, wie er geschrieben wurde, also lass abgelehnte URLs und lokale Pfade aus seinem Text heraus. Fange Exceptions in deinen Membern ab und löse ToolError (in TypeScript mit throw) mit deinem eigenen Text aus.
Ohne den Tool-Runner ausführen
Übergib die Instanz in tools (browser.toJSON() in TypeScript) und beantworte jeden Member-Aufruf mit tool_result (toolResult in TypeScript). Das Browser-Use-Tool verlangt, dass du beim ersten fehlgeschlagenen Aufruf anhältst (Batch-Aktionen). Nach einem fehlgeschlagenen Aufruf beantwortet diese Schleife die späteren Aufrufe desselben Turns, ohne sie auszuführen:
from anthropic.types.beta import BetaToolResultBlockParam
NOT_EXECUTED = "Not executed: an earlier action in this turn failed."
MAX_TURNS = 10
with MyBrowser(backend, allowed_domains=["example.com"]) as browser:
messages = [{"role": "user", "content": "Open example.com"}]
for _ in range(MAX_TURNS):
response = client.beta.messages.create(
model="claude-opus-5-5",
max_tokens=1024,
tools=[browser],
messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
calls = [
block
for block in response.content
if block.type == "tool_use" and block.toolset_name == browser.toolset_name
]
if not calls:
break
results: list[BetaToolResultBlockParam] = []
failed = False
for call in calls:
if failed:
# Nach einem fehlgeschlagenen Aufruf wird der Rest des Turns beantwortet, nicht ausgeführt.
results.append(
{
"type": "tool_result",
"tool_use_id": call.id,
"toolset_name": call.toolset_name,
"content": NOT_EXECUTED,
"is_error": True,
}
)
continue
result = browser.tool_result(call)
failed = bool(result.get("is_error"))
results.append(result)
messages.append({"role": "user", "content": results})Jede Antwort auf einen übersprungenen Aufruf enthält is_error, den toolset_name des Aufrufs und genau den Text, den der Abschnitt Batch-Aktionen verlangt. Der Tool-Runner sendet dieselbe Antwort.
Das Toolset sicher ausführen
Claudes nächste Aktion hängt von den Seiten ab, die es liest. Eine Seite oder in sie eingeschleuster Text kann versuchen, interne Dienste zu erreichen oder Dateien vom Host abzuziehen. Sie kann auch versuchen, Aktionen mit realen Auswirkungen auszulösen. Bevor du einen Treiber gegen etwas anderes als einen Wegwerf-Browser ausführst, unternimm diese sechs Schritte:
- Lege eine URL-Richtlinie fest:
allowed_domains,blocked_domainsoder deine eigeneurl_policy. - Fange Anfragen im Treiber ab und frage das Toolset nach einem Urteil.
- Lege eine „egress policy" (Richtlinie für ausgehenden Datenverkehr) auf den Container, damit das Netzwerk blockiert, was der Treiber nicht sehen kann.
- Beschränke Uploads und Downloads oder lass Uploads deaktiviert.
- Sichere folgenreiche Member mit
confirmab. - Isoliere den Browser-Host für jede Sitzung in einem dedizierten Container oder einer VM.
Das SDK setzt die Schritte 1, 4 und 5 so durch, wie du sie konfigurierst. Die Schritte 2, 3 und 6 liegen bei deinem Treiber und deinem Deployment. Die Vorsichtsmaßnahmen unter Sicherheitsüberlegungen gelten ebenfalls.
URL-Richtlinie festlegen
Setze allowed_domains (allowedDomains in TypeScript) auf die Websites, die die Aufgabe benötigt. Ein Eintrag in einer der beiden Listen ist eine Domain (die auch ihre Subdomains abdeckt), eine IP-Adresse oder ein CIDR-Netzwerk. Wenn allowed_domains gesetzt ist, lehnt das Toolset jeden anderen Host ab.
browser = MyBrowser(backend, allowed_domains=["example.com", "iana.org"])Wenn die Aufgabe das offene Web benötigt, setze stattdessen blocked_domains (blockedDomains). Die Listen vergleichen Hostnamen, ohne sie aufzulösen. Ein Sperrlisteneintrag 127.0.0.0/8 blockiert localhost nicht, also benenne sowohl Hosts als auch Netzwerke. Wenn du beide Listen setzt, hat blocked_domains Vorrang.
Eine Sperrliste kann keinen öffentlichen Namen erfassen, der zu einer privaten Adresse aufgelöst wird. Bei blocked_domains ist es daher die Egress-Richtlinie des Containers, die verhindert, dass ein solcher Name eine private Adresse erreicht.
# Liste die Hosts und Netzwerke auf, die der Browser erreicht, Claude aber nicht darf:
# Loopback-, Link-Local- und private Bereiche in IPv4 und IPv6, 0.0.0.0/8, die
# Metadaten-Adressen und -Namen deiner Cloud (etwa metadata.google.internal),
# localhost sowie deine internen Hostnamen.
browser = MyBrowser(backend, blocked_domains=internal_networks)Eine url_policy (urlPolicy) ersetzt beide Listen, und sie zusammen mit einer der Listen zu übergeben, ist ein Konfigurationsfehler. Deine Richtlinie gibt nichts zurück, um eine URL zu erlauben, und löst ToolError aus (throw), um sie abzulehnen. Um die Standardregeln beizubehalten, erstelle die Standardrichtlinie mit default_url_policy (defaultURLPolicy) und rufe sie zuerst aus deiner eigenen auf:
from urllib.parse import urlsplit
from anthropic.tools.browser import ToolError, URLContext, default_url_policy
listed = default_url_policy(allowed_domains=["example.com"])
def url_policy(context: URLContext, url: str) -> None:
listed(context, url) # the default rules first
if context.phase == "request" and urlsplit(url).scheme != "https":
raise ToolError("Only https navigation is allowed.")
browser = MyBrowser(backend, url_policy=url_policy)Die Richtlinie läuft bei jeder navigate-URL vor deinem Code, bei der URL, die ein Ergebnis meldet, und bei jeder Tab- und Download-URL in einem Zustandsbericht. In Ergebnissen und Zustandsberichten überspringt sie Adressen, die keinen entfernten Host benennen: einen leeren Tab, about:blank, die chrome-error:-Seite des Browsers und data:-Dokumente.
Unter jeder Richtlinie lehnt das Toolset ein navigate zu einem anderen Schema als http oder https ab, mit Ausnahme von about:blank. url_policy="allow_all" (urlPolicy: "allow_all") schaltet die Richtlinie ab, aber nicht diese Schemaregel.
Die Übergabe von url_policy=None (urlPolicy: null) lässt den Konstruktor einen Konfigurationsfehler auslösen, sodass ein aus deiner Konfiguration gelesenes None (null) die Prüfungen nicht abschalten kann. In TypeScript lässt undefined die Option ungesetzt, genauso, als würdest du sie nicht übergeben.
Wenn eine Seite auf einer abgelehnten Adresse landet, liest Claude, dass ihr Inhalt zurückgehalten wurde, und der Tab wird als (blocked) aufgeführt. Bis der Tab wieder auf einer erlaubten Adresse ist, lehnt das Toolset Aufrufe auf ihm ab. Die Ausnahmen sind navigate (aber nicht "reload"), new_tab, list_tabs, switch_tab und close_tab.
Anfragen im Treiber abfangen
Die URL-Richtlinie beurteilt nur die Adressen, die das Toolset sieht: Navigationen, Ergebnisse und Zustandsberichte. Sie sieht keine Sub-Ressourcen, fetch()-Aufrufe, WebSockets oder wohin ein Hostname aufgelöst wird.
Das Toolset erkennt eine neue Adresse erst, wenn ein Aufruf endet, im Ergebnis oder Zustandsbericht des Aufrufs. Ein Aufruf kann also vorher noch auf einer abgelehnten Seite agieren, und das SDK kann höchstens das Ergebnis dieses Aufrufs zurückhalten. Sofern dein Treiber nicht jede Anfrage beurteilt, einschließlich Weiterleitungsschritten, lädt eine Seite, die auf eine abgelehnte Adresse weiterleitet, trotzdem.
Rufe im Request-Hook deines Treibers (der Funktion, die deine Automatisierungsbibliothek vor jeder Anfrage aufruft) check_url (checkURL) auf. Es wendet die eigene Richtlinie des Toolsets an, sodass du die Regeln nicht zweimal schreibst:
from anthropic.tools.browser import URLContext
class MyBrowser(BetaAbstractBrowserToolset20260801):
...
# Registriert auf einem Playwright-Browserkontext mit context.route("**/*", self._guard)
def _guard(self, route):
url_context = URLContext(
member="navigate", phase="request", tab_id=self.backend.active
)
if not self.check_url(url_context, route.request.url).allowed:
return route.abort("blockedbyclient")
route.continue_()check_url wendet dieselbe Schemaregel und Richtlinie an wie navigate. Ein Request-Hook wie dieser sieht keine WebSocket-Handshakes, Service-Worker-Anfragen oder Weiterleitungsschritte. Blockiere Service Worker. Beurteile WebSocket-Handshakes und Weiterleitungsschritte mit einem Hook, der sie sieht.
In der Anfragephase erlaubt check_url nur http-, https- und about:blank-URLs. Ändere bei einem WebSocket daher ws:// in http:// und wss:// in https://, bevor du es aufrufst.
Egress-Richtlinie auf den Container legen
Das Abfangen kann nicht jede Anfrage sehen, die der Browser stellt, und die URL-Richtlinie sieht nicht, wohin ein Name aufgelöst wird. Eine Egress-Richtlinie, die das Netzwerk des Containers durchsetzt, deckt beides ab:
- Blockiere Loopback-, Link-Local- und private Adressbereiche in IPv4 und IPv6 sowie
0.0.0.0/8. Dazu gehört die Cloud-Metadatenadresse169.254.169.254. - Erlaube ausgehende Verbindungen nur zu den Hosts, die die Aufgabe benötigt. Wenn deine Regeln IP-Adressen abgleichen, löse die erlaubten Hostnamen beim Start des Containers auf.
- Erlaube DNS nur zum Resolver des Containers.
- Wenn dein Treiber den Browser über einen lokalen DevTools-Port erreicht, erlaube Loopback nur auf diesem Port. Eine Regel für das gesamte Loopback würde der Seite jeden lokalen Dienst öffnen.
Uploads und Downloads beschränken
file_upload ist standardmäßig deaktiviert. Ohne file_policy lehnt das SDK jeden Upload ab, der einen Pfad oder eine Dokument-ID nennt. Um Uploads zu aktivieren, übergib eine LocalFilePolicy (NodeFilePolicy in TypeScript) mit einem Upload-Verzeichnis, das nur die Dateien der Aufgabe enthält:
from anthropic.tools.browser import LocalFilePolicy
# Ein MyBrowser, der zusätzlich file_upload implementiert
browser = MyBrowser(
backend,
configs={"file_upload": {"enabled": True}},
confirm=make_confirm(), # required for file_upload; see Gate consequential members
file_policy=LocalFilePolicy(
upload_roots=["/task/uploads"],
download_dir="/task/downloads",
expose_download_paths=False,
),
)Das SDK löst jeden Upload-Pfad auf, folgt dabei Symlinks und lehnt jeden Pfad außerhalb der Upload-Wurzeln ab. Die Datei-Richtlinie lehnt ein Download-Verzeichnis innerhalb einer Upload-Wurzel ab. Der Pfad eines Downloads erreicht Claude nur, wenn expose_download_paths (exposeDownloadPaths) true ist und die Datei sich im Download-Verzeichnis befindet.
Die mitgelieferten Pfadprüfungen lösen Pfade im Dateisystem des Prozesses auf, der das SDK ausführt. Sie schützen nur einen Browser, der dieses Dateisystem teilt. Folge bei einem entfernten Browser stattdessen Entfernte und gehostete Browser.
Richte Downloads so ein:
- Erstelle das Download-Verzeichnis selbst mit dem Modus
0700und mounte es mitnoexec,nosuid,nodev. - Halte das Verzeichnis außer Reichweite anderer Tools, die Claude aufrufen kann, etwa einer Shell oder eines Datei-Tools.
- Schreibe in einer
download_failed-Zustandsänderungerrorals feste Formulierung. Der Text einer Exception kann den Pfad oder die URL enthalten. - Lies eine heruntergeladene Datei nicht in die Konversation ein und führe sie nicht aus, bis eine Person dies entscheidet.
Folgenreiche Member absichern
javascript_exec und file_upload sind standardmäßig deaktiviert. Wenn du eines davon ohne ein confirm-Callable aktivierst, löst der Konstruktor einen Konfigurationsfehler aus. Mit einem confirm-Callable ruft das SDK es vor jedem Aufruf auf, der gleich ausgeführt wird. Ohne eines wird nichts gefragt.
Gib True zurück, um den Aufruf auszuführen, oder False, um ihn abzulehnen (true und false in TypeScript). Wenn dein Callable eine Person fragt, zeige ihr das Member, die URL der Seite und die Eingabe des Aufrufs. Maskiere zuerst jedes Zeichen in der Eingabe, das außerhalb von druckbarem ASCII liegt, da die Eingabe Text von der Seite enthalten kann.
Dieses Beispiel fragt über deine eigene Funktion ask_user (askUser in TypeScript) nach den beiden abgesicherten Membern und genehmigt den Rest:
import json
from collections.abc import Callable
from anthropic.tools.browser import ConfirmContext
GATED = {"javascript_exec", "file_upload"}
def shown(context: ConfirmContext) -> str:
"""The call's input as JSON, with every character outside printable
ASCII escaped."""
return json.dumps(context.input.to_dict(), ensure_ascii=True, indent=2)
def make_confirm() -> Callable[[ConfirmContext], bool]:
granted: set[tuple[str, str, str]] = set()
def confirm(context: ConfirmContext) -> bool:
name = context.member
if name not in GATED:
return True
detail = shown(context)
page = context.tab_url
origin = context.origin
if page is None or origin is None or origin.startswith("chrome-error:"):
# Kein Origin oder eine Fehlerseite: jedes Mal nachfragen.
return ask_user(
f"Allow {name} on {page or 'a page with no origin'}?\n{detail}"
)
# Eine Freigabe gilt nur für genau diese Eingabe auf dieser Seite.
key = (name, page, detail)
if key not in granted and ask_user(f"Allow {name} on {page}?\n{detail}"):
granted.add(key)
return key in granted
return confirm
# Ein MyBrowser, der zusätzlich javascript_exec und file_upload implementiert
browser = MyBrowser(
backend,
configs={"javascript_exec": {"enabled": True}, "file_upload": {"enabled": True}},
confirm=make_confirm(),
)Jeder Aufruf von make_confirm() (makeConfirm() in TypeScript) gibt ein Callable ohne Genehmigungen zurück. Rufe es einmal pro Toolset auf und gib jedem Benutzer sein eigenes Toolset.
Eine Genehmigung gilt für die Seite, wie der letzte Zustandsbericht sie gezeigt hat, und die Seite kann sich ändern, bevor der Aufruf ausgeführt wird. Käufe, gesendete Nachrichten und akzeptierte Bedingungen erfolgen über gewöhnliche Member wie left_click und type, daher kann confirm sie nicht anhand des Namens herausfiltern. Damit eine Person sie genehmigt, frage auch nach diesen Membern.
Aktiviere javascript_exec nicht bei einem Treiber, der keine Anfragen abfängt. Ein Skript, das auf einer abgelehnten Seite läuft, kann deren Inhalt an einen Ort kopieren, von dem ein späterer Lesevorgang ihn zurückgibt.
Browser-Host isolieren
Führe den Browser für jede Sitzung in einem dedizierten Container oder einer VM mit minimalen Rechten aus:
- Führe ihn als Nicht-Root-Benutzer aus, mit einem schreibgeschützten Root-Dateisystem, wo der Browser es zulässt.
- Mounte nichts vom Host außer den Upload- und Download-Verzeichnissen, die du konfiguriert hast, falls vorhanden.
- Halte Anmeldedaten aus der Umgebung heraus und starte mit einem frischen Browserprofil.
- Teile kein Dateisystem mit anderen Tools, die Claude aufrufen kann.
Führe den Code, der die API aufruft, außerhalb des Containers des Browsers aus, da dieser Code deinen API-Key und die Konversation enthält. Der Tool-Runner und tool_result führen das Toolset beide im Prozess dieses Codes aus, sodass der Browser das Dateisystem des Toolsets nicht teilt. Behandle den Browser als entfernt: Es gilt der Abschnitt Entfernte und gehostete Browser.
Behandle alles, was eine Seite zurückgibt, als nicht vertrauenswürdig, einschließlich Seitentext, Screenshots, Konsolen- und Netzwerkeinträgen, Tab-Titeln und Download-Namen.
Entfernte und gehostete Browser
Manche Browser teilen kein Dateisystem mit dem Prozess, der das SDK ausführt. Beispiele sind ein Browser in einem anderen Container, einer, den du über eine DevTools-URL erreichst, und einer von einem gehosteten Browser-Dienst. Bei diesen laufen die URL-Richtlinie, das Abfangen von Anfragen und confirm weiterhin in deinem Prozess.
Bei einem gehosteten Browser kontrolliert der Anbieter Egress und Host-Isolation. Deine eigene Egress-Richtlinie gilt dort nicht, daher ist der Request-Hook des Treibers deine einzige Prüfung der Anfragen des Browsers. Finde heraus, was das Netzwerk des Browsers erreichen kann.
Die mitgelieferten Pfadprüfungen schützen keinen entfernten Browser. LocalFilePolicy (NodeFilePolicy in TypeScript) prüft Pfade im Dateisystem des Prozesses, der das SDK ausführt, und der Browser liest und schreibt sein eigenes Dateisystem.
Das SDK kann nicht erkennen, dass ein Browser entfernt ist. Lass bei einem entfernten Browser daher file_upload deaktiviert, es sei denn, dein Treiber prüft Upload-Pfade dort, wo der Browser läuft, mit einer eigenen FilePolicy. Eine FilePolicy prüft die Pfade und Dokument-IDs jedes Uploads und entscheidet, ob Claude den Pfad eines Downloads sieht.
Lass einen entfernten Browser Downloads ablehnen, es sei denn, sein eigener Host verfügt über die Download-Einrichtung aus Uploads und Downloads beschränken.
Die Beispiel-Treiber folgen dieser Regel. Bei einem entfernten Browser lösen sie einen Konfigurationsfehler für eine file_policy (filePolicy) oder ein aktiviertes file_upload aus und stellen den Browser so ein, dass er Downloads ablehnt.
Halte den API-Key des Anbieters und die Verbindungs-URL der Sitzung, die einen Key enthalten kann, aus Logs, Tool-Ergebnissen und Fehlertexten heraus. Wenn der Anbieter Sitzungen aufzeichnet, ist die Aufzeichnung eine weitere Kopie von allem, was Claude gesehen und eingegeben hat, und die Aufbewahrungsbedingungen des Anbieters gelten dafür.
Referenz
Die Konstruktoroptionen haben in beiden SDKs dieselbe Bedeutung:
| Python | TypeScript | Legt fest |
|---|---|---|
configs | configs | Welche Member aktiviert sind |
confirm | confirm | Das Callable, das jeden Aufruf genehmigt oder ablehnt |
allowed_domains, blocked_domains | allowedDomains, blockedDomains | Die Listen der Standard-URL-Richtlinie |
url_policy | urlPolicy | Deine eigene URL-Richtlinie |
file_policy | filePolicy | Upload-Wurzeln und Offenlegung von Download-Pfaden |
tool_configs | toolConfigs | Felder für den tools-Eintrag, etwa cache_control |
Die Methode _browser_state | browserState | Der Zustandsbericht |
Du kannst eine Option nach der Konstruktion nicht ändern. Standardwerte, Fehler, Kontextfelder und die asynchrone Python-Klasse (BetaAsyncAbstractBrowserToolset20260801) sind im Python SDK und im TypeScript SDK dokumentiert.
Einschränkungen
- Die URL-Richtlinie prüft Navigationen, nicht jede Anfrage: Siehe Anfragen im Treiber abfangen.
- Eine Genehmigung basiert auf dem letzten Zustandsbericht: Die Seite kann sich nach diesem Bericht ändern. Das SDK prüft die Seite nicht erneut, bevor der Aufruf ausgeführt wird.
- Aufrufe auf einem Toolset laufen nacheinander: Du kannst das nicht abschalten.
- Das SDK prüft nicht, ob Tab-IDs eindeutig sind, ob ein Tab aktiv ist oder wie viele Tabs es gibt: Die API lehnt einen Bericht ab, der gegen diese Regeln verstößt.
Nächste Schritte
Die Member-Tools, der browser_state-Block und die Sicherheitsüberlegungen des Tools.
Wie das SDK die Schleife ausführt und wie du die Nachrichten änderst, die es sendet.
Schutzmaßnahmen für jede Anwendung, die nicht vertrauenswürdige Inhalte liest.
Was this page helpful?