npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@browserless.io/cli

v0.0.2

Published

Browserless CLI — manage authentication profiles, sessions, and other Browserless features from your terminal.

Readme

📋 Table of Contents

🚀 Get Started in Seconds!

Step 1: Install

npm install -g @browserless.io/cli

Requires Node.js ≥ 24.

Step 2: Log in

# Pass your API token as a positional arg, or pipe it via stdin to keep
# it out of shell history.
browserless auth login <your-token>
echo $TOKEN | browserless auth login

Tokens are stored in your OS keychain when available (Keychain on macOS, libsecret on Linux, DPAPI on Windows) and fall back to a mode-0600 file at ~/.browserless/config.json when not.

browserless auth status    # who am I, where is my token stored?
browserless auth logout    # wipe credentials (keychain + file)

Step 3: Capture a profile

# Capture from your local Chrome and upload it as a cloud profile
browserless profile upload \
  --browser chrome --profile Default --name my-chrome

✅ Success! Any Browserless cloud session can now start already authenticated by attaching ?profile=my-chrome to its launch URL.

Picking a server

By default the CLI talks to https://production-sfo.browserless.io. Two ways to point it elsewhere:

# Production regions — short codes for production-<code>.browserless.io
browserless config set region sfo                # San Francisco (default)
browserless config set region lon                # London
browserless config set region ams                # Amsterdam

# Or a full URL — for self-hosted / staging deployments
browserless config set server https://my-browserless.example.com

Per-invocation overrides: --region <code> or --server <url>. Passing both flags (or having both keys set in config) is an error — they're mutually exclusive.

🗂 Capture Commands

First-run note (macOS only). The first time you run profile upload or profile refresh, macOS may show a one-time Keychain prompt: "Google Chrome wants to access key 'Chrome Safe Storage' in your keychain". This is the launched Chrome reading its own existing keychain entry — not the CLI asking for new access. Click Always Allow and you won't see it again.

Liability disclaimer. The first profile upload or profile refresh shows a one-screen disclaimer and asks you to type I accept. The acknowledgment is recorded and re-prompted every 7 days by default. Use --accept-terms (or BROWSERLESS_ACCEPT_TERMS=1) in scripts / non-interactive shells; --terms-ttl-days <n> tunes the re-prompt window (0 to re-prompt every run).

# Discover local browser profiles
browserless profile sources list

# Capture and upload as a new cloud profile (strict create)
browserless profile upload \
  --browser chrome --profile Default --name my-chrome

# Re-capture and overwrite an existing cloud profile (strict replace)
browserless profile refresh \
  --browser chrome --profile Default --name my-chrome

# Capture and print a summary without uploading (handy for debugging)
browserless profile inspect --browser chrome --profile Default

# Launch your real browser interactively against the local profile —
# useful for fixing up auth state (logging in, dismissing dialogs)
# before re-running `profile refresh`. Source browser must be closed.
browserless profile launch --browser chrome --profile Default

# Manage cloud profiles
browserless profile list
browserless profile list --limit 50 --offset 0
browserless profile show my-chrome
browserless profile rename my-chrome my-chrome-v2
browserless profile delete my-chrome-v2

--browser and --profile

--browser accepts either the short key or the display name in quotes:

| Key | Display name | | --------------- | -------------------------------------------------- | | chrome | Google Chrome | | chrome-beta | Google Chrome Beta | | chrome-dev | Google Chrome Dev | | chrome-canary | Google Chrome Canary | | brave | Brave | | edge | Microsoft Edge | | vivaldi | Vivaldi | | opera | Opera | | arc | Arc | | chromium | Chromium (incl. Snap on Linux) | | (custom) | whatever you registered via profile sources add |

The match is case-insensitive: --browser CHROME, --browser Chrome, and --browser "google chrome" all resolve to the same entry.

--profile accepts either the user-visible profile name from Local State (e.g. Personal, Work) or the on-disk directory name (Default, Profile 1). If multiple profiles match (rare — display names should be unique within a browser), the CLI prints all candidates so you can disambiguate by passing the directory name.

