Skip to main content
SeleniumDecoded

Cookies, Local Storage and Session Storage

Read, add and delete cookies, reuse a login session across tests, inspect localStorage and sessionStorage, and understand the domain and secure-flag rules that make cookie injection fail.

Selenium 3 & 4 Stable Updated 9 Sept 2026 · Verified against Selenium 4.48.0

Logging in through the UI in every test is slow and is the single largest source of wasted minutes in most suites. Cookies and web storage let you log in once, save the session, and inject it into later tests. The same APIs let you assert on consent banners, feature flags and anything else the app persists client-side.

Read, add, delete cookies
Selenium 3 & 4 Stable
import org.openqa.selenium.Cookie;
driver.get("https://app.example.com");
// Read
Set<Cookie> all = driver.manage().getCookies();
Cookie session = driver.manage().getCookieNamed("session_id");
System.out.println(session.getValue() + " expires " + session.getExpiry());
// Add (must be on the cookie's domain already)
Cookie flag = new Cookie.Builder("feature_new_checkout", "true")
.domain("app.example.com")
.path("/")
.isSecure(true)
.isHttpOnly(false)
.sameSite("Lax")
.expiresOn(Date.from(Instant.now().plus(1, ChronoUnit.DAYS)))
.build();
driver.manage().addCookie(flag);
// Delete
driver.manage().deleteCookieNamed("feature_new_checkout");
driver.manage().deleteAllCookies();
driver.get("https://app.example.com")
# Read
all_cookies = driver.get_cookies() # list of dicts
session = driver.get_cookie("session_id") # dict or None
print(session["value"], session.get("expiry"))
# Add (must be on the cookie's domain already)
driver.add_cookie({
"name": "feature_new_checkout",
"value": "true",
"domain": "app.example.com",
"path": "/",
"secure": True,
"httpOnly": False,
"sameSite": "Lax",
"expiry": int(time.time()) + 86400,
})
# Delete
driver.delete_cookie("feature_new_checkout")
driver.delete_all_cookies()
await driver.get('https://app.example.com');
// Read
const all = await driver.manage().getCookies();
const session = await driver.manage().getCookie('session_id');
console.log(session.value, session.expiry);
// Add
await driver.manage().addCookie({
name: 'feature_new_checkout',
value: 'true',
domain: 'app.example.com',
path: '/',
secure: true,
httpOnly: false,
sameSite: 'Lax',
expiry: Math.floor(Date.now() / 1000) + 86400,
});
// Delete
await driver.manage().deleteCookie('feature_new_checkout');
await driver.manage().deleteAllCookies();
driver.Navigate().GoToUrl("https://app.example.com");
// Read
var all = driver.Manage().Cookies.AllCookies;
var session = driver.Manage().Cookies.GetCookieNamed("session_id");
Console.WriteLine($"{session.Value} expires {session.Expiry}");
// Add
var flag = new Cookie("feature_new_checkout", "true", "app.example.com", "/",
DateTime.Now.AddDays(1), secure: true, isHttpOnly: false, sameSite: "Lax");
driver.Manage().Cookies.AddCookie(flag);
// Delete
driver.Manage().Cookies.DeleteCookieNamed("feature_new_checkout");
driver.Manage().Cookies.DeleteAllCookies();

The Rules That Make addCookie Fail

InvalidCookieDomainException and silently ignored cookies both come from the same handful of rules:

  1. You must already be on the cookie’s domain. Navigate to any page on app.example.com first, even a 404. You cannot set a cookie for a domain you have not visited.
  2. secure cookies need HTTPS. Setting a secure cookie while on an http:// page fails.
  3. domain must match or be a parent of the current host. .example.com works from app.example.com; other.com does not.
  4. httpOnly cookies can be set by WebDriver even though JavaScript cannot read them; that is the point of using the driver instead of document.cookie.
  5. sameSite values are Strict, Lax or None; None requires secure.
  6. expiry is seconds since epoch in Python and JavaScript, a Date in Java and C#. Omit it for a session cookie.

Reusing a Login Session

The pattern: log in once in a setup phase, save the cookies to a file, and inject them at the start of every test. Skip the UI login entirely.

