How AI Browser Extensions Store State: chrome.storage, IndexedDB, and Why It Matters for Your Browsing Assistant
A look at the four storage APIs available to a Chrome extension — chrome.storage.local, chrome.storage.sync, IndexedDB, and the session store — when each one is the right choice, and what an AI assistant extension needs to consider when persisting context across tabs and browser restarts.
Key takeaways
- chrome.storage.local and chrome.storage.sync are the primary choices for an MV3 extension — both survive background service worker restarts, unlike in-memory variables.
- chrome.storage.sync is limited to 100 KB total and 8 KB per item; it's designed for user preferences, not conversation history.
- IndexedDB is available to both content scripts and service workers, supports large structured data, but requires async open/read/write calls — appropriate for storing full conversation logs.
- The session store (chrome.storage.session) introduced in MV3 clears on browser restart and is scoped to the extension's service worker lifetime — useful for ephemeral tab context that shouldn't persist.
On this page
When you interact with an AI assistant living inside your browser, the assistant needs to remember things: which tabs you have open, what you asked three messages ago, preferences you’ve set, and conversation history that gives the model context. Getting this right is harder than it sounds, because browser extensions run in a fragmented execution environment where a naive “store it in a variable” approach silently loses everything the moment the service worker goes idle.
The fragmented execution model
A Chrome Manifest V3 extension runs across at least three separate JavaScript contexts:
- The service worker (
background.js) — handles browser events, manages cross-tab logic, runs on demand and terminates when idle (typically after 30 seconds of inactivity) - Content scripts — injected into each tab’s page context, isolated from the page’s own JavaScript but sharing the page’s lifetime
- The popup (
popup.html) — a short-lived UI context that starts fresh every time the popup opens
None of these contexts share memory. A variable set in the service worker is invisible to a content script, and it disappears entirely when the service worker terminates. An AI assistant that stores its state in a service worker variable will lose it after about 30 seconds of inactivity — which is why structured, persistent storage isn’t optional.
chrome.storage.local
chrome.storage.local is the default for most extension data. It persists across browser restarts and service worker terminations, holds up to 10 MB of data by default (users can grant unlimited storage), and is only readable by the extension itself. Reads and writes are asynchronous:
// Write
await chrome.storage.local.set({ conversationHistory: messages });
// Read
const { conversationHistory } = await chrome.storage.local.get("conversationHistory");
For an AI assistant, chrome.storage.local is appropriate for conversation history (up to the size limit), user preferences, and cached summaries of recently visited pages. The 10 MB ceiling is generous for text but would fill quickly if you stored full page HTML or large base64 images.
chrome.storage.sync
chrome.storage.sync mirrors data across the user’s signed-in Chrome profiles. The API surface is identical to chrome.storage.local, but the quotas are strict: 100 KB total storage and 8 KB per key. It’s designed for small user preferences — theme settings, preferred language, model selection — not for conversation history.
The sync behavior is also eventually consistent. If the user makes changes offline, Chrome resolves conflicts when the network comes back, which can overwrite data in ways that aren’t always predictable. Store only idempotent, user-authored preferences in chrome.storage.sync.
IndexedDB
IndexedDB is a full client-side database available to both service workers and content scripts. Unlike chrome.storage, it has no hard size limit beyond the browser’s disk quota (typically 50–80% of free disk space), supports structured queries, and can store binary data like cached audio or images.
For an AI assistant that needs to store extensive conversation logs, per-site context summaries, or a local embedding store for retrieval, IndexedDB is the appropriate layer. The trade-off is API complexity — you must open a database, create object stores, and manage versioned schema migrations:
const db = await openDB("browsy-state", 1, {
upgrade(db) {
db.createObjectStore("conversations", { keyPath: "id" });
},
});
await db.put("conversations", { id: tabId, messages, updatedAt: Date.now() });
Because service workers can terminate at any time, always await database writes before the service worker returns from an event handler. A write that’s still pending when the service worker terminates will be lost.
chrome.storage.session
Introduced in Manifest V3 (Chrome 102+), chrome.storage.session stores data that persists for the current browser session but clears on browser restart. Unlike a service worker variable, session storage survives a service worker restart within the same browser session — the data lives in the browser process, not in the service worker’s heap.
This makes it ideal for ephemeral tab context: which page the user was on when they last opened the assistant, the active conversation ID, or a temporary clipboard of selected text. Browsy uses session storage for tab state that’s useful within a browsing session but doesn’t need to carry over to tomorrow.
Choosing the right layer
| Data type | Right storage |
|---|---|
| User preferences (model, theme, language) | chrome.storage.sync |
| Conversation history (current session) | chrome.storage.session or chrome.storage.local |
| Conversation history (long-term archive) | chrome.storage.local or IndexedDB |
| Per-page content summaries | IndexedDB |
| Active tab state (current page URL, selection) | chrome.storage.session |
| Large binary data (cached embeddings) | IndexedDB |
Why this matters for privacy
Every storage layer described here keeps data on the user’s own device. chrome.storage.sync is the exception — it goes to Google’s sync infrastructure if the user is signed in to Chrome. For an AI assistant that handles sensitive browsing context, defaulting to chrome.storage.local rather than .sync is the right privacy posture unless the user explicitly opts into cross-device sync.
Browsy stores conversation history locally, never sends browsing context to a third-party server without an explicit user action, and gives users a one-click clear-history option that wipes all storage layers. The extension’s source is open for inspection precisely because the storage decisions a browser assistant makes are worth scrutinizing.