Cross-platform browser automation with WSL-to-Windows support.
Playwriter provides a simple, composable API for browser automation, with special support for running in WSL while controlling a visible browser on Windows.
Quick Start
# Fetch HTML from a URL (headless)
{:ok, html} = Playwriter.fetch_html("https://example.com")
# Fetch with visible browser on Windows
{:ok, html} = Playwriter.fetch_html("https://example.com",
mode: :remote,
ws_endpoint: "ws://localhost:3337/"
)
# Take a screenshot
{:ok, png_data} = Playwriter.screenshot("https://example.com")
File.write!("screenshot.png", png_data)
# Full control with session
{:ok, result} = Playwriter.with_browser(headless: true, fn ctx ->
Playwriter.goto(ctx, "https://example.com")
Playwriter.click(ctx, "button.accept")
Playwriter.content(ctx)
end)Transport Modes
:local- Uses playwright_ex with local browser (default):windows- Runs Playwright on Windows via PowerShell (WSL only, no server needed!):remote- Connects to a Playwright server via WebSocket:auto- Auto-detects best transport
WSL-to-Windows Integration
Recommended: Use :windows mode (no server setup required):
Playwriter.fetch_html("https://example.com", mode: :windows)This runs Playwright directly on Windows via PowerShell, bypassing WSL networking.
Requires playwright to be installed in %TEMP%\playwriter-server on Windows.
Alternative: Remote server mode (requires running server):
Start the Playwright server on Windows:
powershell.exe -ExecutionPolicy Bypass -File priv/scripts/start_server.ps1Connect from your Elixir code:
Playwriter.fetch_html("https://example.com", mode: :remote, ws_endpoint: "ws://localhost:3337/" )
Summary
Functions
Click an element.
Get page HTML content.
Fetch HTML content from a URL.
Fill an input field.
Navigate to a URL.
Take a screenshot of a URL.
Take a screenshot of the current page.
Returns the library version.
Execute a function with a browser session.
Types
Functions
Click an element.
Use inside with_browser/2 callback.
Examples
Playwriter.with_browser(fn ctx ->
Playwriter.goto(ctx, "https://example.com")
:ok = Playwriter.click(ctx, "button.submit")
end)
Get page HTML content.
Use inside with_browser/2 callback.
Fetch HTML content from a URL.
This is a convenience wrapper around with_browser/2.
Options
All options from with_browser/2 plus:
:timeout- Navigation timeout in ms (default: 30000):wait_until- When to consider navigation complete
Examples
{:ok, html} = Playwriter.fetch_html("https://example.com")
{:ok, html} = Playwriter.fetch_html("https://example.com",
mode: :remote,
ws_endpoint: "ws://localhost:3337/"
)
Fill an input field.
Use inside with_browser/2 callback.
Examples
Playwriter.with_browser(fn ctx ->
Playwriter.goto(ctx, "https://example.com/login")
:ok = Playwriter.fill(ctx, "input[name=email]", "test@example.com")
:ok = Playwriter.fill(ctx, "input[name=password]", "secret123")
:ok = Playwriter.click(ctx, "button[type=submit]")
end)
Navigate to a URL.
Use inside with_browser/2 callback.
Examples
Playwriter.with_browser(fn ctx ->
:ok = Playwriter.goto(ctx, "https://example.com")
# ...
end)
Take a screenshot of a URL.
Returns the screenshot as PNG binary data.
Options
All options from with_browser/2 plus:
:full_page- Capture entire scrollable page (default: false):omit_background- Transparent background (default: false)
Examples
{:ok, png} = Playwriter.screenshot("https://example.com")
File.write!("screenshot.png", png)
{:ok, png} = Playwriter.screenshot("https://example.com", full_page: true)
Take a screenshot of the current page.
Use inside with_browser/2 callback.
Options
:full_page- Capture entire scrollable page (default: false):omit_background- Transparent background (default: false)
Examples
Playwriter.with_browser(fn ctx ->
Playwriter.goto(ctx, "https://example.com")
{:ok, png} = Playwriter.take_screenshot(ctx)
File.write!("screenshot.png", png)
end)
@spec version() :: String.t()
Returns the library version.
Execute a function with a browser session.
The function receives a context map with :session and :page keys.
Session and page are automatically created and cleaned up.
Options
:mode-:local,:remote, or:auto(default::auto):ws_endpoint- WebSocket URL for remote mode:headless- Run browser in headless mode (default: true):browser_type-:chromium,:firefox, or:webkit(default::chromium)
Examples
{:ok, html} = Playwriter.with_browser(headless: true, fn ctx ->
Playwriter.goto(ctx, "https://example.com")
Playwriter.content(ctx)
end)
# With visible Windows browser
{:ok, html} = Playwriter.with_browser(mode: :remote, fn ctx ->
Playwriter.goto(ctx, "https://example.com")
Playwriter.click(ctx, "#accept-cookies")
Playwriter.content(ctx)
end)