How Lightpanda Handles Cookies and Storage via the Chrome DevTools Protocol
Lightpanda implements a minimal but fully functional CDP Storage domain in src/cdp/domains/storage.zig that exposes HTTP cookie operations to remote clients, while the same CookieJar backs the JavaScript document.cookie API and separate in-memory Lookup structures handle localStorage and sessionStorage.
The Lightpanda browser provides automated control through the Chrome DevTools Protocol (CDP), implementing a focused subset of the Storage domain for cookie management. This architecture bridges external automation tools with internal browser state, exposing cookie operations via CDP while maintaining compatibility with standard Web APIs. Understanding how Lightpanda handles CDP cookies and storage requires examining the Zig-based implementation that separates RFC 6265 cookie jars from key-value storage lookups.
CDP Storage Domain: Cookie Management in storage.zig
Lightpanda's CDP Storage domain handles cookie commands through the processMessage function in src/cdp/domains/storage.zig. This synchronous dispatcher routes commands to specific handlers that operate on the BrowserContext retrieved from cmd.browser_context.
The CookieJar and Internal Structures
The core storage mechanism relies on CookieJar, a thin wrapper around std.ArrayList(Cookie) defined in src/browser/webapi/storage/Cookie.zig. The jar maintains a maximum of 1024 entries and provides forRequest formatting for HTTP headers. Individual cookies follow RFC 6265 parsing rules with Lightpanda-specific permissive extensions for Domain, Path, Secure, HttpOnly, SameSite, Max-Age, and Expires attributes.
CDP clients interact with this system using CdpCookie structures that support name, value, url, domain, path, secure, httpOnly, sameSite, expires, and priority fields. Unsupported fields trigger error.NotImplemented responses.
Command Workflow
Storage.clearCookies invokes clearCookies, which calls CookieJar.clearRetainingCapacity() to empty the list while preserving the underlying allocation.
Storage.getCookies triggers getCookies, which first executes Jar.removeExpired(null) to purge stale entries, then constructs a CookieWriter implementing jsonStringify to serialize the remaining cookies for the CDP JSON response.
Storage.setCookies processes arrays through setCookies, converting each CdpCookie via setCdpCookie. This conversion validates supported fields and returns error.NotImplemented for unsupported attributes. The function determines final domains via Cookie.parseDomain, resolves paths via Cookie.parsePath, derives default secure flags from URLs when present, and allocates strings using an ArenaAllocator before final storage via Jar.add.
Web API Storage: localStorage and sessionStorage
Separate from the CDP cookie system, Lightpanda implements the W3C Storage interface through the Lookup struct in src/browser/webapi/storage/storage.zig. This type uses std.StringHashMapUnmanaged([]const u8) to store key-value pairs. A hardcoded 5 MiB quota is enforced by Lookup.setItem on every write operation.
JavaScript Bridge Integration
The Lookup.JsApi constructs the "Storage" class with a prototype chain exposing standard methods: length (getter), getItem(key), setItem(key, value), removeItem(key), clear(), and key(index). Indexed property accessors enable bracket notation syntax equivalent to storage[key].
In src/browser/webapi/Window.zig, the bridge registers storage accessors:
pub fn getLocalStorage(self: *Window) *storage.Lookup { … }
pub fn getSessionStorage(self: *Window) *storage.Lookup { … }
pub const localStorage = bridge.accessor(Window.getLocalStorage, null, .{});
pub const sessionStorage = bridge.accessor(Window.getSessionStorage, null, .{});
These registrations expose window.localStorage and window.sessionStorage to JavaScript contexts.
Persistence and Quota Enforcement
Storage objects remain in memory for the lifetime of the BrowserContext without disk persistence, providing incognito-mode semantics. The Lookup.setItem method calculates total size before insertion and throws QuotaExceeded if the 5 MiB limit would be exceeded.
CDP and Web API Interaction Patterns
Lightpanda maintains strict separation between CDP-accessible storage and JavaScript-only storage. The CDP Storage domain exclusively manipulates HTTP cookies through the CookieJar, while localStorage and sessionStorage remain accessible only via JavaScript execution within the page. The document.cookie API accesses the same CookieJar instance used by CDP commands, ensuring consistency between automation clients and in-page scripts.
Practical CDP Usage
Remote clients like Puppeteer or Playwright interact with Lightpanda's cookie store using standard CDP messages:
{
"id": 1,
"method": "Storage.clearCookies",
"params": { "browserContextId": "BID-123" }
}
{
"id": 2,
"method": "Storage.setCookies",
"params": {
"cookies": [
{
"name": "session",
"value": "abc123",
"domain": "example.com",
"path": "/",
"secure": true,
"httpOnly": true,
"sameSite": "Strict"
}
],
"browserContextId": "BID-123"
}
}
In-Page JavaScript Access
Within the page context, JavaScript interacts with the same underlying storage:
// Web Storage API
window.localStorage.setItem('theme', 'dark');
console.log(window.localStorage.getItem('theme')); // "dark"
// Cookie manipulation via document.cookie
document.cookie = 'foo=bar; Secure; SameSite=Strict';
console.log(document.cookie); // "foo=bar"
Summary
- CDP Storage domain in
src/cdp/domains/storage.zigprovidesclearCookies,getCookies, andsetCookiescommands that manipulate the internalCookieJarviaprocessMessage. CookieJaris defined insrc/browser/webapi/storage/Cookie.zig, enforces a 1024-cookie limit, and implements RFC 6265 parsing with Lightpanda-specific permissive rules.CdpCookietoCookieconversion occurs viasetCdpCookie, handling domain/path parsing throughCookie.parseDomainandCookie.parsePathwith synchronous error responses.- Web Storage APIs use separate
Lookupstructures with a 5 MiB quota, exposed throughWindow.zigaccessors usingbridge.accessorand persisted only in memory. - Architectural separation ensures CDP clients control HTTP cookies while JavaScript retains exclusive access to
localStorageandsessionStorage.
Frequently Asked Questions
How does Lightpanda store cookies internally?
Lightpanda stores cookies in a CookieJar struct defined in src/browser/webapi/storage/Cookie.zig, which wraps std.ArrayList(Cookie) with a maximum capacity of 1024 entries. The jar handles RFC 6265 parsing, expiration checking via removeExpired, and HTTP request formatting through forRequest.
Can CDP clients access localStorage and sessionStorage?
No, Lightpanda's CDP Storage domain implementation only exposes cookie operations. The localStorage and sessionStorage APIs are accessible exclusively through JavaScript execution within the page, using the Lookup struct in src/browser/webapi/storage/storage.zig that is not bridged to CDP commands.
What happens when cookie or storage limits are exceeded?
The CookieJar enforces a hard limit of 1024 cookies, while Lookup.setItem throws a QuotaExceeded error if Web Storage operations would exceed 5 MiB. Both mechanisms operate synchronously and return immediate errors to the calling context, either as CDP error responses or JavaScript exceptions.
How does Lightpanda handle cookie expiration?
Before returning cookies via Storage.getCookies, Lightpanda calls Jar.removeExpired(null) to purge all stale entries. The internal Cookie struct tracks expiration timestamps, and the jar's clearRetainingCapacity method preserves allocations when clearing cookies via Storage.clearCookies.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →