Skip to content
Learn Agentic AI
Learn Agentic AI11 min read40 views

Headless vs Headed Playwright: When AI Agents Need a Visible Browser

Understand the differences between headless and headed browser modes in Playwright, when to use each for AI agents, and how to configure headed mode in Docker, CI/CD, and remote environments.

Headless vs Headed: What Is the Difference?

A headless browser runs without any visible window. It executes the same browser engine — rendering HTML, executing JavaScript, handling CSS — but does not draw pixels to a screen. A headed browser runs with a visible GUI window where you can see every page load, click, and navigation in real time.

Playwright defaults to headless mode, which is the right choice for production AI agents. But headed mode is invaluable for development, debugging, and specific use cases where visual confirmation is required.

Launching in Each Mode

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    # Headless (default) — no visible window
    headless_browser = p.chromium.launch(headless=True)

    # Headed — visible browser window
    headed_browser = p.chromium.launch(headless=False)

    # Headed with slow motion — adds delay between actions
    debug_browser = p.chromium.launch(
        headless=False,
        slow_mo=500,  # 500ms pause between each action
    )

    headless_browser.close()
    headed_browser.close()
    debug_browser.close()

The slow_mo option is particularly useful during development. It slows down every Playwright action so you can visually follow what your agent is doing.

flowchart TD
    START["Headless vs Headed Playwright: When AI Agents Nee…"] --> A
    A["Headless vs Headed: What Is the Differe…"]
    A --> B
    B["Launching in Each Mode"]
    B --> C
    C["When to Use Headless Mode"]
    C --> D
    D["When to Use Headed Mode"]
    D --> E
    E["Using Playwright Inspector for Debugging"]
    E --> F
    F["Codegen: Generating Scripts from Manual…"]
    F --> G
    G["Running Headed Playwright in Docker"]
    G --> H
    H["CI/CD Configuration"]
    H --> DONE["Key Takeaways"]
    style START fill:#4f46e5,stroke:#4338ca,color:#fff
    style DONE fill:#059669,stroke:#047857,color:#fff

When to Use Headless Mode

Headless mode is the default for good reasons:

# Production scraping agent — headless is faster and uses less memory
browser = p.chromium.launch(headless=True)

# CI/CD pipeline — no display available
browser = p.chromium.launch(headless=True)

# Server-side automation — no GUI needed
browser = p.chromium.launch(headless=True)

# Batch processing — efficiency over visibility
browser = p.chromium.launch(headless=True)

Advantages of headless mode:

  • Faster — no rendering overhead for drawing pixels
  • Less memory — no GPU memory for rendering
  • No display required — works on servers, containers, CI/CD
  • More stable — no window management issues

When to Use Headed Mode

Headed mode shines in specific scenarios:

# Debugging a failing automation script
browser = p.chromium.launch(headless=False, slow_mo=1000)

# Sites that detect headless browsers
browser = p.chromium.launch(headless=False)

# User-supervised agent — human watches and can intervene
browser = p.chromium.launch(headless=False)

# Recording a demo or training video
browser = p.chromium.launch(headless=False, slow_mo=300)

Some websites detect headless browsers by checking browser properties, WebGL rendering capabilities, or behavioral patterns. Running headed can bypass these checks.

Using Playwright Inspector for Debugging

Playwright includes a built-in inspector that opens alongside the headed browser:

flowchart TD
    ROOT["Headless vs Headed Playwright: When AI Agent…"] 
    ROOT --> P0["CI/CD Configuration"]
    P0 --> P0C0["GitHub Actions"]
    P0 --> P0C1["GitLab CI"]
    ROOT --> P1["FAQ"]
    P1 --> P1C0["Does headless mode produce different re…"]
    P1 --> P1C1["How do I run headed Playwright on a rem…"]
    P1 --> P1C2["Does slow_mo affect the reliability of …"]
    style ROOT fill:#4f46e5,stroke:#4338ca,color:#fff
    style P0 fill:#e0e7ff,stroke:#6366f1,color:#1e293b
    style P1 fill:#e0e7ff,stroke:#6366f1,color:#1e293b
# Set the environment variable to enable the inspector
PWDEBUG=1 python my_agent_script.py
import os
os.environ["PWDEBUG"] = "1"

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    # Inspector opens automatically with PWDEBUG=1
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()

    # Each action pauses, letting you inspect the page state
    page.goto("https://example.com")
    page.get_by_text("More information").click()

    browser.close()

The inspector lets you step through actions one at a time, inspect selectors, and see what the browser sees at each step.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

Codegen: Generating Scripts from Manual Interaction

Playwright can record your manual interactions and generate automation code:

# Open a browser and record interactions
playwright codegen https://example.com

# Generate Python async code
playwright codegen --target python-async https://example.com

# Record to a file
playwright codegen --target python -o my_script.py https://example.com

# Use a specific viewport
playwright codegen --viewport-size=375,812 https://example.com

This is useful for AI agent developers who need to automate a complex workflow. Record the manual steps first, then refine the generated code into your agent logic.

Running Headed Playwright in Docker

Docker containers do not have a display by default. To run headed Playwright in Docker, you need a virtual display:

FROM mcr.microsoft.com/playwright/python:v1.49.0-noble

# Install virtual display
RUN apt-get update && apt-get install -y xvfb

# Copy your application
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt

# Run with virtual display
CMD ["xvfb-run", "--auto-servernum", "python", "agent.py"]

For headless-only Docker deployments (the common case), the official Playwright image works without any display setup:

