Skip to content
Google Chrome Releases

Chrome third party cookies deprecation (2026): migration guide

Chrome is removing third-party cookie access across the web, and by 2026 you should treat cross-site cookies as unreliable by default. If your product depends on third-party cookies for embeds, SSO, ads, or cross-site analytics, you need a migration plan that maps each use case to a concrete replacement. This is an engineering runbook: what […]

Jack Pauley July 17, 2026 6 min read
chrome third party cookies deprecation infographic

Chrome is removing third-party cookie access across the web, and by 2026 you should treat cross-site cookies as unreliable by default. If your product depends on third-party cookies for embeds, SSO, ads, or cross-site analytics, you need a migration plan that maps each use case to a concrete replacement.

This is an engineering runbook: what breaks, what to use instead (CHIPS, Storage Access API, FedCM), minimal React/Node/TypeScript implementation patterns, and a QA checklist to validate behavior under Chrome’s deprecation modes.

Contents

What actually breaks when third-party cookies go away

Third-party cookies are cookies set in a third-party context (most commonly: an <iframe> or third-party subresource) where the cookie’s “site” differs from the top-level site. When Chrome blocks them, anything that assumes a cookie will be sent in an embedded or cross-site request starts failing in ways that look like “random logouts” or “state not persisting”.

Common breakages (mapped to symptoms)

Use case Typical current design What breaks without 3P cookies User-visible symptom
Embedded SaaS app / widget Iframe points to saas.vendor.com; session cookie scoped to vendor; host site is customer.com Vendor session cookie not sent in iframe requests Iframe shows logged-out state; infinite login loops; 401s in embedded views
SSO in embedded contexts IdP or app relies on cookie-based session in third-party iframe or popup flows Cross-site session continuity breaks; silent SSO breaks Repeated login prompts; “can’t authenticate inside embed”
Cross-site analytics attribution Third-party analytics sets identifier cookie on its own domain via script tag Identifier not available as third-party cookie Attribution gaps; user/session stitching degrades
Ads / retargeting Third-party cookie-based audience targeting and measurement Cookie-based targeting becomes ineffective in Chrome Lower match rates; measurement discrepancies (platform-dependent)
CSRF patterns relying on same cookie in cross-site contexts Backend expects cookie to accompany cross-site requests Cookie missing; request rejected or unauthenticated 403/401 spikes on embedded or redirected flows

Terminology you need for the rest of this guide

  • CHIPS (“Cookies Having Independent Partitioned State”): lets a third party set a cookie that is partitioned per top-level site. It’s still sent in an iframe, but only within the partition for the embedding site. Implemented via the Partitioned cookie attribute. Official docs: Chrome CHIPS.
  • Storage Access API: a user-mediated mechanism where an embedded third party requests access to its first-party storage (cookies/localStorage) in a third-party context. Requires a user gesture and UX considerations. Official docs: Storage Access API.
  • FedCM (“Federated Credential Management”): a browser-mediated identity flow intended to replace third-party cookie dependent federation patterns. Official docs: FedCM and Chrome overview: Chrome FedCM.

If you’re treating this as a runbook, the key move is: stop reasoning in terms of “do I still have cookies?” and start reasoning in terms of which storage scope you need: per-embed partition (CHIPS), explicitly granted access (Storage Access API), or a browser-mediated identity assertion (FedCM).

Decision tree: pick CHIPS vs Storage Access API vs FedCM (by use case)

This is the practical decision matrix. It’s opinionated because the wrong choice creates either bad UX (Storage Access prompts everywhere) or the wrong security model (trying to use CHIPS like a global SSO cookie).

Quick decision table

Use case What you’re trying to preserve Recommended approach Why
Embedded SaaS (iframe) session Logged-in state inside the embed per customer site CHIPS (Partitioned cookie) Partitioned sessions are usually fine: each embedding site gets its own session boundary.
Embedded SaaS needs shared login across many customer sites One login carries across embeds on different top-level sites Storage Access API (selectively) + first-party top-level login You’re asking for cross-site continuity; CHIPS explicitly prevents that. SAA can grant access per site after user interaction.
SSO / identity federation (login with IdP) Federated login without third-party cookie hacks FedCM FedCM moves the flow into browser UI and avoids third-party cookie reliance.
Analytics Measurement and attribution across sites Depends: first-party analytics; Privacy Sandbox APIs (not covered deeply here) CHIPS won’t recreate cross-site identifiers; SAA prompts are a non-starter for analytics UX.
Ads / retargeting Cross-site audience and conversion measurement Privacy Sandbox ads APIs (Topics/Protected Audience/Attribution Reporting) Cookie replacement is not the direction; Chrome is steering toward dedicated APIs.

