Claude Platform Docs
MessagesAlat

Penggunaan browser dengan toolset SDK

Jalankan alat penggunaan browser dari SDK Python atau TypeScript. SDK menjalankan loop serta pemeriksaan URL, file, dan persetujuan yang Anda konfigurasikan, dan Anda yang menyediakan browsernya.

SDK Python dan TypeScript menyertakan sebuah kelas untuk alat penggunaan browser. Anda membuat subkelasnya dan menulis satu metode per "member tool" (alat anggota), seperti navigate atau left_click, di atas otomatisasi browser Anda sendiri. SDK merutekan setiap panggilan, memeriksa URL dan path file, menanyakan callback persetujuan Anda, dan membangun setiap tool_result.

SDK tidak menyertakan browser, driver siap pakai, atau "denylist" (daftar blokir). Contoh driver untuk Playwright dan Chrome DevTools Protocol, dalam Python dan TypeScript, tersedia di folder browser-toolset pada repositori claude-quickstarts.

Mulai cepat

Driver adalah subkelas Anda dari BetaAbstractBrowserToolset20260801. Driver ini mengimplementasikan navigate, screenshot, dan left_click, ditambah _browser_state (browserState di TypeScript), yaitu laporan state yang dibutuhkan setiap driver. Dalam contoh ini, backend mewakili wrapper Anda sendiri di sekitar library otomatisasi browser, seperti 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 adalah URL yang telah lolos kebijakan URL, atau "back", "forward",
        # atau "reload". SDK menambahkan https:// jika Claude tidak menyertakan skema.
        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:
        # Tidak ada yang dikembalikan: Claude membaca "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)

Teruskan instance driver itu sendiri sebagai entri tools. Anggota yang tidak Anda implementasikan dikirim ke API dalam keadaan dinonaktifkan. Jika Claude tetap memanggilnya, SDK mengembalikan error, dan run tetap berlanjut. Meng-override execute mengubah anggota mana yang dikirim dalam keadaan dinonaktifkan (Menambahkan hook sebelum dan sesudah). Runner tidak pernah menutup toolset, sehingga satu instance dapat melayani beberapa run. Tutup toolset setelah Anda selesai.

Menyesuaikan driver

Mengaktifkan atau menonaktifkan anggota

configs menerima pengaturan per anggota yang dijelaskan di Mengonfigurasi toolset. Cantumkan hanya anggota yang Anda ubah:

# MyBrowser yang juga mengimplementasikan read_console
browser = MyBrowser(
    backend, configs={"read_console": {"enabled": True}, "navigate": {"enabled": False}}
)

SDK menolak panggilan ke anggota yang dinonaktifkan sebelum kode Anda berjalan. Mengaktifkan anggota yang tidak diimplementasikan oleh kelas Anda merupakan error konfigurasi, kecuali kelas tersebut meng-override execute.

Menambahkan hook sebelum dan sesudah

Override execute dan panggil execute milik kelas induk. Kode sebelum panggilan tersebut berjalan setelah pemeriksaan URL (Menetapkan kebijakan URL) dan confirm (Membatasi anggota yang berdampak), dan kode tersebut dapat mengubah input. SDK tidak memeriksa ulang input yang telah diubah. Kode setelah panggilan menerima hasilnya, dan dapat mengubah hasil tersebut. Raise ToolError (throw di TypeScript) untuk menolak panggilan.

Meng-override execute mengubah anggota mana yang ditawarkan kepada Claude. SDK menganggap setiap anggota sudah diimplementasikan, sehingga Claude ditawari setiap anggota yang aktif secara default. MyBrowser dari mulai cepat melayani tiga anggota, sehingga TracedBrowser berikut menawarkan kepada Claude anggota-anggota yang tidak dapat dilayaninya. Nonaktifkan anggota tersebut dengan configs sebelum Anda menggunakannya.

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 result

Mengimplementasikan driver

Override anggota yang didukung browser Anda. Setiap anggota menerima konteks panggilan dan input anggota sebagai objek bertipe, seperti BetaBrowserNavigateInput. Tipe input berasal dari anthropic.types.beta (@anthropic-ai/sdk/resources/beta di TypeScript). Alat anggota mencantumkan field dari setiap input.

