Your Coding Agent Can Now Inspect a Page Without Running Its JavaScript

·10 min read·Evergreen Tools Team

The most useful thing in Chrome's October 2026 DevTools recap is not a feature, it is a permission. Buried in the DevTools-for-agents section is a flag called --no-javascript-evaluation, which lets an agent inspect a page without running its scripts. Chrome 153 and 154 also added the ability to turn off JavaScript execution tools entirely, on-demand source maps, configurable filesystem roots, heap snapshot queries by retained size or property name, dedicated PWA automation tools, and optional stack traces in console listings. None of these make an agent smarter. All of them shrink the blast radius, which is the part that decides whether you can point an agent at a page at all.

Your Coding Agent Can Now Inspect a Page Without Running Its JavaScript

A browser with developer tools open beside a code editor

1. The Read-Only Switch Is the Headline

Pointing an agent at a live site is genuinely useful: console errors, network failures and layout problems are exactly the kind of evidence a coding agent cannot invent. The problem was that a browser automation layer with script evaluation could also change state — fill a form, submit an order, bump a counter. --no-javascript-evaluation closes that, and per the recap the control extends across navigations and initialization scripts rather than just the first document. You can also disable the JavaScript execution tools outright. For anything that is not a local dev build, that should be the default, and turning it on should be a deliberate, recorded decision for one task.

{
  "mcpServers": {
    "chrome-devtools": {
      "command": "npx",
      "args": [
        "-y",
        "chrome-devtools-mcp@latest",
        "--no-javascript-evaluation",
        "--isolated"
      ],
      "env": {
        "CHROME_DEVTOOLS_MCP_ALLOWED_ROOTS": "${workspaceFolder}"
      }
    }
  }
}

// Read this block as "read a page, do not run it".
// --no-javascript-evaluation keeps page scripts from executing while the agent
// inspects, and the recap notes the control extends across navigations and
// initialization scripts, not just the first document.

2. Memory Is Where Agents Quietly Fail

Two additions matter if your agent is debugging rather than reading: on-demand source maps, so large sites do not blow up memory when the agent attaches, and heap snapshot work — querying objects directly by retained size or property name, filtering edges by minimum retained size, and reporting memory kept alive by V8 execution contexts. Anyone who has watched an agent chase a 'memory leak' with a 4 GB snapshot open knows why this matters. The honest workflow is: get a stable baseline, sort by retained size, query by property name for the suspect, and only then read code. The tools now support that order; the agent will still try to skip to step three.

# Two ways to keep an agent read-only, picked by environment.

# Local build: full authority, it is your own code.
npx chrome-devtools-mcp@latest \
  --browser-url http://127.0.0.1:9222 \
  --allowed-root "$PWD"

# Anything that is not a local build: no evaluation, no unrestricted paths.
npx chrome-devtools-mcp@latest \
  --no-javascript-evaluation \
  --allowed-root /tmp/agent-run/$(date +%s)

# The recap also notes a --allow-unrestricted-paths behaviour in the CLI and
# configurable file system roots. Treat "unrestricted" as a local-dev-only flag:
# an agent that can read the whole disk can read .env, SSH keys and browser
# profiles, which is a data-exfiltration path far cheaper than a prompt injection.

3. Deciding Flags From the URL, Not From the Prompt

The most common failure I see is a policy that lives in the prompt: 'you are read-only' written in a system message, next to an agent that has full evaluation. Write the decision in code instead, keyed on the URL. A local build gets full authority. A third-party page gets an audit profile with evaluation off and a scratch root. A page you do not own, for any purpose other than a read-only audit, gets a refusal. That last branch is the one that keeps you out of the incident report, and it is three lines long.

# browser-policy.py — decide the flags from the URL, not from the prompt
from urllib.parse import urlparse

LOCAL = {"localhost", "127.0.0.1", "::1", "0.0.0.0"}

def decide(url: str, purpose: str) -> dict:
    host = (urlparse(url).hostname or "").lower()
    is_local = host in LOCAL or host.endswith(".local") or host.endswith(".test")

    if is_local:
        return {"flags": [], "js_evaluation": True,
                "reason": "local build, agent may drive and mutate"}

    if purpose == "audit":
        return {"flags": ["--no-javascript-evaluation"], "js_evaluation": False,
                "reason": "third-party page, read-only audit"}

    raise PermissionError(
        "refusing to attach an agent to %s for purpose=%r; "
        "use a recorded HAR or a staging copy instead" % (host, purpose))

