Navigate a headless browser to the exact website origin, then read that page’s localStorage from its browser context. With Playwright, the shortest approach is page.evaluate(() => Object.entries(localStorage)); the dedicated WebStorage API is clearer when you need named storage operations. For reusing a logged-in context, save browser state with storageState() instead. These methods do not bypass browser origin boundaries, and saved authentication state must be treated as a secret.
Read localStorage from the page you navigated to
Web Storage belongs to an origin: the combination of scheme, host, and port. Navigate to the site whose values you need before querying them. A page on https://example.com cannot read storage belonging to a different origin, such as https://app.example.com or http://example.com. This scope follows the HTML Standard’s definition of the local storage area.
In Playwright, evaluate JavaScript in the page to retrieve all key/value pairs as strings:
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
try {
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
const entries = await page.evaluate(() => Object.entries(window.localStorage));
console.log(entries);
} finally {
await browser.close();
}
entries is an array of pairs, for example [['theme', 'dark'], ['locale', 'en']]. Local storage stores string keys and values; if an application keeps JSON in a value, parse that value separately and handle malformed JSON. This reads only the origin of the current page.
#1 Best Overall
Use Playwright’s WebStorage API for explicit operations
Playwright’s WebStorage API exposes localStorage for the current origin through asynchronous, browser-consistent methods. To list items, use page.localStorage.items(); to get a particular key, use getItem():
const allItems = await page.localStorage.items();
const theme = await page.localStorage.getItem('theme');
console.log({ allItems, theme });
The API is documented in Playwright’s WebStorage reference. Check that the installed Playwright version documents this API before using it; if it is unavailable in your project, the page-evaluation method above is a practical alternative.
Choose the method by what you need
- One-off extraction or selected values: use
page.evaluate()or WebStorage methods after navigating. - Reuse a browser context: save cookies and localStorage with
browserContext.storageState(). - Session storage: capture and restore it separately; it is not automatically included in the ordinary storage-state file.
Handle navigation, origin, and access errors
Read storage only after the page has reached the target origin. A redirect may land on a login page, a regional host, or another subdomain, so inspect page.url() before assuming you are looking at the intended store.
await page.goto('https://example.com', { waitUntil: 'domcontentloaded' });
console.log('Current URL:', page.url());
console.log('Origin:', await page.evaluate(() => location.origin));
const entries = await page.evaluate(() => Object.entries(window.localStorage));
Access can fail. The HTML Standard notes that the localStorage getter can throw a SecurityError when the document has an opaque origin or policy prevents storage access. Wrap the read and report the error without dumping potentially sensitive values:
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
const result = await page.evaluate(() => {
try {
return { ok: true, origin: location.origin, entries: Object.entries(localStorage) };
} catch (error) {
return { ok: false, origin: location.origin, error: String(error) };
}
});
if (!result.ok) throw new Error(`Storage read failed at ${result.origin}: ${result.error}`);
Do not treat storage as a transactional database. The standard encourages authors to assume there is no locking mechanism across agent clusters. If multiple pages or workers can update the same keys, a read followed by a write is not guaranteed to be an atomic operation.
Save and reuse browser state with storageState()
When your goal is to open a later browser context with the same authentication state, save a snapshot rather than manually copying each localStorage value. Playwright’s BrowserContext storageState API documents snapshots containing cookies and localStorage, with optional IndexedDB and OPFS data in newer versions.
import { chromium } from 'playwright';
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://example.com');
// Complete an authorized login flow here, if needed.
await context.storageState({ path: 'state.json' });
const nextContext = await browser.newContext({ storageState: 'state.json' });
const nextPage = await nextContext.newPage();
await nextPage.goto('https://example.com');
await nextContext.close();
await context.close();
await browser.close();
Use storageState() when you want to initialize another context from saved browser state; use a direct read when you only need particular values. If the application keeps required login data in IndexedDB, opt into IndexedDB when exporting and confirm support in the Playwright version installed. Playwright documents IndexedDB inclusion as added in v1.51 and OPFS inclusion as added in v1.63. These options are version-dependent; do not assume they exist in an older installation.
The saved-state workflow is not an export of every kind of browser data. In particular, sessionStorage needs a separate procedure. Also verify the state file’s contents and the application’s actual auth design before relying on it: an app may use server-side sessions, localStorage tokens, IndexedDB, or a combination.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Capture and restore sessionStorage separately
Playwright’s authentication guide explains that its normal saved-state approach covers cookies, localStorage, IndexedDB, and passkey authentication, while sessionStorage must be handled separately. Capture the current page’s session storage as JSON:
const savedSessionStorage = await page.evaluate(() =>
JSON.stringify(sessionStorage)
);
Then add an initialization script to the new context so values are restored before the application’s own page scripts run. Scope the values to the intended hostname:
const sessionValues = JSON.parse(savedSessionStorage);
const context = await browser.newContext();
await context.addInitScript(storage => {
if (window.location.hostname === 'example.com') {
for (const [key, value] of Object.entries(storage)) {
window.sessionStorage.setItem(key, value);
}
}
}, sessionValues);
const page = await context.newPage();
await page.goto('https://example.com');
This example matches the hostname exactly. If your site uses multiple approved subdomains, explicitly decide which hosts should receive the values rather than broadly injecting them everywhere. The Playwright authentication guide’s sessionStorage section describes this capture-and-initialize pattern.
Protect extracted values and state files
Local storage may contain access tokens or other account data, and a browser-state file may include cookies and headers usable to impersonate the account that created it. Playwright explicitly warns that its browser state file may contain sensitive cookies and headers. Treat dumps and snapshots as credentials:
Rank #4
- Do not commit state files or raw storage dumps to source control.
- Keep them outside the repository, restrict filesystem and CI access, and delete them when no longer needed.
- Avoid printing token values in build logs, test output, screenshots, or error reports.
- Use a dedicated test account with only the access your automation requires.
- Automate only accounts and pages you are authorized to access.
See Playwright’s authentication guidance for its recommendations about keeping saved authentication state out of repositories.
Common problems and fixes
| Symptom | Likely cause | What to do |
|---|---|---|
| The result is empty | The page is on another origin, the app has not populated storage yet, or the key is not stored in localStorage. | Check page.url() and location.origin; wait for the app’s relevant state or selector, then inspect again. Check whether the app uses sessionStorage, cookies, or IndexedDB instead. |
SecurityError accessing storage |
The document has an opaque origin or browser policy blocks storage access. | Use the actual site URL with a normal scheme and host, and handle the exception. Do not assume every document can access persistent storage. |
| Values appear on one host but not another | Origins differ by scheme, hostname, or port. | Navigate to the exact origin that owns the data. A subdomain or HTTP/HTTPS change is not the same origin. |
| Login is lost in a new context | The snapshot omitted a storage mechanism the app needs, or sessionStorage was expected to be saved automatically. | Check whether auth depends on IndexedDB and enable its inclusion when supported; capture and restore sessionStorage separately if the app uses it. |
| Restored session value is overwritten | The app’s initialization runs before restoration or replaces the value. | Install addInitScript() before navigating so restoration runs before application code; confirm the app’s expected keys and timing. |
| WebStorage methods are unavailable | The installed Playwright version does not expose the documented API. | Check the API reference for the version in your project or use page.evaluate() for the page-origin read. |
Performance, reliability, and cost considerations
For a single page, a direct storage read is a small operation compared with launching a browser and loading the site. The practical costs are usually navigation, authentication, and managing the resulting sensitive data. Reusing a browser process or a saved context can avoid repeating setup in a larger automation workflow, but it does not make storage reads atomic or guarantee that a site will accept stale credentials. The cited Playwright documentation does not establish comparative speed benchmarks for these approaches.
For reliable extraction, wait for the application state that causes the value to be written rather than relying on an arbitrary short delay. Use a selector or app-specific readiness signal where possible, and capture the origin alongside results so an empty read is diagnosable. Avoid concurrent read-modify-write assumptions when other tabs or workers may update the same storage.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server, not a localStorage extraction API: a screenshot does not expose a page’s storage values. It can be useful when the actual task is to capture a clean page image or PDF without managing a browser. One GET request captures a URL; see the ScreenshotNeo service and API documentation.
Best Value
curl -G "https://api.screenshotneo.com/v1/shot"
-d access_key=YOUR_API_KEY
--data-urlencode url=https://example.com
-o shot.webp
Cookie banners, popups, and chat widgets are removed before the shot, and each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for AI agents. The free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000 shots. Sign up free for 1,000 screenshots a month with no card.
Frequently Asked Questions
Does Playwright storageState() save sessionStorage?
No. Capture sessionStorage separately and restore it with an initialization script before navigating, as shown above.
Can localStorage be read from another domain?
No. A page can read storage for its own origin only; navigate to the exact scheme, hostname, and port associated with the data.
Can ScreenshotNeo return a website’s localStorage values?
No. ScreenshotNeo returns screenshots or PDFs; it is not a browser storage extraction API.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




