
Um arquivo storageState do Playwright pode parecer completo e ainda assim falhar em restaurar o estado de que o app realmente depende. As cookies podem estar lá, o localStorage pode estar lá, e o JSON pode parecer perfeitamente válido, mas sessionStorage falta por padrão. Se o app guarda parte da sessão ali, carregar o arquivo em um contexto novo não traz esse estado de volta.
Essa distinção importa porque storageState é um snapshot, não um perfil completo de navegador. O Playwright deixa esse snapshot fácil de exportar, carregar, isolar por conta e verificar. Mas quando a tarefa depende de estado de navegador que não cabe limpo no arquivo, como sessionStorage, extensões, um perfil já logado ou uma pessoa completando o MFA, o ego (lite) toma a outra rota: manter o ambiente real de Chromium no lugar em vez de recriá-lo a partir de JSON.
Este guia fica no próprio snapshot: o que storageState contém, como gerá-lo e carregá-lo, como manter contas e ambientes separados, e como provar que o estado restaurado de fato funcionou. Loops de login e reautenticação automática são outro problema. Aqui a pergunta é mais simples: o que o arquivo realmente salvou, e o que deixou de fora?
O que é storageState no Playwright?
storageState do Playwright é o snapshot salvo de cookies e localStorage de um contexto de navegador. Você exporta depois que o contexto já tem o estado que quer e então semeia um contexto posterior para ele começar com esse snapshot em vez de um pote vazio.
A documentação oficial de autenticação do Playwright monta o setup de testes neste arquivo. Isso é um consumidor do snapshot, não a definição do snapshot. Esta página fica no arquivo.
Muros de login no X e no LinkedIn estão em scraping com IA atrás de muros de login.
O roteamento de scrape em JavaScript está em web scraping com JavaScript.
O que o arquivo storageState realmente contém?
O arquivo é JSON com cookies e origins. cookies é um array de objetos cookie. origins é um array de registros de origem, cada um com pares name/value de localStorage. A API storageState escreve essa forma quando você passa um path, e devolve o mesmo objeto quando não passa.
| Armazenamento | No storageState por padrão? | O que isso significa |
|---|---|---|
| cookies | Sim | Cada entrada pode carregar name, value, domain, path, expires, httpOnly, secure e sameSite. |
| localStorage | Sim, sob origins | Indexado por origem. Uma chave salva em https://quotes.toscrape.com não aparece em outra origem. |
| sessionStorage | Não | O JSON não tem chave sessionStorage por padrão. Uma página restaurada lê sessionStorage como null. |
Testamos essa forma de arquivo em 2026-09-18 a partir do OpenCode. O Chromium headed em quotes.toscrape.com exportou storageState com as chaves de primeiro nível cookies e origins. d05-demo estava no localStorage de origins. A string JSON não continha sessionStorage nem d05-session.

O guia de autenticação do Playwright também menciona IndexedDB e passkeys em estado reaproveitado em alguns setups. Não presuma que essas chaves existem porque um post as listou. Abra o arquivo que você gerou e leia as chaves de primeiro nível.
Cookies de sessão sem Expires ou Max-Age são outra armadilha em diretórios de perfil. Esse comportamento em disco está em sessões persistentes de navegador. Em um JSON de storageState, a expiração do cookie é um campo explícito em cada cookie. Zero ou um timestamp passado é como você vê um cookie que não sobrevive ao próximo dia no calendário.
Como gerar storageState e carregá-lo?
Gere a partir de um contexto que já tem o estado que você quer. Carregue em um contexto novo antes de abrir a página que precisa dele. Não exporte de uma origem e espere o localStorage de outra origem aparecer.
import { chromium } from "playwright";
const browser = await chromium.launch();
const setup = await browser.newContext();
const page = await setup.newPage();
await page.goto("https://quotes.toscrape.com/");
await page.evaluate(() => {
localStorage.setItem("d05-demo", "local-only");
sessionStorage.setItem("d05-session", "session-only");
});
await setup.storageState({ path: "playwright/.auth/user.json" });
await setup.close();
const reused = await browser.newContext({
storageState: "playwright/.auth/user.json",
});
const next = await reused.newPage();
await next.goto("https://quotes.toscrape.com/");
const restored = await next.evaluate(() => ({
local: localStorage.getItem("d05-demo"),
session: sessionStorage.getItem("d05-session"),
}));
console.log(restored);
await browser.close();Esse trecho é o mecanismo inteiro. A documentação de autenticação do Playwright envolve isso em um projeto de setup para os testes pularem a UI de login. O encapsulamento é opcional. As duas chamadas não.
Se o app guarda o token de sessão só em sessionStorage, este arquivo não o carrega. Copie sessionStorage com page.evaluate, mantenha um processo vivo ou use um perfil real.
Testamos a restauração na mesma sessão do OpenCode. Um contexto novo carregado daquele arquivo imprimiu local = local-only e session = null.

Como provar que o estado restaurado fez efeito?
Prove a restauração com uma chave que você escreveu, ou com uma URL autenticada que só os cookies salvos conseguem abrir. Não trate 'o formulário de login sumiu' como prova. Um bug de redirecionamento também pode esconder o formulário.
await page.goto("https://quotes.toscrape.com/");
const local = await page.evaluate(() => localStorage.getItem("d05-demo"));
if (local !== "local-only") {
throw new Error("storageState did not restore localStorage");
}Para uma conta real, acesse uma URL que só devolve 200 quando o cookie é válido e então faça assert de um rótulo visível de sessão iniciada. Se você cair em /login, o snapshot está velho. Reautenticação fica em outro lugar. Aqui você só precisa da falha: este JSON não restaurou a sessão.
| Checagem | Passa | Falha |
|---|---|---|
| Chave de localStorage | Lê o valor que você salvou | null depois do carregamento |
| Chave de sessionStorage | null a menos que você mesmo tenha copiado | Presumir que sobreviveu porque localStorage sobreviveu |
| Expiração de cookie | expires está no futuro nos cookies de que você precisa | expires é 0 ou já passou |
Como isolar contas e ambientes?
Um arquivo por conta, por ambiente e por contexto de navegador que você pretende reaproveitar. Misturar cookies de staging e produção em user.json é como você testa o tenant errado.
Os origins no JSON são delimitados por origem. Uma chave de localStorage salva em https://quotes.toscrape.com não aparece em http://quotes.toscrape.com. Esquema, host e porta todos contam.
playwright/.auth/staging-admin.json
playwright/.auth/staging-viewer.json
playwright/.auth/prod-readonly.jsonWorkers em paralelo precisam cada um do próprio arquivo ou do próprio contexto. Compartilhar um JSON entre dois contextos que depois escrevem de volta é uma corrida. Exporte depois do setup, carregue somente leitura durante a execução e grave um arquivo novo só a partir de um job dedicado de refresh.
Como saber que o estado salvo expirou?
O arquivo pode parecer válido enquanto o site já revogou a sessão. Confira expires dos cookies no JSON e depois uma URL ao vivo que exige esse cookie.
Um cookie com expires: -1 ou 0 é um cookie de sessão no snapshot. Pode funcionar na mesma execução e sumir depois, conforme o navegador o trata. Um timestamp no passado já está morto. Um timestamp futuro ainda pode ser revogado no servidor.
A checagem ao vivo é a que importa. Abra uma rota autenticada depois de carregar. Se você receber a página de login, 401 ou uma casca anônima, o snapshot está gasto. Atualize o arquivo. Não codifique nesta página uma máquina de login único.
Como guardar storageState com segurança?
Trate o JSON como uma senha. O próprio guia de autenticação do Playwright diz que ele pode conter cookies e headers com os quais alguém se passa por você. Mantenha-o fora de git, logs, artefatos de CI e contexto do modelo.
# .gitignore
playwright/.auth/A CI pode injetar o arquivo de um cofre de segredos no início do job e apagá-lo no fim. Não imprima. Não anexe a um zip de teste falho. Não cole em um prompt de agente para 'depurar a sessão'.
Quando reaproveitar um perfil real de navegador?
Reaproveite um perfil real de Chromium quando o app precisa de mais do que cookies e localStorage: extensões, sessionStorage, sinais de dispositivo ou uma pessoa passando pelo MFA. Um arquivo JSON não carrega isso.
É aí que entra ego (lite) 0.5.0.32. O agente roda em um Space isolado contra o perfil diário de navegador que já está na máquina. A aba pode ser acompanhada, um prompt pode ser assumido e a tarefa pode ser parada. O changelog dessa versão está datado de 2026-09-12 em o changelog do ego (lite). Não é um exportador de storageState. É o caminho que pula o arquivo quando o arquivo tem a forma errada.
Testamos esse isolamento no ego (lite) a partir do OpenCode. A visão de Spaces manteve a tarefa de citações no próprio Space em execução, com o resto do trabalho em outro Space em vez de reconstruir a sessão a partir de JSON.

