Firefox Cookies API: Handling Private and Container Tabs

This article provides a quick overview of how the browser.cookies API in the Firefox Web Browser manages cookie isolation using specific Cookie Store IDs. It explains the distinct identifiers assigned to standard windows, Private Browsing modes, and Container tabs, detailing how developers can use these IDs to read, modify, and manage cookies across isolated browsing contexts.

In Firefox, cookies are not stored in a single global database. Instead, they are segregated into different storage areas known as cookie stores. The browser.cookies API uses the CookieStore object to represent these isolated storage contexts. Every cookie store is identified by a unique string called a storeId.

When a web extension interacts with cookies using methods like cookies.get(), cookies.getAll(), cookies.set(), or cookies.remove(), it can specify the storeId property to target a specific browsing context. If the storeId is omitted, the API defaults to the store of the current execution context.

For standard browsing windows and tabs that do not use any special isolation features, Firefox assigns a default cookie store.

  • Store ID: "firefox-default"

All standard tabs share this single store. Any cookie set with the "firefox-default" ID is accessible across all normal windows and persists across browser sessions unless it is a session cookie or explicitly deleted.

Firefox isolates Private Browsing sessions from standard sessions to ensure that tracking data and login states do not leak between the two modes.

  • Store ID: "firefox-private"

All open Private Browsing windows and tabs share the "firefox-private" cookie store. Cookies placed in this store are held exclusively in memory, are never written to the disk, and are permanently purged the moment the user closes the last Private Browsing window.

For an extension to access the "firefox-private" store via the browser.cookies API, the user must explicitly grant the extension permission to run in Private Windows. If the extension does not have this permission, attempts to query or modify "firefox-private" will fail.

Container Tabs (Contextual Identities)

Firefox features "Container Tabs" (managed programmatically via the browser.contextualIdentities API), which allow users to separate their browsing into color-coded contexts like Personal, Work, Banking, and Shopping. Each container has its own completely isolated cookie jar.

  • Store ID: "firefox-container-N" (where N is a unique integer, such as "firefox-container-1", "firefox-container-2", etc.)

When a new container is created, Firefox increments the integer to generate a new storeId. Cookies set in "firefox-container-1" cannot be read by tabs open in "firefox-container-2" or "firefox-default". Unlike Private Browsing cookies, Container cookies are persistent and remain saved even after the browser is closed.

Hardcoding storeId values is generally discouraged, especially for containers, as users can create and delete them dynamically. Developers can dynamically retrieve the correct storeId using the following approaches:

  1. Via the Tabs API: Every tabs.Tab object includes a cookieStoreId property. If you query the active tab using browser.tabs.query(), you can read tab.cookieStoreId and pass that exact string directly into your browser.cookies API calls.
  2. Via the Cookies API: Calling browser.cookies.getAllCookieStores() returns an array of CookieStore objects currently active in the browser. Each object contains the id (the storeId) and an array of tab IDs that are currently using that store.
  3. Via the Contextual Identities API: Calling browser.contextualIdentities.query({}) returns all user containers, each containing a cookieStoreId property corresponding to its "firefox-container-N" value. Requires the "contextualIdentities" permission.

Example: Getting Cookies from a Specific Context

To retrieve cookies from a specific context, pass the storeId into the details object of the API call:

// Retrieve all cookies for a specific container tab
const cookies = await browser.cookies.getAll({
  storeId: "firefox-container-1"
});

// Set a cookie specifically in Private Browsing
await browser.cookies.set({
  url: "https://example.com",
  name: "session_type",
  value: "private",
  storeId: "firefox-private"
});

By leveraging these specific storeId strings, extensions can accurately respect user privacy boundaries and manage data seamlessly across Firefox's multi-context architecture.