Save cookies after login, restore before each test
Selenium 4 Medium
// One-time setup (e.g. @BeforeAll)
public static void loginAndSaveCookies(WebDriver driver, Path file) throws IOException {
driver.get("https://app.example.com/login");
driver.findElement(By.id("email")).sendKeys("qa@example.com");
driver.findElement(By.id("password")).sendKeys("secret");
driver.findElement(By.cssSelector("button[type=submit]")).click();
new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.urlContains("/dashboard"));
// Serialise as JSON (Jackson/Gson) or Java serialisation
String json = new Gson().toJson(driver.manage().getCookies());
Files.writeString(file, json);
}
// Per test (@BeforeEach)
public static void restoreCookies(WebDriver driver, Path file) throws IOException {
driver.get("https://app.example.com/404"); // land on the domain first
Type type = new TypeToken<Set<Cookie>>(){}.getType();
Set<Cookie> cookies = new Gson().fromJson(Files.readString(file), type);
cookies.forEach(driver.manage()::addCookie);
driver.get("https://app.example.com/dashboard"); // now authenticated
}
import json
def login_and_save_cookies(driver, path):
driver.get("https://app.example.com/login")
driver.find_element(By.ID, "email").send_keys("qa@example.com")
driver.find_element(By.ID, "password").send_keys("secret")
driver.find_element(By.CSS_SELECTOR, "button[type=submit]").click()
WebDriverWait(driver, 10).until(EC.url_contains("/dashboard"))
path.write_text(json.dumps(driver.get_cookies()))
def restore_cookies(driver, path):
driver.get("https://app.example.com/404") # land on the domain first
for cookie in json.loads(path.read_text()):
cookie.pop("sameSite", None) if cookie.get("sameSite") not in ("Strict", "Lax", "None") else None
driver.add_cookie(cookie)
driver.get("https://app.example.com/dashboard") # now authenticated
# pytest: session-scoped fixture logs in once, function-scoped fixture restores
@pytest.fixture(scope="session")
def auth_cookies(tmp_path_factory):
path = tmp_path_factory.mktemp("auth") / "cookies.json"
d = webdriver.Chrome()
try:
login_and_save_cookies(d, path)
finally:
d.quit()
return path
@pytest.fixture
def logged_in_driver(auth_cookies):
d = webdriver.Chrome()
restore_cookies(d, auth_cookies)
yield d
d.quit()
const fs = require('fs');
async function loginAndSaveCookies(driver, file) {
await driver.get('https://app.example.com/login');
await driver.findElement(By.id('email')).sendKeys('qa@example.com');
await driver.findElement(By.id('password')).sendKeys('secret');
await driver.findElement(By.css('button[type=submit]')).click();
await driver.wait(until.urlContains('/dashboard'), 10000);
fs.writeFileSync(file, JSON.stringify(await driver.manage().getCookies()));
}
async function restoreCookies(driver, file) {
await driver.get('https://app.example.com/404');
for (const cookie of JSON.parse(fs.readFileSync(file, 'utf8'))) {
await driver.manage().addCookie(cookie);
}
await driver.get('https://app.example.com/dashboard');
}
using System.Text.Json;
public static void LoginAndSaveCookies(IWebDriver driver, string file)
{
driver.Navigate().GoToUrl("https://app.example.com/login");
driver.FindElement(By.Id("email")).SendKeys("qa@example.com");
driver.FindElement(By.Id("password")).SendKeys("secret");
driver.FindElement(By.CssSelector("button[type=submit]")).Click();
new WebDriverWait(driver, TimeSpan.FromSeconds(10)).Until(d => d.Url.Contains("/dashboard"));
var cookies = driver.Manage().Cookies.AllCookies.Select(c => new {
c.Name, c.Value, c.Domain, c.Path, c.Expiry, c.Secure, c.IsHttpOnly, c.SameSite });
File.WriteAllText(file, JsonSerializer.Serialize(cookies));
}
public static void RestoreCookies(IWebDriver driver, string file)
{
driver.Navigate().GoToUrl("https://app.example.com/404");
using var doc = JsonDocument.Parse(File.ReadAllText(file));
foreach (var c in doc.RootElement.EnumerateArray())
{
driver.Manage().Cookies.AddCookie(new Cookie(
c.GetProperty("Name").GetString(), c.GetProperty("Value").GetString(),
c.GetProperty("Domain").GetString(), c.GetProperty("Path").GetString(), null));
}
driver.Navigate().GoToUrl("https://app.example.com/dashboard");
}

Caveats: sessions expire, so regenerate the file when a restored session redirects to login; and if your app binds sessions to a user agent or IP, keep the same browser options. Some teams instead call the login API directly and set the resulting token cookie, which avoids the UI entirely.

Local Storage and Session Storage

WebDriver has no cross-browser storage API (the old WebStorage interface only ever worked in Firefox). Use JavaScript; it is two lines and works everywhere.

localStorage and sessionStorage via JavaScript
Selenium 3 & 4 Stable
JavascriptExecutor js = (JavascriptExecutor) driver;
// Write
js.executeScript("localStorage.setItem(arguments[0], arguments[1]);", "theme", "dark");
js.executeScript("sessionStorage.setItem(arguments[0], arguments[1]);", "wizardStep", "3");
// Read
String theme = (String) js.executeScript("return localStorage.getItem(arguments[0]);", "theme");
// Dump everything (useful in failure diagnostics)
Map<String, String> all = (Map<String, String>) js.executeScript("return Object.assign({}, localStorage);");
// Clear
js.executeScript("localStorage.clear(); sessionStorage.clear();");
# Write
driver.execute_script("localStorage.setItem(arguments[0], arguments[1]);", "theme", "dark")
driver.execute_script("sessionStorage.setItem(arguments[0], arguments[1]);", "wizardStep", "3")
# Read
theme = driver.execute_script("return localStorage.getItem(arguments[0]);", "theme")
# Dump everything
everything = driver.execute_script("return Object.assign({}, localStorage);")
# Clear
driver.execute_script("localStorage.clear(); sessionStorage.clear();")
await driver.executeScript('localStorage.setItem(arguments[0], arguments[1]);', 'theme', 'dark');
await driver.executeScript('sessionStorage.setItem(arguments[0], arguments[1]);', 'wizardStep', '3');
const theme = await driver.executeScript('return localStorage.getItem(arguments[0]);', 'theme');
const everything = await driver.executeScript('return Object.assign({}, localStorage);');
await driver.executeScript('localStorage.clear(); sessionStorage.clear();');
var js = (IJavaScriptExecutor)driver;
js.ExecuteScript("localStorage.setItem(arguments[0], arguments[1]);", "theme", "dark");
js.ExecuteScript("sessionStorage.setItem(arguments[0], arguments[1]);", "wizardStep", "3");
var theme = (string)js.ExecuteScript("return localStorage.getItem(arguments[0]);", "theme");
var everything = (Dictionary<string, object>)js.ExecuteScript("return Object.assign({}, localStorage);");
js.ExecuteScript("localStorage.clear(); sessionStorage.clear();");

Storage is per origin, so navigate to the app first. Values are strings; JSON-encode objects. Setting a value does not notify the running app; reload the page afterwards if the app reads storage only at startup. Apps that keep JWTs in localStorage can be logged in by setting the token and reloading, which is even faster than cookies.

Practical Uses Beyond Login

  • Dismiss consent banners by setting the cookie or storage key the banner checks, instead of clicking through it in every test.
  • Enable feature flags the app reads from a cookie or storage.
  • Assert persistence: change a setting, reload, and verify the stored value and the UI agree.
  • Isolate tests: deleteAllCookies() plus localStorage.clear() between tests gives a clean state without restarting the browser (though a fresh driver per test is still safer).

Summary

  • Navigate to the domain before adding cookies; secure cookies need HTTPS; domains must match.
  • Log in once, save cookies, restore per test. Regenerate on expiry.
  • Web storage has no cross-browser WebDriver API; use executeScript with localStorage and sessionStorage.
  • Cookies and storage are the fastest way to reach a test’s starting state; use them to skip UI that is not under test.

Copy-paste recipes for this topic

Related lessons