Runbook-style decision tree

  1. Are you trying to keep a user logged in inside an iframe?
    • If the session can be isolated per embedding site: use CHIPS.
    • If you require the same session across multiple embedding sites: you need a top-level login experience plus Storage Access API (and accept that it’s per-site, user-mediated).
  2. Are you doing “Login with X” (IdP) and relying on third-party cookies for silent login?
    • Use FedCM. Keep OAuth/OIDC on the server; swap the browser piece that used third-party cookies.
  3. Are you primarily tracking users across sites?
    • Don’t try to rebuild third-party cookies. Move measurement to first-party contexts where possible and evaluate Privacy Sandbox measurement APIs where required.

Related reading on ReleaseRun for production-grade migrations and debugging: Chrome third-party cookies deprecation migration guide and (for React/Node ops patterns) React Server Components in production.

Implementation patterns (React + Node + TypeScript)

The examples below are minimal on purpose. They’re meant to be pasted into a spike branch to prove the storage model works, then integrated with your real auth/session layer.

Pattern A: CHIPS for embedded sessions (partitioned cookies)

Use this when: your app is embedded on customer.com via iframe pointing to app.vendor.com, and you’re fine with a separate session per embedding site.

Server: set a partitioned cookie. Requirements (practically): Secure, SameSite=None, and Partitioned. You also still need correct CORS and iframe embedding policies.

// Node + Express + TypeScript
import express from "express";
import cookieParser from "cookie-parser";

const app = express();
app.use(cookieParser());

app.post("/session", (req, res) => {
  // Create your session server-side as usual
  const sessionId = "sess_" + Math.random().toString(36).slice(2);

  // CHIPS partitioned cookie
  // Note: Express 'res.cookie' does not support 'Partitioned' as a first-class option in all versions.
  // Use Set-Cookie header directly to guarantee the attribute is present.
  res.setHeader(
    "Set-Cookie",
    [
      `__Host-embed_session=${sessionId}`,
      "Path=/",
      "Secure",
      "HttpOnly",
      "SameSite=None",
      "Partitioned",
    ].join("; ")
  );

  res.status(204).end();
});

app.get("/me", (req, res) => {
  const sid = req.cookies["__Host-embed_session"];
  if (!sid) return res.status(401).json({ error: "no session" });
  return res.json({ userId: "u_123", sessionId: sid });
});

app.listen(3000);

Client (React): bootstrap the embedded session. In the iframe, call the vendor domain and include credentials.

// React (inside the iframe on app.vendor.com)
import { useEffect, useState } from "react";

type Me = { userId: string; sessionId: string };

export function EmbedApp() {
  const [me, setMe] = useState<Me | null>(null);

  useEffect(() => {
    (async () => {
      // Ensure session exists
      await fetch("/session", { method: "POST", credentials: "include" });

      // Read authenticated state
      const r = await fetch("/me", { credentials: "include" });
      if (!r.ok) throw new Error("Not authenticated");
      setMe(await r.json());
    })().catch((e) => {
      console.error(e);
      setMe(null);
    });
  }, []);

  if (!me) return <div>Signed out</div>;
  return <div>Signed in as {me.userId}</div>;
}

Operational pitfalls:

  • CHIPS partitions by top-level site. If the same user opens your embed on two different customer domains, they’ll have two unrelated sessions. Design support tooling accordingly (“why is user logged out on Customer B?”).
  • Don’t treat CHIPS as a tracking identifier. It’s for embedded state isolation.
  • Cookie prefix __Host- is a good default because it forces safer constraints (host-only, path=/, secure). You still need to confirm your cookie string matches the prefix rules.

Pattern B: Storage Access API for “I need my first-party cookie inside this iframe”

Use this when: you run app.vendor.com and you have a first-party login at vendor.com (or app.vendor.com top-level). You embed the app as a third party, and you want to re-use the existing login cookie (not a partitioned per-embed session).

Reality check: Storage Access API is user-mediated. You need to plan UI for a “Continue” button (user gesture), and you need a fallback when access isn’t granted. Official docs: Storage Access API.

React helper: check access, request access after a user gesture, then retry authenticated calls.

// React + TypeScript
import { useCallback, useState } from "react";

declare global {
  interface Document {
    hasStorageAccess?: () => Promise<boolean>;
    requestStorageAccess?: () => Promise<void>;
  }
}

export function StorageAccessGate({ children }: { children: React.ReactNode }) {
  const [state, setState] = useState<"unknown" | "granted" | "denied">("unknown");

  const check = useCallback(async () => {
    if (!document.hasStorageAccess) {
      // Browser doesn’t support SAA; fall back to top-level redirect login.
      setState("denied");
      return;
    }
    const ok = await document.hasStorageAccess();
    setState(ok ? "granted" : "denied");
  }, []);

  const request = useCallback(async () => {
    if (!document.requestStorageAccess) return setState("denied");
    try {
      await document.requestStorageAccess();
      setState("granted");
    } catch {
      setState("denied");
    }
  }, []);

  // Call check() on mount in your real code

  if (state === "granted") return <>{children}</>;

  return (
    <div>
      <p>This embed needs access to your login session.</p>
      <button onClick={request}>Continue</button>
      <button onClick={check}>Re-check</button>
    </div>
  );
}

