One thing I quickly learned while writing Playwright tests is that logging in before every test gets repetitive. It slows the suite down and adds setup that has nothing to do with what I’m trying to test. That’s where Local Storage becomes useful.
Instead of recreating the same application state every time, I can read, update, and reuse data that’s already stored in the browser. I can keep a user logged in, save preferences, or start a test from a specific state without repeating the same steps.
In this guide, I’ll show you how to access, modify, and verify Local Storage in Playwright. You’ll also learn a few practical ways to use it to write faster and more reliable tests.
What is Local Storage?
Local Storage is a browser feature that lets websites save small amounts of data directly on a user’s device. It stores information as key-value pairs and keeps that data available even after the browser is closed or the computer is restarted.
When I’m writing Playwright tests, I think of Local Storage as a way to control the starting state of my application. Instead of logging in before every test or recreating the same user preferences, I can read or update the stored values and begin testing exactly where I need to. A few characteristics make Local Storage particularly useful:
- The data persists across browser sessions: Unlike session storage, the values remain until they’re explicitly removed by the application or the user.
- It can store more data than cookies: Most browsers allow around 5 MB of storage per origin, making it suitable for user preferences, application settings, and other client-side data.
- The data stays in the browser: Since Local Storage isn’t sent with every HTTP request like cookies, it’s useful for storing information that only the client needs.
- Everything is stored as key-value pairs: Both keys and values are saved as strings, making the API simple to read and update during automation.
Accessing Local Storage in Playwright
I’ve realised that the easiest way to access Local Storage in Playwright is with page.evaluate(). It lets me run JavaScript inside the browser, so I can read or inspect the values stored by the application. Here is how you can do it too:
Read All Local Storage Values
Start by opening the page you want to test. Then use page.evaluate() to loop through every Local Storage entry and return it as a JavaScript object.
await page.goto('https://example.com');
const localStorageData = await page.evaluate(() => {
const data = {};
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
data[key] = localStorage.getItem(key);
}
return data;
});
console.log(localStorageData);This returns every stored key and value, making it easy to inspect the application’s current state or verify stored data in your assertions.
Read a Single Value
If you only need one item, you can retrieve it directly instead of reading everything.
const userRole = await page.evaluate(() =>
localStorage.getItem('userRole')
);
console.log(userRole); // adminThis approach is useful when your test depends on a specific value, such as a user role, theme preference, or authentication token.
Setting Local Storage Values
I’ll be honest, most of the time I update Local Storage just to skip the repetitive setup, not test the API itself.
For example, if every test starts by logging in, selecting a theme, or dismissing an onboarding screen, I can store those values before the page loads and begin testing the feature I’m actually interested in. I’ll help you with these values:
Add or Update Storage Values
You can write to Local Storage with page.evaluate() and localStorage.setItem().
await page.goto('https://example.com');
await page.evaluate(() => {
localStorage.setItem('theme', 'dark');
localStorage.setItem('isLoggedIn', 'true');
});Set Multiple Values at Once
If your application relies on several Local Storage entries, it’s easier to add them together instead of making multiple calls.
await page.evaluate(() => {
const data = {
userToken: 'abc123xyz',
preferences: JSON.stringify({
newsletter: true,
}),
};
for (const [key, value] of Object.entries(data)) {
localStorage.setItem(key, value);
}
});Setting these values directly makes the test shorter and keeps the focus on the feature you’re trying to validate, rather than the setup required to reach it.
Modifying and Removing Data from Local Storage
As your test suite grows, you’ll also need to update existing data or remove it completely to recreate different user scenarios. For making changes to removing data, you use the same page.evaluate() method.
Modify an Exisiting Value
Updating a value works the same way as creating one. If the key already exists, localStorage.setItem() replaces the previous value.
await page.evaluate(() => {
localStorage.setItem('user_token', 'new_token_value');
});Remove a Single Item
If a test only depends on one value being removed, use localStorage.removeItem().
await page.evaluate(() => {
localStorage.removeItem('user_token');
});Clear Everything
Sometimes it’s easier to start with a clean browser state. Instead of deleting keys one by one, you can clear the entire Local Storage for the current origin.
await page.evaluate(() => {
localStorage.clear();
});I usually do this at the beginning of a test when I want to make sure no data from previous runs affects the result. It creates a predictable starting point and helps avoid failures caused by leftover browser state.
Reusing Browser State Across Playwright Tests
If multiple tests need the same logged-in user or application state, I don’t recreate it every time. Instead, I save the browser state once and reuse it across the rest of the suite.
Playwright’s storageState() makes this easy by saving cookies, Local Storage, and IndexedDB together. The next test can load that state and start exactly where the previous one left off.
Save the Current Browser State
After completing actions such as signing in or setting up user preferences, save the current browser state to a file.
The file contains everything needed to recreate the same session later, including Local Storage values and authentication cookies.
await context.storageState({
path: 'localStorageState.json',
});Start a New Test from the Saved State
Instead of repeating the same setup, create a new browser context and load the saved state.
const context = await browser.newContext({
storageState: 'localStorageState.json',
});I usually save and reuse browser state when:
- Most tests require the same authenticated user.
- Setting up the application takes longer than the feature I’m testing.
- I want every test to begin from a consistent state without repeating UI actions.
- Running larger test suites where reducing setup time has a noticeable impact on execution time.
How Can You Use These Local Storage Values?
Now that you have learned all actions with Playwright’s local storage values, you can access, edit or delete, and reuse these values. Now is a good time to understand the best use cases for these values:
- Skipping Repetitive Logins: This is why I use it the most. You can store authentication tokens or session data in Local Storage to bypass login steps, helping you save time and improve efficiency.
- Testing User Preferences: You can use Local Storage to store user-specific settings like theme, language, or layout preferences to validate personalized experiences.
- Simulating Authenticated User Flows: Preserve Local Storage data to test features that are accessible only to your logged-in users.
- Maintaining Application State Across Tests: Mimic real user interactions into your testing suite by reusing Local Storage to carry over states like cart items or form progress between test steps.
- Bypassing Intro or Consent Screens: Save Local Storage after dismissing cookie consent or onboarding modals to skip them in future tests and focus on core functionality.
- Testing Role-Based Access: Store and reuse different Local Storage states for various user roles (like admin or user) to test access control and role-specific features.
How to Build More Reliable Playwright Tests with Local Storage
The way you manage Local Storage can have a noticeable impact on the stability of your test suite. A few good practices will help you reduce flaky tests, shorten execution time, and make failures easier to investigate as your automation grows:
- Start Every Test from a Predictable State: Sharing Local Storage between tests often leads to inconsistent results. Create a fresh browser context or reset Local Storage before each test to ensure every test begins with the same conditions.
- Reuse Browser State Instead of Repeating Setup: If multiple tests require the same logged-in user or application configuration, save the browser state with storageState() and reuse it across the suite.
- Test with Realistic Data: Add your Local Storage with values your application would normally create instead of artificial test data. Tests that mirror real user behaviour are more likely to catch issues before they reach production.
- Verify the Data Your Application Stores: Don’t assume values are written correctly. Check that Local Storage contains the expected keys and values after important user actions.
- Keep Test Data Isolated: Only read or update Local Storage for the application you’re testing. Keeping data isolated to the correct browser context and origin prevents unexpected interactions between different applications or environments.
- Avoid Storing Sensitive Information: Even in test environments, avoid placing passwords, personal information, or other sensitive data in Local Storage. Since browser storage is easily accessible through JavaScript, using temporary or masked test data is a safer approach.
Conclusion
One of the biggest advantages I’ve found with Local Storage is that it lets me spend less time preparing a test and more time validating the feature I actually care about. Instead of repeating the same login flow or user setup, I can start from the exact application state I need and keep my tests focused.
As your Playwright suite grows, that small change has a noticeable impact. Tests become faster, easier to maintain, and less prone to failures caused by repetitive setup. Pairing this with BrowserStack Automate lets you run those same tests across real browsers and devices, so you’re not just saving time locally. You’re building confidence that your application behaves consistently for every user.









