"Headless or headful" usually gets decided once, early, and never revisited—headless for CI because it's faster, headful for local debugging because you want to watch. That default is fine for traditional test suites. It breaks down for AI browser agents, where the same session might need to run unattended at scale one minute and be watched by a human or a vision model the next.
What Headless Actually Removes
A headless browser still parses HTML, builds a full DOM, runs JavaScript, and executes the network stack exactly as it would with a window open—it just skips compositing pixels to a display. That's why headless is lighter on memory and CPU and starts faster: there's no rendering surface to paint. For a scraper or a test suite that only reads the DOM or asserts on selectors, none of that missing pixel output matters.
It matters the moment your agent's decision loop depends on what the page looks like rather than what's in the tree. Computer-use and vision-based agents that reason over screenshots need an actual rendered frame to capture, and some layout and animation states genuinely differ under compositing versus none. Headless also removes the one thing a human reviewer needs to sanity-check a run in progress: something to look at.
Where Headful Earns Its Overhead
Headful mode costs more resources per session, but it buys three things scraping-only workloads don't need: a real rendering surface for screenshot- or vision-driven agents, a live feed a human can watch to catch a flow going sideways before it fails silently, and, for anything shared with a non-technical stakeholder, something you can point a browser tab at and say "here's what the agent is doing right now."
Making It a Runtime Setting, Not a Rebuild
Anchor sessions start headful by default, with recording enabled, since most agent workloads benefit from visibility until proven otherwise. Switching to headless is a single field on session creation, not a different code path:
import os
from anchorbrowser import Anchorbrowser
anchor_client = Anchorbrowser(api_key=os.getenv("ANCHOR_API_KEY"))
# High-throughput extraction: no one needs to watch this run
headless_session = anchor_client.sessions.create(
browser={"headless": {"active": True}}
)
# Agent build/debug: keep it visible
headful_session = anchor_client.sessions.create(
browser={"headless": {"active": False}}
)
print(headful_session.data.live_view_url)
Every session, headless or headful, returns a live_view_url you can drop into an iframe to watch it in real time—in headful mode it renders the full Chrome chrome, address bar included, which is what you want when a teammate or an end user needs to follow along. The connection your automation code makes is identical either way: same cdp_url, same Playwright or Puppeteer calls, same DOM. The only thing that changes is whether there's a frame being painted for something to look at.
Choosing Between Them
Default to headless for anything that runs unattended at volume—scheduled scrapers, regression suites, batch extraction jobs—where the only output that matters is data or a pass/fail signal. Reach for headful when an agent is new enough that you don't trust it yet, when a computer-use model needs actual screenshots to reason over, or when someone other than you needs to watch a run happen. Treating it as a per-session flag instead of a fixed architecture choice means you don't have to guess which one you'll need before you've built the agent.
If you're building agents that need to move between both modes without maintaining two separate browser setups, that's what Anchor's cloud sessions are built for. Get an API key and try toggling a session between headless and headful against a flow you're already automating.



