DEV Community

wayknow
wayknow

Posted on Originally published at wayknow.tech

Building a Privacy-First Cookie Editor: CHIPS, Interceptors & Auto-Cleanup in MV3

CrumbKit is a free, open-source cookie editor for Chrome. We released v1.2 in August 2026 with three features that required non-obvious Manifest V3 implementation work: CHIPS partitioned cookie support, a Set-Cookie response interceptor, and scheduled auto-cleanup rules. Here's how we built each one — and what we learned.

Full disclosure: I built CrumbKit. Everything below is from the actual codebase — no marketing fluff, no hand-waving.

1. CHIPS Partitioned Cookies — The New Third-Party Cookie

Chrome is phasing out third-party cookies in favor of CHIPS (Cookies Having Independent Partitioned State). A partitioned cookie is scoped to a specific top-level site — two different websites can each have their own cookie with the same name and domain, but they're completely isolated from each other.

This is a big deal for cookie editors because it means the traditional dedup key — name + domain + path — is no longer unique. Without handling partitionKey, you'd silently overwrite or lose cookies.

How we implemented it

The change touched four layers:

Cookie normalization: We added partitionKey to the normalized cookie object:

function normalizeCookie(cookie) {
  return {
    name: cookie.name,
    value: cookie.value,
    domain: cookie.domain,
    path: cookie.path,
    // ... other fields
    partitionKey: cookie.partitionKey || null
  };
}
Enter fullscreen mode Exit fullscreen mode

Deduplication: The dedup key now includes the partition key. Two cookies with the same name/domain/path but different top-level sites are treated as distinct:

const key = `${c.name}|${c.domain}|${c.path}|${c.partitionKey || ''}`;
Enter fullscreen mode Exit fullscreen mode

Export formats: All six export formats had to be updated. JSON includes the full partitionKey object. CSV serializes it as a JSON string. Set-Cookie headers add the Partitioned attribute. Puppeteer scripts pass the partitionKey through. The key principle: partition data is never silently dropped.

UI: Partitioned cookies show a blue "P" badge in the cookie list. The edit form displays the top-level site as read-only text with a hint: "(CHIPS — set by server)". Users can't edit the partition key because it's determined by the browser, not the cookie itself.

What we learned

Chrome's chrome.cookies API returns partitionKey on partitioned cookies, but most cookie editor tutorials and existing tools don't handle it. CookieJar was the only competitor we found with full CHIPS support. The lack of awareness around partitioned cookies is a real gap — as Chrome rolls out CHIPS more broadly, tools that don't handle it will silently produce incorrect exports.

2. Set-Cookie Interceptor — Watching the Network

One thing we noticed: developers often want to see what cookies a server is setting via Set-Cookie response headers, but Chrome's DevTools buries this in the Network tab. We wanted a one-click way to see, inspect, and add intercepted cookies.

The MV3 challenge

In Manifest V3, you can't use chrome.webRequest.onHeadersReceived to modify requests. But you can use it to observe them. The key is the extraInfoSpec parameter:

chrome.webRequest.onHeadersReceived.addListener(
  (details) => {
    // details.responseHeaders contains Set-Cookie headers
    for (const header of details.responseHeaders) {
      if (header.name.toLowerCase() === 'set-cookie') {
        // Parse and store the intercepted cookie
      }
    }
  },
  { urls: ['<all_urls>'] },
  ['responseHeaders']
);
Enter fullscreen mode Exit fullscreen mode

The ['responseHeaders'] extraInfoSpec tells Chrome to include response headers in the event. Without it, you only get the request.

Data storage

We store intercepted cookies in chrome.storage.session — a volatile store that's cleared when the browser restarts. This is intentional: intercepted cookies are transient data (they're what the server tried to set, not what's actually in the browser). The store is capped at 50 entries to prevent bloat.

The service worker runs as a persistent-ish background script (MV3 service workers can be terminated), so we use a keep-alive port pattern to maintain the interceptor connection when the popup is open.