Di TypeScript, tulis anggota sebagai metode, bukan field arrow-function, karena SDK menemukannya pada prototype. Tulis anggota type sebagai type_ di TypeScript. Di Python, namanya type.

Mengembalikan hasil

Apa yang dikembalikan anggota menentukan apa yang dibaca Claude. Hasil yang berhasil diakhiri dengan blok browser_state yang dibangun dari laporan state Anda. Hasil error tidak membawa blok tersebut.

AnggotaMengembalikanYang dibaca Claude
screenshot, zoomBetaBrowserScreenshotResultSatu blok gambar
navigateBetaBrowserNavigateResultNavigated to {url} — {title} (HTTP {status})
new_tab, switch_tab, list_tabs, close_tabSebuah entri tab (new_tab, switch_tab), daftar entri tab (list_tabs), atau tidak ada (close_tab)Blok browser_state saja
read_page, get_page_text, find, read_console, read_network, javascript_execSebuah stringString tersebut
Setiap anggota lainnyaTidak ada, atau satu baris teksKonfirmasi singkat, seperti Clicked., lalu baris yang dikembalikan dalam blok teks tersendiri

Melaporkan state browser

SDK memanggil _browser_state (opsi browserState di TypeScript) setelah setiap panggilan, termasuk panggilan yang ditolak dan yang gagal. Kembalikan setiap tab yang terbuka, dan apa yang berubah sejak laporan terakhir:

  • Tab yang dibuka dan event unduhan.
  • Sebuah NavigationRefused untuk setiap navigasi yang diblokir oleh hook permintaan Anda.
  • Sebuah DialogDismissed untuk setiap dialog native yang ditutup oleh driver Anda.

Masukkan semua ini ke dalam state_changes. Di Python, NavigationRefused(url=...) dan DialogDismissed(kind=..., message=...) berasal dari anthropic.tools.browser. Di TypeScript, keduanya adalah { type: "navigation_refused", url } dan { type: "dialog_dismissed", kind, message }.

Dua yang terakhir bukan perubahan state API. SDK melaporkannya kepada Claude sebagai teks di luar blok browser_state: satu baris untuk semua navigasi yang ditolak, yang tidak menyebutkan URL, dan satu baris untuk masing-masing dari tiga dialog pertama yang ditutup, lalu jumlah dialog lainnya.

Ketika ada tab yang terbuka, tepat satu tab harus aktif. Setiap anggota yang menerima tab_id harus bertindak pada tab yang disebutkannya. SDK menggunakan laporan tersebut untuk menentukan dari halaman mana suatu hasil berasal. Batasan API pada laporan tercantum di Melacak tab dengan browser_state.

Menangani error

Di-raise oleh anggota atau SDKYang dibaca ClaudeRun
ToolErrorPesannya, sebagai hasil errorBerlanjut
Exception lainnyaTeksnya, sebagai hasil errorBerlanjut
ToolsetUsageError, untuk kesalahan konfigurasi, penyalahgunaan SDK selama panggilan, atau panggilan setelah closeTidak adaBerhenti

Sebelum Claude membaca teks error anggota, baris yang dikembalikan oleh tindakan seperti left_click, error dari unduhan yang gagal, atau pesan dari dialog yang ditutup, SDK mengganti setiap URL yang ditolak oleh kebijakan dengan (blocked). SDK mengganti setiap path lokal yang tidak diekspos oleh kebijakan file dengan (path hidden). Pemeriksaan ini dapat melewatkan beberapa URL dan path. ToolError dari kebijakan URL, kebijakan file, atau callable confirm Anda sampai ke Claude apa adanya, jadi jangan sertakan URL yang ditolak dan path lokal dalam teksnya. Tangkap exception di anggota Anda, dan raise ToolError (throw di TypeScript) dengan teks Anda sendiri.

Menjalankan tanpa tool runner

Teruskan instance di tools (browser.toJSON() di TypeScript), dan jawab setiap panggilan anggota dengan tool_result (toolResult di TypeScript). Alat penggunaan browser mengharuskan Anda berhenti pada panggilan gagal pertama (Tindakan batch). Setelah panggilan gagal, loop ini menjawab panggilan-panggilan berikutnya dalam giliran tersebut tanpa menjalankannya:

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:
                # Setelah panggilan gagal, sisa giliran hanya dijawab, bukan dijalankan.
                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})