FROM mcr.microsoft.com/playwright/python:v1.49.0-noble

COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt

CMD ["python", "agent.py"]

CI/CD Configuration

GitHub Actions

name: Browser Agent Tests
on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install playwright pytest
      - run: playwright install --with-deps chromium
      - run: pytest tests/ --headed=false

GitLab CI

browser_tests:
  image: mcr.microsoft.com/playwright/python:v1.49.0-noble
  script:
    - pip install -r requirements.txt
    - pytest tests/

Building a Mode-Switching Agent

A well-designed agent should support both modes, switching based on environment:

flowchart TD
    CENTER(("Core Concepts"))
    CENTER --> N0["Faster — no rendering overhead for draw…"]
    CENTER --> N1["Less memory — no GPU memory for renderi…"]
    CENTER --> N2["No display required — works on servers,…"]
    CENTER --> N3["More stable — no window management issu…"]
    style CENTER fill:#4f46e5,stroke:#4338ca,color:#fff
import os
from playwright.sync_api import sync_playwright

class BrowserAgent:
    def __init__(self, debug: bool = False):
        self.debug = debug or os.getenv("AGENT_DEBUG") == "1"
        self.slow_mo = 500 if self.debug else 0

    def run(self, url: str, task_fn):
        with sync_playwright() as p:
            browser = p.chromium.launch(
                headless=not self.debug,
                slow_mo=self.slow_mo,
            )
            context = browser.new_context(
                record_video_dir="./debug_videos/" if self.debug else None,
            )
            page = context.new_page()

            # Enable tracing in debug mode
            if self.debug:
                context.tracing.start(
                    screenshots=True,
                    snapshots=True,
                    sources=True,
                )

            try:
                result = task_fn(page, url)
                return result
            except Exception as e:
                if self.debug:
                    page.screenshot(path="error_screenshot.png")
                    print(f"Error screenshot saved. URL: {page.url}")
                raise
            finally:
                if self.debug:
                    context.tracing.stop(path="trace.zip")
                    print("Trace saved to trace.zip")
                    print("View with: playwright show-trace trace.zip")
                context.close()
                browser.close()

# Usage
def my_task(page, url):
    page.goto(url)
    return page.title()

# Production mode
agent = BrowserAgent(debug=False)
title = agent.run("https://example.com", my_task)

# Debug mode
agent = BrowserAgent(debug=True)
title = agent.run("https://example.com", my_task)

Viewing Traces After Headless Runs

Even in headless mode, you can capture traces for post-mortem debugging:

# View the trace file in the Playwright trace viewer
playwright show-trace trace.zip

This opens a web-based viewer where you can step through every action, see screenshots at each step, inspect the DOM, view network requests, and analyze timing — all from a headless run.

FAQ

Does headless mode produce different results than headed mode?

In most cases, no. The browser engine behaves identically in both modes. However, some websites detect headless mode by checking properties like navigator.webdriver, WebGL rendering differences, or missing plugins. If a site works in headed mode but fails in headless, it likely has headless detection. Try removing the webdriver flag with page.add_init_script() or switch to headed mode.

How do I run headed Playwright on a remote server over SSH?

You need X11 forwarding. Connect with ssh -X user@server, then run your script normally. Alternatively, use a VNC server on the remote machine and connect with a VNC client. For most production use cases, capturing traces in headless mode and viewing them locally with playwright show-trace is more practical than streaming the GUI.

Does slow_mo affect the reliability of my tests?

slow_mo adds a fixed delay between every Playwright action, but it does not change the auto-waiting behavior. Your script remains reliable because Playwright still waits for elements to be actionable before interacting with them. slow_mo is purely additive — it will not make flaky tests pass, but it will not make passing tests fail either.


#HeadlessBrowser #PlaywrightDebugging #DockerAutomation #CICD #AIAgents #BrowserTesting #HeadedMode

Share
C

Written by

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

AI Interview Prep

7 MLOps & AI Deployment Interview Questions for 2026

Real MLOps and AI deployment interview questions from Google, Amazon, Meta, and Microsoft in 2026. Covers CI/CD for ML, model monitoring, quantization, continuous batching, serving infrastructure, and evaluation frameworks.

Learn Agentic AI

CI/CD for AI Agents: Automated Testing, Deployment, and Rollback Strategies

Learn how to build CI/CD pipelines for AI agents with prompt regression tests, tool integration tests, canary deployments, and automated rollback on quality degradation.

Learn Agentic AI

Playwright Browser Contexts: Isolated Sessions for Multi-Account AI Agents

Learn how to use Playwright browser contexts to create isolated sessions with separate cookies, storage, and authentication state for multi-account AI agents with proxy rotation.

Learn Agentic AI

Playwright Network Interception: Capturing API Calls and Modifying Requests

Master Playwright's network interception API to capture API responses, log request/response data, mock endpoints, and extract structured data from XHR and fetch calls in your AI agents.

Learn Agentic AI

Building a Vision-Based Web Navigator: GPT-4V Sees and Acts on Web Pages

Build a complete screenshot-action loop where GPT-4V analyzes web pages, decides where to click, and navigates autonomously. Learn coordinate extraction, click targeting, and navigation decision-making.

Learn Agentic AI

Taking Screenshots and Recording Videos with Playwright for AI Analysis

Learn how to capture full-page screenshots, element-level screenshots, and record browser session videos with Playwright, then feed them to GPT-4 Vision for automated visual analysis.