What we learned

The chrome.webRequest API is read-only in MV3, which is fine for an interceptor — you're watching, not modifying. But there's a gotcha: service workers can be killed by Chrome at any time. The interceptor needs to re-register its listener when the service worker starts up, not just when the extension is installed. We handle this with a chrome.runtime.onStartup + chrome.runtime.onInstalled double-registration pattern.

3. Scheduled Auto-Cleanup — Chrome Alarms as a Cron Job

The auto-cleanup feature lets users set rules like "delete all advertising cookies every hour" or "delete cookies older than 30 days every Sunday." Rules run in the background via chrome.alarms.

How it works

Each rule has a schedule (in minutes), a target (domain, category, or age), and a list of matching cookies. When the user creates a rule, we call chrome.alarms.create() with the interval. When the alarm fires, the service worker:

  1. Gets all cookies via chrome.cookies.getAll({})
  2. Filters by the rule's target (domain pattern, category, or age threshold)
  3. Deletes matching cookies via chrome.cookies.remove()
  4. Optionally sends a chrome.notifications notification

Classification in the service worker

Here's the tricky part: the popup's cookie classification uses a bundled tracking-domains.json file loaded via chrome.runtime.getURL(). But service workers can't access the DOM, so chrome.runtime.getURL() doesn't work the same way.

Our solution: the service worker uses inline classification — the same regex patterns as the main classification module, but hardcoded into the service worker. This avoids loading the JSON file in the background context. Domain-based matching (checking if a cookie's domain appears in the tracker list) is available when creating rules in the options page, where the DOM is accessible.

What we learned

chrome.alarms is Chrome's built-in cron job. It's reliable, survives service worker restarts, and is exactly the right tool for background tasks. The minimum interval is 1 minute, which is fine for cookie cleanup. One caveat: alarms don't fire while Chrome is closed. If the user has a "daily" rule and doesn't open Chrome for a week, it only fires once when they open the browser. This is acceptable for cookie cleanup — the cookies will still be there waiting to be deleted.

4. Six Export Formats — The Keyword Spam Trap

This isn't a technical challenge, but it's a lesson we learned the hard way. CrumbKit supports six export formats: JSON, Netscape, cURL, CSV, Puppeteer, and Set-Cookie headers.

When we submitted v1.2 to the Chrome Web Store, the listing was rejected for keyword spam. The automated审核 system flagged the enumeration of six format names in two places — even though every format name corresponds to a real feature. The system interpreted the comma-separated list of technical terms as SEO keyword stuffing.

Fix: reduce any format enumeration to three names maximum, use "and more" for the rest, and never repeat the same list in two places within the description. The CWS automated审核 treats repeated lists of technical terms as spam, regardless of whether they're real features.

The Bigger Picture: Why Free Matters

Every cookie editor on the market is either abandoned (EditThisCookie), paid (CookieJar at $4.99/month), or has ads (Cookie Editor). None of them hit all three: free, open source, and actively maintained.

CrumbKit is free because it's an acquisition tool for our product family. We make money from SnapMark and ClearJSON. CrumbKit is how developers discover WayKnow. The cookie editor market has no validated paid demand — EditThisCookie had 3M free users for a decade, Cookie-Editor has 2M free users. Making CrumbKit free maximizes reach.

The entire extension is under 85KB of pure vanilla JavaScript. Zero frameworks, zero build step, zero dependencies. The chrome.cookies API hasn't changed since 2016. This thing will run for years without maintenance.

Try It

CrumbKit is free, MIT open source, and on the Chrome Web Store and Edge Add-ons:

If you're building a Chrome extension and run into MV3 issues — especially with service workers, chrome.webRequest, or chrome.alarms — the CrumbKit codebase is a working reference. MIT licensed, so steal freely.


CrumbKit is part of the WayKnow product family — privacy-first browser tools with zero tracking and no sign-up required.

Top comments (0)