# The failure this prevents is not exotic: a checkout page where an agent
# "tests the flow" and a script changes state. Read-only by default, write
# access only where you own the machine.

4. Bound the File System, Then Bound It Again

Configurable file system roots plus a CLI path flag sound like housekeeping until you consider what a browsing agent can read on a developer laptop: .env files, SSH keys, browser profile directories, shell history. An agent with an unrestricted root and a way to exfiltrate through a page is a data-loss path that costs far less than a clever prompt injection. Give the agent a per-run scratch directory, mount nothing else, and treat 'unrestricted paths' as a flag that exists for the two minutes you are debugging locally. The audit script below creates a timestamped output directory for exactly this reason.

#!/usr/bin/env bash
# browse-audit.sh — one page, read-only, artifacts on disk.
set -euo pipefail
URL="$1"; OUT="audit/$(echo "$URL" | tr '/:' '__')"; mkdir -p "$OUT"

npx -y chrome-devtools-mcp@latest \
  --no-javascript-evaluation \
  --allowed-root "$OUT" \
  --once --url "$URL" --out "$OUT" || true

# What you actually want out of an audit:
#   1. console errors (with stack traces, the recap added them to list_console_messages)
#   2. failed network requests
#   3. layout issues you can see in the screenshot
#   4. memory, only if the question is about memory
ls -la "$OUT"

5. Turn 'Looks Fine' Into an Assertion

The recap adds optional stack traces to list_console_messages, which makes console output checkable rather than skimmable. Use it. Pull the console log into a file, assert zero error-level messages outside a short ignore list, and require a stack trace on anything you accept into a baseline — an error without a stack is an error you have decided not to understand. Run the assertion before deploying, not after. This is the cheapest form of regression testing for a web app that an agent touched, and it catches the class of bug that a green unit test suite happily ignores.

# assert-console.py — turn "looks fine" into a check that can fail CI
import json, sys

def load(path):
    with open(path) as f:
        return json.load(f)

def failing(messages, ignore=("favicon.ico", "third-party-cookie")):
    bad = []
    for m in messages:
        text = (m.get("text") or "")
        if any(i in text for i in ignore):
            continue
        if m.get("level") in ("error", "assert"):
            bad.append((m.get("level"), text[:120], bool(m.get("stackTrace"))))
    return bad

if __name__ == "__main__":
    msgs = load(sys.argv[1])
    bad = failing(msgs)
    for level, text, has_stack in bad:
        print(f"[{level}] {text}  stack={has_stack}")
    sys.exit(1 if bad else 0)

# Two habits worth keeping:
#   - assert on console errors before a deploy, not after
#   - require a stack trace for every error you accept into a baseline

6. A Configuration I Would Ship Today

If you take one thing from this: give your browsing agent two profiles, not one. A local profile with evaluation on, a scratch root and a short lifetime; and an audit profile with evaluation off, a timestamped output directory and an assertion script that fails CI on console errors. Then decide which profile runs from the URL, in code, and log the decision with the run. The interesting part of agentic browsing was never the model's ability to click. It was whether you could hand it a page and still be able to say afterwards, precisely, what it was allowed to touch.

Your Coding Agent Can Now Inspect a Page Without Running Its JavaScript

A padlock and network cables, representing controlled access

Your Coding Agent Can Now Inspect a Page Without Running Its JavaScript

Charts of memory and performance measurements

📌 Frequently Asked Questions

What does --no-javascript-evaluation do?

It lets a coding agent inspect a page without evaluating its scripts. According to Chrome's October 2026 DevTools recap, the control extends across navigations and initialization scripts, and you can also turn off the JavaScript execution tools entirely.

Which Chrome versions shipped these changes?

Chrome 153 and Chrome 154, as summarised in the October 2026 New in DevTools post. Chrome now releases twice a month, so the DevTools series became a monthly recap.

What memory improvements were added?

On-demand source maps so large sites do not consume high memory when source maps are enabled, heap snapshot edge filtering by minimum retained size, direct object querying by retained size or property name, aggregate memory reporting for V8 execution contexts, and clearer errors for corrupted snapshot files.

What is query_heapsnapshot?

A DevTools-for-agents tool that queries heap snapshot objects directly by retained size threshold or property name, which shortens memory-leak investigations.

What else is in the October recap?

Ad script tracking in the Application panel, full soft navigation support and CPU performance tier overrides in Performance, inactive style support and keyboard-accessible adorners in Elements, modernised device presets, edit-and-resend-as-fetch in Network, and several accessibility fixes.