Setiap jawaban untuk panggilan yang dilewati membawa is_error, toolset_name dari panggilan tersebut, dan teks persis yang diwajibkan oleh Tindakan batch. Tool runner mengirimkan jawaban yang sama.

Menjalankan toolset dengan aman

Tindakan Claude berikutnya bergantung pada halaman yang dibacanya. Sebuah halaman, atau teks yang disuntikkan ke dalamnya, dapat mencoba menjangkau layanan internal atau menarik file dari host. Halaman tersebut juga dapat mencoba memicu tindakan dengan efek nyata. Sebelum Anda menjalankan driver terhadap apa pun selain browser sekali pakai, lakukan enam langkah berikut:

  1. Tetapkan kebijakan URL: allowed_domains, blocked_domains, atau url_policy Anda sendiri.
  2. Intersep permintaan di driver dan minta putusan dari toolset.
  3. Terapkan kebijakan egress pada container, sehingga jaringan memblokir apa yang tidak dapat dilihat driver.
  4. Batasi unggahan dan unduhan, atau biarkan unggahan nonaktif.
  5. Batasi anggota yang berdampak dengan confirm.
  6. Isolasi host browser dalam container atau VM khusus untuk setiap sesi.

SDK menegakkan langkah 1, 4, dan 5 sesuai konfigurasi Anda. Langkah 2, 3, dan 6 menjadi tanggung jawab driver dan deployment Anda. Tindakan pencegahan di Pertimbangan keamanan juga berlaku.

Menetapkan kebijakan URL

Tetapkan allowed_domains (allowedDomains di TypeScript) ke situs-situs yang dibutuhkan tugas. Entri di salah satu daftar berupa domain (yang juga mencakup subdomainnya), alamat IP, atau jaringan CIDR. Dengan allowed_domains ditetapkan, toolset menolak setiap host lainnya.

browser = MyBrowser(backend, allowed_domains=["example.com", "iana.org"])

Jika tugas membutuhkan web terbuka, tetapkan blocked_domains (blockedDomains) sebagai gantinya. Daftar-daftar tersebut membandingkan hostname tanpa me-resolve-nya. Entri denylist 127.0.0.0/8 tidak memblokir localhost, jadi sebutkan nama host, bukan hanya jaringan. Ketika Anda menetapkan kedua daftar, blocked_domains yang berlaku.

Denylist tidak dapat menangkap nama publik yang di-resolve ke alamat privat. Jadi dengan blocked_domains, kebijakan egress container adalah yang mencegah nama semacam itu menjangkau alamat privat.

# Daftarkan host dan jaringan yang dapat dijangkau browser tetapi tidak boleh dijangkau Claude:
# rentang loopback, link-local, dan privat di IPv4 dan IPv6, 0.0.0.0/8, alamat
# dan nama metadata cloud Anda (seperti metadata.google.internal),
# localhost, serta hostname internal Anda.
browser = MyBrowser(backend, blocked_domains=internal_networks)

url_policy (urlPolicy) menggantikan kedua daftar, dan meneruskannya bersama salah satu daftar merupakan error konfigurasi. Kebijakan Anda tidak mengembalikan apa pun untuk mengizinkan URL, dan me-raise (throw) ToolError untuk menolaknya. Untuk mempertahankan aturan default, bangun kebijakan default dengan default_url_policy (defaultURLPolicy), dan panggil kebijakan tersebut terlebih dahulu dari kebijakan Anda sendiri:

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)

Kebijakan berjalan pada setiap URL navigate sebelum kode Anda, pada URL yang dilaporkan suatu hasil, dan pada setiap URL tab dan unduhan dalam laporan state. Dalam hasil dan laporan state, kebijakan melewati alamat yang tidak menyebutkan host remote: tab kosong, about:blank, halaman chrome-error: milik browser, dan dokumen data:.

Di bawah kebijakan apa pun, toolset menolak navigate ke skema selain http atau https, kecuali about:blank. url_policy="allow_all" (urlPolicy: "allow_all") menonaktifkan kebijakan, tetapi tidak menonaktifkan aturan skema ini.

