To save and load cookies in Playwright, use the browser context's cookies() method to export the current session's cookies, then add_cookies() to restore them into a context later. This lets you skip a login flow or restore browsing state between script runs instead of repeating it every time.
Saving cookies
context.cookies() returns a list of dictionaries, one per cookie, each containing fields like name, value, domain, path, expires, httpOnly, secure, and sameSite. Serialize the list to JSON and write it to a file so you can reuse it later.
import json
with open("cookies.json", "w") as f:
json.dump(context.cookies(), f)
Loading cookies
Read the JSON file back and pass the resulting list directly to context.add_cookies(). The fields returned by cookies() are already in the exact shape add_cookies() expects, so no conversion is needed.
import json
with open("cookies.json", "r") as f:
context.add_cookies(json.load(f))
Call add_cookies() before navigating to the target page if you want that page's first request to include the cookies. Adding cookies after the page has already loaded won't resend the original request with them attached.
Full example
import json
from playwright.sync_api import sync_playwright
# First run: perform login and save cookies
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("https://example.com/login")
# ... fill and submit login form ...
with open("cookies.json", "w") as f:
json.dump(context.cookies(), f)
# Second run: restore cookies into a fresh context
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
context = browser.new_context()
with open("cookies.json", "r") as f:
context.add_cookies(json.load(f))
page = context.new_page()
page.goto("https://example.com/dashboard") # loads as authenticated
The two with sync_playwright() blocks represent separate script runs. Cookies saved in the first run are loaded into a completely new context in the second, which is how you skip a login flow in practice.
Common errors and limitations
- Missing
urlordomain/path:add_cookies()requires each cookie dict to include either aurl, or bothdomainandpath. Cookies returned bycontext.cookies()already include these, but a hand-built cookie dict will raise an error if you leave them out. - Cookies don't apply retroactively: adding cookies after a page has already loaded doesn't resend that page's request. Call
add_cookies()beforepage.goto()if the target page needs to see the cookies on its first load. - Expired cookies won't restore a session:
add_cookies()will load expired cookies without error, but the target site won't treat the session as authenticated. If a site rejects a restored session, re-run the login flow and re-savecookies.json. - Persisting
localStorageandsessionStorage:add_cookies()only restores cookies. If you also need to preserve web storage, usecontext.storage_state(path="state.json")to save everything in one call andbrowser.new_context(storage_state="state.json")to restore it.