Playwriter (Playwriter v0.1.0)

Copy Markdown View Source

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):

  1. Start the Playwright server on Windows:

    powershell.exe -ExecutionPolicy Bypass -File priv/scripts/start_server.ps1
  2. Connect from your Elixir code:

    Playwriter.fetch_html("https://example.com",
      mode: :remote,
      ws_endpoint: "ws://localhost:3337/"
    )

Summary

Functions

Get page HTML content.

Fetch HTML content from a URL.

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

context()

@type context() :: %{session: pid(), page: String.t()}

result()

@type result() :: {:ok, term()} | {:error, term()}

Functions

click(ctx, selector, opts \\ [])

@spec click(context(), String.t(), keyword()) :: :ok | {:error, term()}

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)

content(ctx)

@spec content(context()) :: {:ok, String.t()} | {:error, term()}

Get page HTML content.

Use inside with_browser/2 callback.

fetch_html(url, opts \\ [])

@spec fetch_html(
  String.t(),
  keyword()
) :: {:ok, String.t()} | {:error, term()}

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(ctx, selector, value, opts \\ [])

@spec fill(context(), String.t(), String.t(), keyword()) :: :ok | {:error, term()}

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)

goto(ctx, url, opts \\ [])

@spec goto(context(), String.t(), keyword()) :: :ok | {:error, term()}

Navigate to a URL.

Use inside with_browser/2 callback.

Examples

Playwriter.with_browser(fn ctx ->
  :ok = Playwriter.goto(ctx, "https://example.com")
  # ...
end)

screenshot(url, opts \\ [])

@spec screenshot(
  String.t(),
  keyword()
) :: {:ok, binary()} | {:error, term()}

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_screenshot(ctx, opts \\ [])

@spec take_screenshot(
  context(),
  keyword()
) :: {:ok, binary()} | {:error, term()}

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)

version()

@spec version() :: String.t()

Returns the library version.

with_browser(opts \\ [], fun)

@spec with_browser(
  keyword(),
  (context() -> term())
) :: result()

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)