sodcalculator

10 Tech How-To

Save and Reuse Browser Sessions in Playwright

Guide 10-38827 · Updated · Step by step

This guide shows you how to save a browser session (cookies, local storage, and authentication state) in Playwright and reuse it in later runs. This saves time by skipping login steps and keeps your tests consistent. You’ll need a basic Playwright setup with tests written in JavaScript or TypeScript.

What You’ll Need

  • A Node.js project with Playwright installed (npm init playwright@latest)
  • At least one test file that performs a login or requires authentication
  • Basic familiarity with Playwright’s test runner or scripting API

Step-by-Step

  1. Create a storage state file
    Playwright can save the browser context’s state (cookies, localStorage, sessionStorage) to a JSON file. Add a test that logs in, then saves the state:
  2. // auth.spec.js
    import { test } from '@playwright/test';
    
    test('save auth state', async ({ page }) => {
      await page.goto('https://example.com/login');
      await page.fill('#username', 'your_username');
      await page.fill('#password', 'your_password');
      await page.click('button[type="submit"]');
      await page.waitForURL('https://example.com/dashboard');
      await page.context().storageState({ path: 'auth.json' });
    });
  3. Use the storage state in other tests
    In your Playwright config (playwright.config.js), set the storageState option for projects that need authentication:
  4. // playwright.config.js
    module.exports = {
      use: {
        storageState: 'auth.json',
      },
      projects: [
        { name: 'authenticated', testMatch: /.*\.spec\.js/ },
      ],
    };
  5. Alternative: use a global setup
    For more control, create a global setup file that logs in once and saves the state, then reference it in the config:
  6. // global-setup.js
    const { chromium } = require('@playwright/test');
    
    module.exports = async () => {
      const browser = await chromium.launch();
      const context = await browser.newContext();
      const page = await context.newPage();
      await page.goto('https://example.com/login');
      // ... perform login ...
      await context.storageState({ path: 'auth.json' });
      await browser.close();
    };
    // playwright.config.js
    module.exports = {
      globalSetup: './global-setup.js',
      use: {
        storageState: 'auth.json',
      },
    };
  7. Reuse the state in a single script
    If you’re not using the test runner, you can load the state directly when creating a context:
  8. const { chromium } = require('playwright');
    
    (async () => {
      const browser = await chromium.launch();
      const context = await browser.newContext({ storageState: 'auth.json' });
      const page = await context.newPage();
      // Now you're authenticated without logging in again
      await page.goto('https://example.com/dashboard');
      await browser.close();
    })();
  9. Handle session expiration
    If your session expires, you’ll need to re-run the login test to refresh the storage state. You can automate this by checking if the auth file exists and is recent, or by running the login test in CI before other tests.

Common Mistakes

  • Forgetting to update the storage state after login changes – If you change your password or the login flow, the old auth.json becomes invalid. Always re-run the login test.
  • Using storageState in the wrong project – If you have multiple projects, make sure the storageState is applied only to the tests that need it, otherwise you might get unexpected behavior.
  • Saving state too early – If you save the state before the login completes (e.g., before redirect), the saved state may not contain the necessary cookies.
  • Sharing auth.json in version control – This file contains sensitive session data. Add it to .gitignore to avoid leaking credentials.

Tips

  • Use a dedicated test for saving state – Keep the login test separate from your main test suite so it runs only when needed.
  • Parameterize the storage state path – Use environment variables to switch between different environments (e.g., staging vs. production).
  • Combine with trace viewer – If a test fails, you can inspect the trace to see the state at the time of failure.
  • Consider using signed-in cookies from a real browser – For debugging, you can manually log in in a browser, copy the cookies, and use them in your tests, but this is less maintainable.

Troubleshooting

  • Tests still ask for login – Check that the storageState file exists and is not empty. Verify the path in the config is correct. Also, ensure the login test ran successfully before the tests that depend on it.
  • Session expires mid-test – This can happen if the test runs longer than the session timeout. Increase the timeout in your config or re-authenticate within the test using API requests if possible.
  • Storage state not loading in headed mode – When running with --headed, the browser may behave differently. Try running headless to see if the issue persists.
  • Cannot find module ‘auth.json’ – Ensure the file is in the same directory as your config, or use a relative path from the config file’s location.
  • Cookies are domain-specific – If your tests run against a different domain than the one used to save the state, the cookies won’t apply. Make sure the base URL matches.

Frequently Asked Questions

Can I save a session without a test runner?

Yes. Use the Playwright library directly, as shown in Step 4. Create a context, log in, save the state, then close the browser.

Does storageState include local storage?

Yes, it includes cookies, localStorage, and sessionStorage. However, IndexedDB is not saved. If your app uses IndexedDB, you’ll need to handle that separately.

How often should I refresh the storage state?

It depends on your session timeout. If your sessions last 24 hours, refresh daily. In CI, it’s common to run the login test once per build.

Can I use storageState with multiple users?

Yes, create separate storage state files (e.g., user1.json, user2.json) and use them in different projects or tests.

What if my login uses two-factor authentication (2FA)?

You can bypass 2FA by saving the state after the 2FA step, but you’ll need to manually complete it once. Alternatively, use a test-specific 2FA bypass if your app supports it.

Is it safe to commit auth.json to the repository?

No. It contains sensitive session data. Add it to .gitignore and generate it during the test run.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →