# `Playwriter.Browser.Session`
[🔗](https://github.com/nshkrdotcom/playwriter/blob/v0.3.0/lib/playwriter/browser/session.ex#L1)

Manages a browser session lifecycle.

A session owns:
- A transport connection
- A browser instance
- Multiple browser contexts
- Pages within those contexts

## Example

    {:ok, session} = Session.start_link(mode: :local, headless: true)
    {:ok, page} = Session.new_page(session)
    :ok = Session.goto(session, page, "https://example.com")
    {:ok, html} = Session.content(session, page)
    :ok = Session.close(session)

# `page_info`

```elixir
@type page_info() :: %{
  page_guid: String.t(),
  frame_guid: String.t(),
  context_guid: String.t()
}
```

# `add_cookies`

```elixir
@spec add_cookies(GenServer.server(), String.t(), [map()]) :: :ok | {:error, term()}
```

Add cookies to a context (guid from `new_context/2`). Each cookie is a map
using Playwright's field names (`name`, `value`, and either `url` or
`domain`+`path`; optionally `httpOnly`, `secure`, `sameSite`, `expires`).

This is the fast way past an auth gate: seed a pre-signed session cookie
instead of driving the login UI.

## Examples

    {:ok, ctx} = Session.new_context(session, [])
    :ok = Session.add_cookies(session, ctx, [
      %{name: "_listener_web_key", value: signed, domain: "localhost", path: "/", sameSite: "Lax"}
    ])
    {:ok, page} = Session.new_page(session, context_guid: ctx)   # starts past the gate

# `add_init_script`

```elixir
@spec add_init_script(GenServer.server(), String.t(), String.t(), keyword()) ::
  :ok | {:error, term()}
```

Add an init script to a context (identified by the guid returned from
`new_context/2`). The script runs before any page scripts on every page and
navigation in that context, so it must be added *before* the page is created.

## Examples

    {:ok, ctx} = Session.new_context(session, [])
    :ok = Session.add_init_script(session, ctx, "window.__debug = 1")
    {:ok, page} = Session.new_page(session, context_guid: ctx)

# `cdp_send`

```elixir
@spec cdp_send(GenServer.server(), String.t(), String.t(), map()) ::
  {:ok, term()} | {:error, term()}
```

Send a CDP command over a session opened with `new_cdp_session/2`.

## Examples

    {:ok, cdp} = Session.new_cdp_session(session, page)
    {:ok, _} = Session.cdp_send(session, cdp, "Network.emulateNetworkConditions", %{
      offline: false, latency: 200, downloadThroughput: 100_000, uploadThroughput: 100_000
    })

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `click`

```elixir
@spec click(GenServer.server(), String.t(), String.t(), keyword()) ::
  :ok | {:error, term()}
```

Click an element.

## Options

- `:timeout` - Click timeout in ms (default: 30000)

# `close`

```elixir
@spec close(GenServer.server()) :: :ok
```

Close the entire session.

# `close_page`

```elixir
@spec close_page(GenServer.server(), String.t()) :: :ok | {:error, term()}
```

Close a page.

# `content`

```elixir
@spec content(GenServer.server(), String.t()) :: {:ok, String.t()} | {:error, term()}
```

Get page HTML content.

# `evaluate`

```elixir
@spec evaluate(GenServer.server(), String.t(), String.t(), keyword()) ::
  {:ok, term()} | {:error, term()}
```

Evaluate a JavaScript expression in a page's main frame and return the result.

## Options

- `:is_function` - treat the expression as a function body (default: false)
- `:arg` - argument passed to the function
- `:timeout` - evaluation timeout in ms (default: 30000)

## Examples

    {:ok, true} = Session.evaluate(session, page, "crossOriginIsolated")
    {:ok, 3} = Session.evaluate(session, page, "(a) => a + 1", arg: 2, is_function: true)

# `expose_binding`

```elixir
@spec expose_binding(GenServer.server(), String.t(), String.t(), (list() -&gt; term())) ::
  :ok | {:error, term()}
```

Expose an Elixir callback to the page as a binding (**experimental**,
`:windows`-only). The page can call `window.<name>(...args)` and the callback
is invoked with the argument list; its return value is passed back to the page.

Register the binding on a context (guid from `new_context/2`) before creating
the page. `:local`/`:remote` return `{:error, :not_supported}`.

# `fill`

```elixir
@spec fill(GenServer.server(), String.t(), String.t(), String.t(), keyword()) ::
  :ok | {:error, term()}
```

Fill an input field.

## Options

- `:timeout` - Fill timeout in ms (default: 30000)

# `goto`

```elixir
@spec goto(GenServer.server(), String.t(), String.t(), keyword()) ::
  :ok | {:error, term()}
```

Navigate to a URL.

## Options

- `:timeout` - Navigation timeout in ms (default: 30000)
- `:wait_until` - When to consider navigation complete (:load, :domcontentloaded, :networkidle)

# `new_cdp_session`

```elixir
@spec new_cdp_session(GenServer.server(), String.t()) ::
  {:ok, String.t()} | {:error, term()}
```

Open a Chrome DevTools Protocol session for a page. Returns an opaque CDP
session id to use with `cdp_send/4`.

Only supported by the `:windows` transport; `:local` returns
`{:error, :not_supported}`.

# `new_context`

```elixir
@spec new_context(
  GenServer.server(),
  keyword()
) :: {:ok, String.t()} | {:error, term()}
```

Create a new browser context.

## Options

- `:viewport` - Viewport dimensions `%{width: 1920, height: 1080}`
- `:user_agent` - Custom user agent string
- `:locale` - User locale (e.g., "en-US")
- `:color_scheme` - Color scheme preference (:light, :dark)

# `new_page`

```elixir
@spec new_page(
  GenServer.server(),
  keyword()
) :: {:ok, String.t()} | {:error, term()}
```

Create a new page in the default context.

Returns a page_id that can be used with other Session functions.

# `screenshot`

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

Take a screenshot.

## Options

- `:full_page` - Capture full scrollable page (default: false)
- `:omit_background` - Omit background for transparent screenshots (default: false)

# `start_link`

```elixir
@spec start_link(keyword()) :: {:ok, pid()} | {:error, term()}
```

Start a new browser session.

## 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`)
- `:name` - Optional name for the GenServer

# `storage_state`

```elixir
@spec storage_state(GenServer.server(), String.t()) :: {:ok, map()} | {:error, term()}
```

Return a context's storage state (cookies + localStorage). Capture it after a
UI login and re-seed it with `add_cookies/3` in later runs.

# `wait_for_function`

```elixir
@spec wait_for_function(GenServer.server(), String.t(), String.t(), keyword()) ::
  :ok | {:error, term()}
```

Wait until a JavaScript predicate becomes truthy in a page's main frame.

## Options

- `:is_function` - treat the expression as a function body (default: false)
- `:arg` - argument passed to the function
- `:polling` - a number of ms, or `"raf"` (default: `"raf"`)
- `:timeout` - timeout in ms (default: 30000)

## Examples

    :ok = Session.wait_for_function(session, page, "window.__ready === true", timeout: 60_000)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