Meneruskan url_policy=None (urlPolicy: null) membuat konstruktor me-raise error konfigurasi, sehingga None (null) yang terbaca dari konfigurasi Anda tidak dapat menonaktifkan pemeriksaan. Di TypeScript, undefined membiarkan opsi tidak ditetapkan, sama seperti tidak meneruskannya.

Ketika sebuah halaman berakhir di alamat yang ditolak, Claude membaca bahwa kontennya ditahan, dan tab tersebut dicantumkan sebagai (blocked). Hingga tab tersebut kembali berada di alamat yang diizinkan, toolset menolak panggilan pada tab itu. Pengecualiannya adalah navigate (tetapi bukan "reload"), new_tab, list_tabs, switch_tab, dan close_tab.

Mengintersep permintaan di driver

Kebijakan URL hanya menilai alamat yang dilihat toolset: navigasi, hasil, dan laporan state. Kebijakan tersebut tidak melihat sub-resource, panggilan fetch(), WebSocket, atau ke mana suatu hostname di-resolve.

Toolset mendeteksi alamat baru hanya ketika sebuah panggilan berakhir, dalam hasil atau laporan state dari panggilan tersebut. Jadi sebuah panggilan masih dapat bertindak pada halaman yang ditolak sebelum itu, dan SDK paling banyak hanya dapat menahan hasil dari panggilan tersebut. Kecuali driver Anda menilai setiap permintaan, termasuk lompatan redirect, halaman yang me-redirect ke alamat yang ditolak tetap akan dimuat.

Di hook permintaan driver Anda (fungsi yang dipanggil library otomatisasi Anda sebelum setiap permintaan), panggil check_url (checkURL). Fungsi ini menerapkan kebijakan milik toolset itu sendiri, sehingga Anda tidak perlu menulis aturan dua kali:

from anthropic.tools.browser import URLContext


class MyBrowser(BetaAbstractBrowserToolset20260801):
    ...

    # Didaftarkan pada konteks browser Playwright dengan 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 menerapkan aturan skema dan kebijakan yang sama dengan navigate. Hook permintaan seperti ini tidak melihat handshake WebSocket, permintaan service-worker, atau lompatan redirect. Blokir service worker. Nilailah handshake WebSocket dan lompatan redirect dengan hook yang dapat melihatnya.

Dalam fase permintaan, check_url hanya mengizinkan URL http, https, dan about:blank. Jadi untuk WebSocket, ubah ws:// menjadi http:// dan wss:// menjadi https:// sebelum Anda memanggilnya.

Menerapkan kebijakan egress pada container

Intersepsi tidak dapat melihat setiap permintaan yang dibuat browser, dan kebijakan URL tidak melihat ke mana suatu nama di-resolve. Kebijakan "egress" (lalu lintas keluar) yang ditegakkan oleh jaringan container mencakup keduanya:

  • Blokir rentang alamat loopback, link-local, dan privat di IPv4 dan IPv6, serta 0.0.0.0/8. Itu termasuk alamat metadata cloud 169.254.169.254.
  • Izinkan koneksi keluar hanya ke host yang dibutuhkan tugas. Jika aturan Anda mencocokkan alamat IP, resolve hostname yang Anda izinkan saat container dimulai.
  • Izinkan DNS hanya ke resolver milik container.
  • Jika driver Anda menjangkau browser melalui port DevTools lokal, izinkan loopback hanya pada port tersebut. Aturan untuk seluruh loopback akan membuka setiap layanan lokal bagi halaman.

Membatasi unggahan dan unduhan

file_upload nonaktif secara default. Tanpa file_policy, SDK menolak setiap unggahan yang menyebutkan path atau ID dokumen. Untuk mengaktifkan unggahan, teruskan LocalFilePolicy (NodeFilePolicy di TypeScript) dengan satu direktori unggahan yang hanya berisi file-file untuk tugas tersebut:

from anthropic.tools.browser import LocalFilePolicy

# MyBrowser yang juga mengimplementasikan file_upload
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,
    ),
)