🔒 Privacy & Domain Filtering

Cookies and origin storage for sensitive domains can be filtered out locally, before the upload leaves your machine — Browserless never sees them:

browserless profile exclude add chase.com
browserless profile exclude add "*.okta.com"
browserless profile exclude list
browserless profile exclude rm chase.com

Suffix-match: example.com matches example.com, .example.com, www.example.com, and sub.www.example.com. The optional *. prefix is the default behaviour — *.example.com is identical to example.com. Non-ASCII / IDN domains are accepted; they're punycode-normalized to match how Chrome stores them.

Or one-shot for a specific upload (repeatable):

browserless profile upload \
  --browser chrome --profile Default --name demo \
  --exclude-domain chase.com --exclude-domain "*.okta.com"

Use --no-default-excludes to ignore the persistent list for a single invocation (e.g. when refreshing a profile that needs a domain that's normally excluded).

In addition to your list, the CLI always filters out cookies and origin storage for localhost, *.local, *.internal, and IP-literal hosts. These aren't user-configurable — they protect against accidentally uploading intranet / corp / local-network state that would never apply to a cloud session anyway.

📦 Managing Artifact Size

The Browserless server caps uploaded profiles at 2 MB of serialized state (cookies + per-origin localStorage + IndexedDB). Real-world profiles usually fit easily, but a handful of heavyweight sites (figma.com, google.com, vendor analytics) can push you over. When the capture exceeds the cap, the CLI prints the heaviest origins on stderr and the upload returns HTTP 400 — pick one of the flags below to fit under it.

| Flag | Effect | | ------------------- | --------------------------------------------------------------------------------------------------------------- | | --auto-fit | Drop the heaviest origins (largest first) until the artifact fits under the cap. Cookies are never dropped. | | --keep-domain <d> | Protect a domain from --auto-fit drops — suffix-match (same syntax as --exclude-domain), repeatable. | | --only-domain <d> | Allowlist: capture only cookies / origins matching these domains, discard everything else. Suffix-match, repeatable. Applies after --exclude-domain. |

# Auto-drop heaviest origins so the upload succeeds, but never drop google.com
browserless profile upload \
  --browser chrome --profile Default --name demo \
  --auto-fit --keep-domain google.com --keep-domain github.com

# Capture only the sites you care about — everything else is discarded locally
browserless profile upload \
  --browser chrome --profile Default --name demo \
  --only-domain github.com --only-domain "*.atlassian.net"

--auto-fit reports each origin it dropped on stderr; --only-domain reports how many cookies / origins it kept and dropped. If --auto-fit can't reach the cap because every remaining heavy origin is protected by --keep-domain, the CLI tells you which --keep-domain to relax.

🧩 Custom Chromium Browsers

Register any Chromium-based binary the built-in registry doesn't know about (Thorium, Cromite, a self-built Chromium, ...):

browserless profile sources add \
  --name my-chromium \
  --path /path/to/chromium \
  --user-data-dir /path/to/user-data-dir
browserless profile sources rm my-chromium

The --name doubles as both the display name and the --browser <key> value. Registrations are stored in ~/.browserless/custom-browsers.json. If the binary or user-data-dir later goes missing, profile sources list flags the entry under "Registered custom browsers with missing paths" so you can clean it up with profile sources rm.

⚙️ Shared Flags

Every command that hits the cloud API accepts:

| Flag | Effect | | ----------------- | --------------------------------------------------------------- | | --token <tok> | Override token resolution (flag > env > keychain > config file) | | --server <url> | Override the configured server URL | | --region <code> | sfo / lon / ams — shorthand for --server | | --json | Emit the server response as JSON (script-friendly) |

Capture commands (upload, refresh, inspect) also accept:

| Flag | Effect | | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | --exclude-domain <d> | Append a domain to the exclusion list for this run (repeatable) | | --no-default-excludes | Skip the persistent exclusion list for this run | | --only-domain <d> | Allowlist: capture only domains matching this pattern (repeatable, applies after --exclude-domain) | | --auto-fit | If the artifact exceeds the 2 MB server cap, drop the heaviest origins until it fits (see Managing Artifact Size) | | --keep-domain <d> | Domain that --auto-fit must never drop (repeatable) | | --accept-terms | Pre-accept the liability disclaimer | | --terms-ttl-days <n> | Override the re-prompt TTL for this run (0 = every run) | | --password-store <s> | Linux only — pass basic / gnome-libsecret / kwallet5 through to the launched browser if auto-detection picks wrong |

🛠 Configuration

~/.browserless/config.json is created with mode 0600 on first use. Manage user-managed keys via the commands below; CLI-managed keys are written automatically and not user-editable.

| Key | Kind | How to change | | ------------------- | ----------- | ------------------------------------------------------------------------ | | server | user scalar | browserless config set server <url> (mutually exclusive with region) | | region | user scalar | browserless config set region <sfo\|lon\|ams> | | terms_ttl_days | user scalar | browserless config set terms_ttl_days <n> (default 7) | | excluded_domains | user list | browserless profile exclude add/rm/list | | accepted_terms_at | CLI-managed | written when you accept the disclaimer | | token_storage | CLI-managed | written by auth login (keychain or file) | | api_key | CLI-managed | written by auth login only when keychain is unavailable |

browserless config get server
browserless config get api_key                        # redacted by default
browserless config get api_key --show-sensitive       # print verbatim
browserless config set terms_ttl_days 30
browserless config unset region

config set is scalar-only — list keys (excluded_domains) go through profile exclude, CLI-managed keys can't be set directly (they have side-effects the CLI itself owns).

🌍 Environment Variables

| Variable | Effect | | ------------------------------ | ---------------------------------------------------------------------- | | BROWSERLESS_TOKEN | Use this token without a stored credential (overrides keychain + file) | | BROWSERLESS_ACCEPT_TERMS | 1 to pre-accept the liability disclaimer | | BROWSERLESS_CONFIG_DIR | Override ~/.browserless/ location (CI / multi-tenant) | | BROWSERLESS_DISABLE_KEYCHAIN | 1 to force plaintext config-file storage even if the keychain works | | BROWSERLESS_CDP_WAIT_MS | Override the 15 s CDP-readiness timeout (raise on slow CI runners) |

🚦 Exit Codes

| Code | Meaning | | ---- | ------------------------------------------------------------------------------------------------------- | | 0 | Success | | 1 | Internal bug — prints a stack trace | | 2 | Bad arguments (UsageError) | | 3 | Precondition failed — no token, disclaimer declined, profile busy, corrupt config (PreconditionError) | | 4 | Local capture pipeline failed — copy / browser launch / CDP (CaptureError) | | 5 | Server returned a non-2xx response (ApiError) |

💡 Why use the CLI?

Sharing a logged-in browser session with a cloud worker is painful.

Cookies live in OS-encrypted SQLite. localStorage and IndexedDB are spread across LevelDB on disk. Manually re-logging in on every cloud session is busywork — and rolling your own cookie export usually ends in "why am I randomly logged out of everything?" when Chrome Sync realises a copy of the profile woke up on a server farm.

The CLI does this once, safely. It launches a temporary copy of your profile in a controlled-headless mode that suppresses Chrome Sync / Safe Browsing / component-update traffic, reads cookies + localStorage + IndexedDB via CDP, applies your domain-exclusion list locally, and uploads only the result. Your real profile is never touched; sensitive domains never leave your machine.

Once uploaded, any Browserless cloud session can attach the profile via ?profile=<name> and start already authenticated.

📜 Licensing

Distributed as part of the Browserless platform. The LICENSE file ships in the package; see browserless.io for full terms.

If you're building a commercial application on Browserless, a commercial license covers priority support, on-premise deployment, source modification, and the admin UI in addition to keeping your software proprietary.

Happy capturing!

Need help? Reach out to us at [email protected]