Testamos a mesma URL pública dentro de um desses Spaces. O Space 6 ficou em controle do agente em quotes.toscrape.com, com Take over e Stop visíveis. O ambiente do navegador permaneceu no lugar em vez de ser reconstruído a partir de um snapshot JSON.

Se localStorage volta e sessionStorage é null, o arquivo fez o trabalho. Não trate um formulário de login ausente como prova. Em 2026-09-18 o contexto restaurado imprimiu local = local-only e session = null a partir de chaves fictícias, sem formulário de senha.
Quais são os desafios e as limitações?
O arquivo parece completo e ainda assim perde o armazenamento que o app realmente usa. Essa é a falha padrão.
O descompasso de origem é o segundo. Salve em localhost:3000, carregue contra 127.0.0.1:3000, e localStorage fica vazio enquanto os cookies ainda podem se anexar conforme o domínio.
O terceiro é sobrecarregar esta página com coreografia de login. Detectar 401, ir para /login e atualizar o snapshot são trabalhos reais. Não são o trabalho deste arquivo.
Perguntas frequentes
O storageState do Playwright inclui cookies?
Sim. cookies é um array de primeiro nível no JSON. Cada cookie pode incluir name, value, domain, path, expires, httpOnly, secure e sameSite.
O storageState inclui localStorage?
Sim, sob origins. Cada registro de origem guarda pares name/value de localStorage só para aquela origem.
O storageState inclui sessionStorage?
Não por padrão. Uma página pode escrever sessionStorage, exportar storageState e ainda produzir um JSON sem chave sessionStorage. O contexto restaurado lê esse armazenamento vazio. Em 2026-09-18 a execução headed restaurou local = local-only e session = null.
Como gerar um arquivo storageState?
Chame await context.storageState({ path: 'playwright/.auth/user.json' }) depois que o contexto já tiver os cookies e o localStorage que você quer.
Como carregar storageState em um contexto novo?
Passe storageState: 'playwright/.auth/user.json' para browser.newContext. Carregue antes de navegar até a página que precisa do snapshot.
Como saber que o estado restaurado funcionou?
Leia uma chave de localStorage que você definiu, ou abra uma URL que só os cookies salvos conseguem alcançar. A ausência da interface de login não é prova.
Devo fazer commit de storageState no git?
Não. Adicione playwright/.auth/ ao .gitignore. O arquivo pode impersonar a conta que capturou.
Dois testes podem compartilhar um arquivo storageState?
Eles podem carregar o mesmo snapshot em somente leitura. Não deixe workers em paralelo escreverem o mesmo arquivo. Use um arquivo por papel se as contas forem diferentes.
Quando usar um perfil real de navegador?
Quando o app precisa de sessionStorage, extensões ou uma pessoa para o MFA. O ego (lite) roda esse trabalho em um Space contra o seu perfil diário de Chromium.
storageState é o mesmo que um user data directory?
Não. storageState é um snapshot JSON. Um user data directory é o perfil em disco.
Se a próxima tarefa precisa do navegador real já logado em vez de um snapshot JSON, o ego (lite) é gratuito para baixar.
