Core Usage

Site Adapters

For task-specific CLI guidance, load chrome-use skills get core/site-adapters. Ordinary clicks and form actions are already covered by core.

To read "structured data from site X," the cheapest path is to skip snapshot + click. Before you open, page through, and click your way across GitHub / Reddit / Bilibili, check whether a ready-made site adapter exists — a small community-written JS snippet that hits the site's own JSON API directly from your logged-in tab and hands you clean structured data in one shot. No clicking, no scraping, no screenshots.

What it is

A site adapter is a community-written JS function: it calls the site's own JSON API directly from your currently logged-in tab and returns clean, structured data. Essentially it's a packaged, per-site eval — except you don't have to write it yourself, and you don't have to reverse-engineer each site's endpoints.

Because it runs inside the tab you're already logged into and makes requests as you, feeds that require a session — like bilibili/feed or twitter/… — read fine too. That's exactly what hand-crafting URLs or anonymous scraping can't do.

ℹ️ Relationship to eval
If you already know how to use eval to hit a site's internal API, a site adapter is that same code distilled into a command — maintained by the community and organized per site. You skip the grunt work once, and everyone else gets to reuse it.

How to use it

Four actions: pull the sources once (update), see what's installed (list), see how a given adapter is called (info), and run it (site <name>/<cmd>).

bash
$ chrome-use site update                            # one-time: pull community, official, and extra sources
$ chrome-use site list                              # what's installed (github/issues, reddit/search…)
$ chrome-use site info github/issues                # an adapter's params + which domain it runs on
$ chrome-use site info github                       # every adapter in the pack, with params + usage
$ chrome-use site github/issues owner/repo --json   # run → JSON (navigates there for you)

With --json, that last command returns the site's own data, already cleaned into a parseable structure (excerpted and indented below):

what site github/issues epiral/bb-sites --json returns
{
  "success": true,
  "data": {
    "domain": "github.com",
    "origin": "https://github.com/",
    "result": {
      "count": 30,
      "repo": "epiral/bb-sites",
      "state": "open",
      "issues": [
        {
          "number": 85,
          "title": "feat(youtube/transcript): migrate to API-based subtitles",
          "author": "kerrmoulton",
          "state": "open",
          "is_pr": true,
          "comments": 0,
          "labels": [],
          "created_at": "2026-06-16T07:54:47Z",
          "url": "https://github.com/epiral/bb-sites/pull/85"
        }
        // … 29 more with the same shape; count is the total returned
      ]
    }
  },
  "error": null
}
✅ info first, then run
When you're not sure what params an adapter needs, run site info <name>/<cmd> first to see its declared params and target domain, then pass them accordingly. Cheaper than blindly running once and reading the error.

Params and navigation

Adapter params are filled positionally in declaration order; to override one by name, use --key value. The two forms mix freely: positional args fill the slots, and --key pins a specific override.

positional vs --key override
# positional args fill in declaration order
$ chrome-use site github/issues owner/repo --json

# --key overrides by name (order doesn't matter)
$ chrome-use site reddit/search --query "chrome-use" --sort new --json

When it runs, it navigates to the domain the adapter declares — and if your current tab is already on that domain, it reuses the current tab instead of opening a new one. The request still happens inside the tab you're logged into, so signed-in feeds like bilibili/feed or twitter/… return normally (why they do is covered under "What it is" above).

ℹ️ It navigates for you
You don't have to open the target site manually first. site <name>/<cmd> navigates to the adapter's domain and then executes; but you do need to be already logged in to that site for logged-in feeds to be readable.

Long text, local files, long runs

Adapters that write (publish an article, upload a video) also run as one command: the body is read from a file, a local file is handed to the adapter, and waiting for an upload or a publish is no longer bound by the ~8s budget of a single command.

publish adapters
# Long text from a file or stdin, instead of "$(cat post.md)"
$ chrome-use site csdn/article-publish --title "Hello" --markdown @post.md
$ cat post.md | chrome-use site csdn/article-publish --title "Hello" --markdown @-

# An arg the adapter declares as "type": "file" takes a local path (shown by site info)
$ chrome-use site douyin-creator/video-publish --video ./clip.mp4 --title "Hello"

# Keep going until the upload / publish is really done
$ chrome-use site bilibili-creator/video-publish --title "Hello" --tags a,b --until-done --timeout 10m

# Writing an adapter: declare the file arg in @meta.args; optional "timeout": 600 (seconds) in @meta
#   "video": {"required": true, "type": "file", "input": "input[type=file]"}
# In the function: put the file on the page's file input, report progress, read the time this run has
#   await args.video.setOn();   args.progress('uploading');   args.budgetMs
⚠️ A timeout is not a failure
status: "timeout" only means the adapter was still running when time ran out; the run in the page may finish afterwards. Check the page before rerunning a publish command, so nothing is published twice.

Auto-triggering — see it, use it

You don't have to remember which sites have adapters. chrome-use keeps the adapter sources in sync automatically (on first use + weekly), and whenever you reach a page whose domain has adapters it tells you: on every open / navigate / snapshot, and on any other command that lands you on a different site (tab new, switching tabs, back / forward, a click that navigates, the first command on a tab you didn't open). Staying on one site, you hear about it once. The hint is:

auto-hint · stderr
$ chrome-use open https://github.com/epiral/bb-sites
# … as the page opens, a line pops up on stderr:
site adapters for github.com — prefer these for structured data:
   github/issues, github/pulls, github/repo …
   e.g. chrome-use site github/issues <repo> --json
   args: chrome-use site info github
✅ See the hint, prefer the site <name>/<cmd> it lists
When you see site adapters for <domain>, don't snapshot + click to read the data — just use the site <name>/<cmd> it names: cheaper, more reliable, and already installed. You also don't need to run site update yourself first — just use the command it gives you.

A site you use a lot has no adapter

When you drive the same site a lot (30+ actions this session, or on 3+ days) and no adapter covers it, chrome-use adds siteAdapterSuggestion: {domain, actionsThisSession, daysUsed, message} to one response (stderr: site adapter suggestion: …), so the AI asks you whether to turn the steps it keeps repeating into an adapter. It comes once per site per session and not again for two weeks; local hosts and IPs are skipped. If you say yes, the AI writes it to ~/.chrome-use/my-sites/<name>/<cmd>.js, registers the folder once with chrome-use site add ~/.chrome-use/my-sites, and runs site update. AGENT_BROWSER_SITES_NO_SUGGEST=1 turns it off.

Adding OpenCLI-format adapters

site add detects OpenCLI-format sources: an OpenCLI plugin repo (e.g. chrome-use site add darinouyang/opencli-plugin-shipxy), a zip, or a local dir such as your existing ~/.opencli/clis. Their commands run through the same OpenCLI runtime over your chrome-use session and show as (opencli: <source>) in site list. .js modules are supported, and .ts ones on Node 22.13+; YAML-only plugins are not (OpenCLI itself stopped loading YAML in 1.8). OpenCLI adapters are Node code running on your computer with your user's permissions, not inside the page like chrome-use adapters. So a local dir is added directly, while a remote source is pinned to the commit (zip: SHA-256) you trusted: at a terminal site add lists its modules and asks, and scripts or agents must pass --trust-node-code. site update re-copies local dirs but never moves a remote pin; run site add again to take a newer version. On a shared name: our adapters, then your OpenCLI sources, then the OpenCLI package.

OpenCLI is a last resort

With Node.js 20+ on PATH, site update also installs OpenCLI (about 180 sites and 1,300 commands; a pinned version, installed with --ignore-scripts). A name/cmd that neither adapter pack has runs through OpenCLI's own runtime, driving your current chrome-use session and its logins, e.g. chrome-use site hackernews/best --limit 5 --json. They show as (opencli) in site list, site info shows their args, and they come last in the site hint. On a shared name ours always win (priority: a site add source, then the official chrome-use-sites pack, then the bb-sites community pack, then OpenCLI); if ours fails and OpenCLI has a read command of the same name, that runs instead (writes never retry). AGENT_BROWSER_SITES_NO_OPENCLI=1 turns them off. douyin/delete, douyin/update, twitter/delete, twitter/like, twitter/follow, bilibili/user-videos and bilibili/creator-stats used to come from OpenCLI and are now maintained in chrome-use-sites (ported with attribution, Apache-2.0); OpenCLI never runs them, and a cache that predates them is synced on first use. Delete, like and follow open their page first, so run them with --until-done. OpenCLI is third-party code chrome-use does not maintain, and its commands have shipped broken. Every OpenCLI run prints a stderr note: … third-party OpenCLI command, not maintained by chrome-use; --json adds maintainedBy: "opencli", readOnly and notice. Use our own adapter whenever one exists; for posting, liking, following, deleting or publishing on your real accounts, don't rely on OpenCLI: port the command into chrome-use-sites.

When the site is not signed in

An adapter that finds the site signed out returns {"loginRequired": true} (with any error code, plus an optional loginUrl, the sign-in page relative to the site). error: "login_required" or "not_logged_in" means the same. chrome-use also counts a failed run as signed out when one of the adapter's fetch calls got HTTP 401 or was redirected to a sign-in page, or the tab ended on one. Then the command fails with a login wall: <host> is not signed in … line on stderr and loginWall in --json, pointing at auth login --bwu instead of the adapter's own message. The first time for a site it asks whether to sign in from the vault: this time, always for that site, or never. A terminal gets a prompt; an agent gets loginWall.ask with the question and one command per answer, and must relay it to you rather than choose. With chrome-use auth autologin always <host> it opens loginUrl, signs in with the vault login for the site and runs the command once more. auth autologin status shows the decisions and auth autologin off <host> forgets one. A write adapter is rerun only when it reported the login itself; one whose failure was inferred from a 401 or redirect may have half-run, so it is left for you to check.

Writing your own: analyze and verify

Do the action that loads the data on the page first (search, scroll, open the list), then run chrome-use site analyze. It lists the API calls the page made, the state it embeds (__NEXT_DATA__, __INITIAL_STATE__, …) and any anti-bot vendor, and recommends a data source. In order of preference: a public API, the site's own JSON API called from the page with its cookies, embedded page state, then the DOM. Each step down breaks more often. Once it works, chrome-use site verify <name>/<cmd> [args] --write-fixture records the shape of a good result; later, site verify fails (exit 1) when a field disappears, changes type, or a list comes back empty. The fixture keeps the shape only, never values.

ℹ️ Exception on a fresh environment
Only on a brand-new environment where the adapter sources haven't been pulled yet might naming a site <name>/<cmd> report "not installed." In that case run site update once and re-run the command.

When to use it vs extract --schema vs snapshot

There's often more than one path to the same page of data. Site adapters are the first choice for structured data from a known site; fall back down the ladder when no suitable adapter exists. The table below helps you pick.

Your situationUseWhy
Structured data from a known site (GitHub issues, Reddit/HN search, Bilibili / Twitter feeds), especially once logged in chrome-use site <name>/<cmd> Hits the site's JSON API directly, runs as you, skips snapshot + click — cheapest and most reliable
Structured data from any page with no community adapter — tables, search results, feed rows, dashboards extract --schema '{rows,fields}' Give it a shape, get clean JSON in one call — no writing eval, no dumping the whole page's HTML
You need to reason over it with a model, or need @refs to interact snapshot -i --json A structured snapshot with stable refs — readable and drives follow-up click / type
A one-off extraction needing a custom shape with special logic eval --stdin Write JS directly in the page's MAIN world — most flexible (an adapter is just this, distilled)
ℹ️ Cheapest to most expensive
Roughly: site adapter → extract --schema → snapshot/eval loop. If there's an adapter, use it; no adapter but a regular shape, use extract --schema; only when neither fits fall back to the usual manual snapshot / eval loop. For the full picture of data extraction, see Extracting Data.

Source and license

Adapters come from two defaults: the bb-sites community source and the chrome-use-sites official source. chrome-use fetches and executes them at runtime — this repo does not bundle or redistribute any adapter code, and site update fetches the latest version from upstream each time.

ℹ️ Fetched at runtime, not built in
Because adapters are maintained in the community and official sources and fetched only at runtime, the command set you see changes as either default source updates; site list reflects the version you synced to locally this time.

Next steps

Site adapters are the cheapest tier of data extraction; the methods below cover the rest.