Recommended fallback: a top-level navigation to your domain to complete login and/or establish storage access. For example: open https://app.vendor.com/login?return_to=... in a new tab or full-page redirect, then return to the embed.

Pattern C: FedCM for identity (replacing third-party cookie SSO hacks)

Use this when: you’re an RP (relying party) that wants “Sign in with IdP” and your previous flow depended on third-party cookies for silent sign-in or iframe-based session checks.

FedCM integrates with existing OIDC-style setups but changes the browser interaction. Exact integration varies by IdP. Start from the official guidance: FedCM.

Client (React): call navigator.credentials.get with an identity option, then send the returned token to your backend for verification and session creation. You’ll need to feature-detect and provide a fallback to your current redirect-based OIDC flow for non-supporting browsers/environments.

// React + TypeScript (minimal FedCM shape)
import React from "react";

type FedCMResponse = {
  token: string;
};

export function SignInWithIdP() {
  const signIn = async () => {
    if (!("credentials" in navigator)) {
      window.location.href = "/auth/oidc/start";
      return;
    }

    // Types for FedCM aren’t always in TS lib yet depending on your TS version.
    // You can cast to any to unblock a spike.
    const cred = (await (navigator as any).credentials.get({
      identity: {
        providers: [
          {
            configURL: "https://idp.example/.well-known/web-identity",
            clientId: "your-client-id",
          },
        ],
      },
    })) as FedCMResponse | null;

    if (!cred?.token) throw new Error("No FedCM token");

    const r = await fetch("/auth/fedcm/callback", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      credentials: "include",
      body: JSON.stringify({ token: cred.token }),
    });

    if (!r.ok) throw new Error("FedCM exchange failed");
    window.location.reload();
  };

  return <button onClick={signIn}>Sign in</button>;
}

Server (Node): verify the token / assertion with the IdP, then mint your own session cookie (first-party). The token format and verification depend on IdP configuration (often JWT + JWKS verification). Minimal skeleton:

// Node + Express + TypeScript (pseudo-realistic skeleton)
import express from "express";

const app = express();
app.use(express.json());

app.post("/auth/fedcm/callback", async (req, res) => {
  const { token } = req.body as { token: string };
  if (!token) return res.status(400).json({ error: "missing token" });

  // 1) Verify token with IdP (JWT verify, audience, issuer, nonce, etc.)
  // 2) Map to internal user
  // 3) Create first-party session

  res.setHeader("Set-Cookie", `session=...; Path=/; Secure; HttpOnly; SameSite=Lax`);
  res.status(204).end();
});

TS upgrade note: if you’re modernizing auth code at the same time, align on a single TS baseline across frontend and backend. This tends to reduce friction when dealing with evolving web platform types. Reference: TypeScript 6.0 upgrade guide.

What not to do

  • Don’t try to emulate cross-site identity with CHIPS. You’ll end up with per-site sessions and confused users.
  • Don’t add Storage Access prompts to flows that happen on page load. Tie requests to explicit user gestures, or you’ll get inconsistent behavior and angry users.
  • Don’t treat “works in Firefox/Safari” as validation. Chrome is the driver for this change, and it behaves differently in edge cases.

QA/testing checklist: flags, policies, metrics, and failure modes

Your QA goal is not “it still works on my machine.” It’s: (1) reproduce third-party cookie blocking in Chrome reliably, (2) validate your chosen replacement under realistic embed/SSO conditions, and (3) instrument breakage so you see it before support does.

1) Test setup: environments you need

  • Two real sites on different eTLD+1 (e.g., customer.test and vendor.test) to reproduce true cross-site behavior. Localhost aliases often hide problems.
  • HTTPS everywhere. Cookie attributes like Secure and platform APIs behave differently without TLS.
  • An embed harness page on the customer site that iframes the vendor app and logs key events (postMessage, auth state, network failures).

2) Chrome controls: how to force the “no third-party cookies” world

Chrome’s UI/flags/policies evolve. Use these categories in your runbook, and keep exact toggles in a team-owned doc that you update as Chrome moves things around:

  • chrome://settings/cookies: ensure third-party cookies are blocked for the test profile.
  • Chrome flags (chrome://flags): use Privacy Sandbox / third-party cookie related flags to simulate deprecation modes when available in your Chrome channel.
  • Enterprise policies: if you ship to managed devices, validate under the relevant Chrome enterprise policies for third-party cookie phaseout and exceptions.

For official references on the moving pieces, anchor your internal docs to Chrome’s own Privacy Sandbox docs and status updates (start from: developer.chrome.com Privacy Sandbox).

3) Functional test cases (copy/paste into QA tickets)

