Manuals / Playwright with Python / Ch 28

Part 4 · Advanced TechniquesAdvanced45 min read

20. Authentication & Session Reuse

Playwright with Python · 244 pages source format

storage_state — saving/reusing login sessions # Log in once, save the resulting session context = browser.new_context() page = context.new_page() page.goto("https://app.example.com/login") page.get_by_label("Username").fill("testuser") page.get_by_label("Password").fill("testpass") page.get_by_role("button", name="Log in").click() context.storage_state(path="auth_state.json") # Reuse the saved ses

What you'll learn

  • Global setup for auth (login once, reuse everywhere)

Overview

storage_state — saving/reusing login sessions

context = browser.new_context() page = context.new_page()

# Reuse the saved session — no login steps needed context = browser.new_context(storage_state="auth_state.json") page = context.new_page()

What it does: Saves the current context's cookies and localStorage to a JSON file (or returns it as a dict if no path given).

Types/params:

Pointers: Only captures cookies/localStorage — not sessionStorage or IndexedDB, so if an app's auth relies on those, this approach needs adjustment.

What it does: Creates a new context pre-loaded with previously saved cookies/localStorage, skipping the need to log in via UI again.

Types/params:

state from a prior context.storage_state() call

Pointers: This is a major speed win across a large suite — logging in via UI once and reusing the state across hundreds of tests versus repeating a slow UI login flow every single test.

  • path (string, optional) — file path to write the state to; if omitted, returns the state as a dict instead
  • storage_state (string path or dict, required for this use case) — the saved
Run / study this snippet
page.goto("https://app.example.com/login")
page.get_by_label("Username").fill("testuser")
page.get_by_label("Password").fill("testpass")
page.get_by_role("button", name="Log in").click()
Interactive study board
OverviewDrag stickies · tap for tips
Study mapDrag stickies · tap for tipsKeep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Assert the UIdrag · tap →Retry wiselydrag · tap →Seed datadrag · tap →Close the loopdrag · tap →Keep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Pathwise hackdrag · tap →Page under testdrag · tap →Multi-browserdrag · tap →Automation pathdrag · tap →Tooling nodedrag · tap →
Clear?

Global setup for auth (login once, reuse everywhere)

A common pattern with pytest is a session-scoped fixture that performs the login exactly once per test run and hands out the saved state file path to every test that needs it:

Pointers: Note the two different scopes working together — auth_state is

session-scoped (login happens once for the whole run), while authenticated_page

is function-scoped (a fresh context per test, for isolation) — reusing the saved state, not the context itself, across tests. This combination gets you both speed and isolation simultaneously.

# conftest.py
@pytest.fixture(scope="session")
def auth_state(browser):
    context = browser.new_context()
    page = context.new_page()
    page.goto("https://app.example.com/login")
    page.get_by_label("Username").fill("testuser")
    page.get_by_label("Password").fill("testpass")
    page.get_by_role("button", name="Log in").click()
    state_path = "auth_state.json"
    context.storage_state(path=state_path)
    context.close()
    return state_path

@pytest.fixture
def authenticated_page(browser, auth_state):
    context = browser.new_context(storage_state=auth_state)
    page = context.new_page()
    yield page
    context.close()
Interactive study board
Global setup for auth (login once, reuse everywhere)Drag stickies · tap for tips
Study mapDrag stickies · tap for tipsKeep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Assert the UIdrag · tap →Retry wiselydrag · tap →Seed datadrag · tap →Close the loopdrag · tap →Keep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Pathwise hackdrag · tap →Page under testdrag · tap →Multi-browserdrag · tap →Automation pathdrag · tap →Tooling nodedrag · tap →
Clear?

Checklist