SDK me-resolve setiap path unggahan, dengan mengikuti symlink, dan menolak path apa pun di luar root unggahan. Kebijakan file menolak direktori unduhan yang berada di dalam root unggahan. Path unduhan sampai ke Claude hanya ketika expose_download_paths (exposeDownloadPaths) bernilai true dan file berada di dalam direktori unduhan.

Pemeriksaan path bawaan me-resolve path pada filesystem dari proses yang menjalankan SDK. Pemeriksaan tersebut hanya melindungi browser yang berbagi filesystem tersebut. Untuk browser remote, ikuti Browser remote dan hosted sebagai gantinya.

Siapkan unduhan dengan cara berikut:

  • Buat direktori unduhan sendiri dengan mode 0700, dan mount dengan noexec,nosuid,nodev.
  • Jauhkan direktori tersebut dari jangkauan alat lain yang dapat dipanggil Claude, seperti shell atau alat file.
  • Dalam perubahan state download_failed, tulis error sebagai frasa tetap. Teks exception dapat berisi path atau URL.
  • Jangan membaca file yang diunduh ke dalam percakapan, atau menjalankannya, sampai seseorang memutuskan untuk melakukannya.

Membatasi anggota yang berdampak

javascript_exec dan file_upload nonaktif secara default. Jika Anda mengaktifkan salah satunya tanpa callable confirm, konstruktor me-raise error konfigurasi. Dengan callable confirm, SDK memanggilnya sebelum setiap panggilan yang akan dijalankan. Tanpanya, tidak ada yang ditanyakan.

Kembalikan True untuk menjalankan panggilan, atau False untuk menolaknya (true dan false di TypeScript). Ketika callable Anda bertanya kepada seseorang, tunjukkan kepada mereka anggota, URL halaman, dan input panggilan. Terlebih dahulu, escape setiap karakter dalam input yang berada di luar ASCII yang dapat dicetak, karena input dapat membawa teks dari halaman.

Contoh ini menanyakan tentang dua anggota yang dibatasi melalui fungsi ask_user Anda sendiri (askUser di TypeScript), dan menyetujui sisanya:

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:"):
            # Tanpa origin, atau halaman error: selalu minta persetujuan.
            return ask_user(
                f"Allow {name} on {page or 'a page with no origin'}?\n{detail}"
            )
        # Persetujuan hanya berlaku untuk input persis ini di halaman ini.
        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


# MyBrowser yang juga mengimplementasikan javascript_exec dan file_upload
browser = MyBrowser(
    backend,
    configs={"javascript_exec": {"enabled": True}, "file_upload": {"enabled": True}},
    confirm=make_confirm(),
)

Setiap panggilan ke make_confirm() (makeConfirm() di TypeScript) mengembalikan callable tanpa persetujuan apa pun. Panggil sekali untuk setiap toolset, dan berikan setiap pengguna toolset mereka sendiri.

Persetujuan mencakup halaman sebagaimana ditunjukkan oleh laporan state terakhir, dan halaman dapat berubah sebelum panggilan berjalan. Pembelian, pesan yang dikirim, dan persyaratan yang diterima terjadi melalui anggota biasa seperti left_click dan type, sehingga confirm tidak dapat memilahnya berdasarkan nama. Agar seseorang menyetujui tindakan tersebut, tanyakan juga tentang anggota-anggota itu.

Jangan aktifkan javascript_exec pada driver yang tidak mengintersep permintaan. Skrip yang berjalan pada halaman yang ditolak dapat menyalin kontennya ke tempat di mana pembacaan berikutnya akan mengembalikannya.

Mengisolasi host browser

Jalankan browser dalam container atau VM khusus dengan hak akses minimal untuk setiap sesi:

  • Jalankan sebagai pengguna non-root, dengan filesystem root read-only jika browser mengizinkannya.
  • Jangan mount apa pun dari host selain direktori unggahan dan unduhan yang Anda konfigurasikan, jika ada.
  • Jauhkan kredensial dari lingkungan, dan mulai dari profil browser yang baru.
  • Jangan berbagi filesystem dengan alat lain yang dapat dipanggil Claude.

Jalankan kode yang memanggil API di luar container browser, karena kode tersebut menyimpan kunci API Anda dan percakapan. Tool runner dan tool_result sama-sama menjalankan toolset dalam proses kode tersebut, sehingga browser tidak berbagi filesystem dengan toolset. Perlakukan browser sebagai remote: Browser remote dan hosted berlaku.