Area Test Expected Failure signal
CHIPS session Open embed on customer A, log in, refresh iframe route Session persists inside iframe for customer A /me returns 401; Set-Cookie missing Partitioned
CHIPS partitioning Open embed on customer A then customer B Separate sessions (expected) Unexpected shared identity across customers (security bug)
Storage Access API Embedded app loads logged out; user clicks “Continue” Access granted and app sees first-party session; no loops Request rejected; repeated prompts; requires multiple clicks
FedCM sign-in Sign-in on Chrome stable and beta; repeat sign-in after sign-out FedCM UI appears; token exchange succeeds; session cookie set No UI; null token; callback 400/401; stuck partial session
Fallback paths Disable API support (or use a browser without it) Redirect-based OIDC / top-level login works Dead end screen or silent failure
Logout Logout from embed Partitioned cookie cleared (CHIPS) or first-party session cleared User appears logged in due to stale cookie partition

4) Observability: metrics to watch in production

  • 401/403 rate in embedded endpoints (tag by user agent, top-level site, iframe route).
  • Auth loop detector: client-side counter for repeated redirects or repeated “not authenticated” within N seconds.
  • Cookie write success vs read success: log whether Set-Cookie is present and whether subsequent requests include the cookie (careful: don’t log raw cookie values).
  • FedCM token exchange failures: callback error rates, IdP verification failures, and time-to-session.
  • User support tags: add a debug panel or support bundle showing whether the app is running as 1P vs 3P, CHIPS vs SAA, and browser versions.

5) Common failure modes and how to diagnose them fast

  • CHIPS cookie not stored: your Set-Cookie is missing Partitioned, Secure, or SameSite=None. Check DevTools Application → Cookies and the Network response headers.
  • Cookie stored but not sent: request is cross-site but you didn’t use credentials: "include", or CORS is rejecting credentials. Validate Access-Control-Allow-Credentials: true and explicit origin allowlisting.
  • Storage Access API never grants: you’re calling it without a user gesture, or your flow violates browser heuristics. Ensure the request is triggered by a click and your UX explains why.
  • FedCM returns null: provider configuration is wrong (config URL, client id) or the browser blocks the flow due to policy/state. Instrument and keep a redirect-based OIDC fallback.

If you maintain other Chrome-sensitive features, keep a unified “Chrome breakage” playbook so you don’t repeat the same QA mistakes. Example: Chrome geolocation API changes migration playbook.

Monitoring: Chrome timeline shifts and release notes

Chrome’s third-party cookie deprecation program has moved before, and it can move again (policy, regulator feedback, ecosystem readiness). Treat the timeline as a dependency you monitor, not a date you hardcode into project plans.

What to monitor (recurring task)

  • Chrome release notes for changes to cookie behavior, CHIPS, SAA, and FedCM.
  • Privacy Sandbox updates for deprecation rollout status and testing modes.
  • Enterprise policy changes if you have managed customers who will ask for exceptions or controlled rollout.

Practical cadence

  • Weekly: scan Chrome changes on your current stable + beta versions in CI smoke runs.
  • Per release (every ~4 weeks): run the QA checklist against the newest stable and your next supported version.
  • Quarterly: revisit your decision matrix. Teams tend to “ship CHIPS” and forget that identity flows should move to FedCM over time.

Keep this guide alongside your broader migration docs: Chrome third-party cookies deprecation 2026 migration playbook and Chrome third-party cookies deprecation migration guide.

Bottom Line

The only reliable way through the Chrome third party cookies deprecation is to map each feature to the storage/identity model it actually needs. Use CHIPS for embedded sessions that can be isolated per top-level site. Use Storage Access API only when you need first-party session continuity inside an embed and you can afford user-mediated prompts. Use FedCM for federated login flows instead of trying to preserve third-party cookie-based silent SSO.

Then test it like an operator: force third-party cookie blocking, validate fallbacks, and instrument 401 spikes and auth loops so you see regressions in hours, not in customer tickets.

🛠️ Try These Free Tools

📦 Dependency EOL Scanner

Paste your dependency file to check for end-of-life packages.

🗺️ Upgrade Path Planner

Plan your upgrade path with breaking change warnings and step-by-step guidance.

🏗️ Terraform Provider Freshness Check

Paste your Terraform lock file to check provider versions.

See all free tools →

Stay Updated

Get the best releases delivered monthly. No spam, unsubscribe anytime.

By subscribing you agree to our Privacy Policy.