Skip to main content
Run a JavaScript expression inside a context of a running dev session and print the result. eval is the most powerful automation verb, so it is double locked. The session must be started with extension dev --allow-eval, and the CLI must present the session token that the dev server wrote for this project and browser. Both happen automatically when you run the two commands from the same project root.

When to use eval

  • You want to poke at extension state (chrome.runtime, storage, DOM) without opening DevTools.
  • An agent needs to run a check inside the page and get a structured value back.
  • You want a scriptable REPL against the background worker or a live tab.

Usage

For example, read the title and URL of the active tab from inside the page:

Arguments and flags

Extension pages (popup, options, sidebar, devtools, newtab, history, bookmarks) answer through their own in-page relay, so the surface must be open in the browser. Use open (documented in Trigger actions and commands) to open one first. On Firefox, an extension document whose policy forbids eval answers through the debugger protocol instead. Since 4.1.32 that route also takes a statement list: it answers the completion value of the last statement and awaits a promise the statements end on. A result past 256 KiB comes back as a 1024 character preview with truncated: true on the envelope, and pretty output prints a result truncated (byte cap) line. Pretty output prints the value itself: strings as-is, everything else as indented JSON. The envelope shape appears only under --output json (see Result envelope).

How the unlock works

  1. extension dev --allow-eval starts the session with eval enabled. --allow-eval also unlocks the other control verbs, so you do not need both flags.
  2. The dev server writes a random session token to .extension-js/control-token-<browser> with 0600 permissions. The token is keyed per browser, so concurrent sessions do not collide.
  3. eval reads that token from the project root and presents it during the handshake.
A session started without --allow-eval refuses the call, and the refusal names --allow-eval as the flag to add. A missing token fails with E_TOKEN_MISSING, a mismatched or disabled one with E_EVAL_REFUSED.

Failure modes

  • The expression threw inside the target: E_EVAL, with a hint that the expression itself is at fault. This is a result, not a transport error.
  • A content security policy forbids eval in the target: E_CSP_BLOCKS_EVAL. An MV3 extension forbids eval in its own documents and content scripts, and a web page can forbid it for itself. On Firefox, the CLI evaluates an extension document through the debugger protocol when the extension’s policy forbids eval. Read the target with inspect when you get this code. Since 4.1.32, Firefox also evaluates a web page that forbids eval for itself through the debugger, when exactly one open tab is on that url. With a duplicate tab open the call keeps the refusal and the hint names the tab to close.
  • No session for the browser: E_SESSION_NOT_FOUND, with the exact extension dev command to run.
  • Target surface not open, or a stale --tab id: E_TARGET_NOT_FOUND. Use inspect --list-tabs to find live ids.
  • The call outlived --timeout: E_TIMEOUT.
The exit code is 0 when the expression succeeds and 1 otherwise, so scripts can gate on it directly. Run doctor when every verb fails and you want the broken leg named.

Next steps

  • Find tab ids and DOM state to target with inspect.
  • Read or write chrome.storage without writing an expression with storage.
  • Read the wider debugging workflow in Debugging.
  • Review the machine output format in Result envelope.