Perlakukan semua yang dikembalikan halaman sebagai tidak tepercaya, termasuk teks halaman, screenshot, entri konsol dan jaringan, judul tab, dan nama unduhan.

Browser remote dan hosted

Beberapa browser tidak berbagi filesystem dengan proses yang menjalankan SDK. Contohnya adalah browser di container lain, browser yang Anda jangkau melalui URL DevTools, dan browser dari layanan browser hosted. Dengan browser-browser ini, kebijakan URL, intersepsi permintaan, dan confirm tetap berjalan di proses Anda.

Dengan browser hosted, penyedia mengontrol egress dan isolasi host. Kebijakan egress Anda sendiri tidak berlaku di sana, sehingga hook permintaan driver adalah satu-satunya pemeriksaan Anda atas permintaan browser. Cari tahu apa saja yang dapat dijangkau oleh jaringan browser tersebut.

Pemeriksaan path bawaan tidak melindungi browser remote. LocalFilePolicy (NodeFilePolicy di TypeScript) memeriksa path pada filesystem dari proses yang menjalankan SDK, sedangkan browser membaca dan menulis filesystem-nya sendiri.

SDK tidak dapat mendeteksi bahwa sebuah browser bersifat remote. Jadi untuk browser remote, biarkan file_upload nonaktif kecuali driver Anda memeriksa path unggahan di tempat browser berjalan, dengan FilePolicy miliknya sendiri. FilePolicy memeriksa path dan ID dokumen dari setiap unggahan, dan memutuskan apakah Claude dapat melihat path unduhan.

Buat browser remote menolak unduhan, kecuali host-nya sendiri memiliki penyiapan unduhan dari Membatasi unggahan dan unduhan.

Contoh driver mengikuti aturan ini. Pada browser remote, contoh-contoh tersebut me-raise error konfigurasi untuk file_policy (filePolicy) atau file_upload yang diaktifkan, dan mengatur browser untuk menolak unduhan.

Jauhkan kunci API penyedia dan URL koneksi sesi, yang dapat berisi kunci, dari log, hasil alat, dan teks error. Jika penyedia merekam sesi, rekaman tersebut merupakan salinan lain dari semua yang dilihat dan diketik Claude, dan ketentuan retensi penyedia berlaku untuknya.

Referensi

Opsi konstruktor memiliki arti yang sama di kedua SDK:

PythonTypeScriptMenetapkan
configsconfigsAnggota mana yang diaktifkan
confirmconfirmCallable yang menyetujui atau menolak setiap panggilan
allowed_domains, blocked_domainsallowedDomains, blockedDomainsDaftar-daftar kebijakan URL default
url_policyurlPolicyKebijakan URL Anda sendiri
file_policyfilePolicyRoot unggahan dan eksposur path unduhan
tool_configstoolConfigsField untuk entri tools, seperti cache_control
Metode _browser_statebrowserStateLaporan state

Anda tidak dapat mengubah opsi setelah konstruksi. Nilai default, error, field konteks, dan kelas Python async (BetaAsyncAbstractBrowserToolset20260801) didokumentasikan di SDK Python dan SDK TypeScript.

Keterbatasan

  • Kebijakan URL memeriksa navigasi, bukan setiap permintaan: Lihat Mengintersep permintaan di driver.
  • Persetujuan didasarkan pada laporan state terakhir: Halaman dapat berubah setelah laporan tersebut. SDK tidak memeriksa ulang halaman sebelum panggilan berjalan.
  • Panggilan pada satu toolset berjalan satu per satu: Anda tidak dapat menonaktifkan perilaku ini.
  • SDK tidak memeriksa apakah ID tab unik, apakah satu tab aktif, atau berapa banyak tab yang ada: API menolak laporan yang melanggar aturan-aturan tersebut.

Langkah selanjutnya

Alat anggota, blok browser_state, dan pertimbangan keamanan alat tersebut.

Bagaimana SDK menjalankan loop, dan cara mengubah pesan yang dikirimnya.

Guardrail untuk aplikasi apa pun yang membaca konten tidak tepercaya.

Was this page helpful?