Fix "Not Cross-Origin Isolated": COOP, COEP, and SharedArrayBuffer
A stepwise fix for the not cross-origin isolated error: set COOP and COEP, gate each embedded resource, verify SharedArrayBuffer on production hostnames, and keep a rollback path.
BotBrowser Team
Want the structured docs for Platform?
This article lives in the editorial library. For step-by-step setup, reference material, and ongoing updates, jump into the docs section.
Cross-origin isolation is a browser security state created by a compatible set of response policies and document relationships. It can enable web features such as SharedArrayBuffer in supporting browsers, but it is not a single header and does not make every cross-origin resource usable. A typical top-level deployment combines Cross-Origin-Opener-Policy: same-origin (COOP) with a Cross-Origin-Embedder-Policy (COEP) value such as require-corp or, where supported and appropriate, credentialless. The document can then inspect window.crossOriginIsolated to confirm the browser's resulting state. BotBrowser can load a page in a controlled test context so you can check window.crossOriginIsolated against your own headers; it cannot make a page cross-origin isolated when the site does not send the required headers.
The deployment decision is broader than “add two headers.” COOP changes how a page relates to windows opened across origins; COEP changes which embedded cross-origin resources can load. Together they can affect sign-in popups, payments, analytics, media, fonts, frames, and vendor scripts. Inventory those dependencies, test their real response headers, and stage the policy before enabling code that depends on isolated-only features. Isolation is an application architecture choice with compatibility costs and should be deployed with an explicit fallback and rollback path.
TL;DR
A page becomes cross-origin isolated only through its own response headers: COOP separates browsing contexts, COEP gates every embedded resource, and SharedArrayBuffer requires both. Decide per resource, verify in production, and keep a rollback path before changing headers.
Contents
- What cross-origin isolation changes
- COOP and COEP have different jobs
- Embedded resources and origin boundaries
- A deterministic deployment fixture
- Deploy, monitor, and roll back
- What BotBrowser can validate
- Practical conclusion
What cross-origin isolation changes
The WHATWG HTML specification's cross-origin isolation model describes a browser state, not a network tunnel or a property that a script can set. A page opts into a stricter relationship with other browsing contexts and embedded resources. If the browser accepts the applicable policy and relationship requirements, it exposes the resulting state through crossOriginIsolated. That value is the runtime assertion to record; a server returning one header is not by itself proof that a loaded document is isolated.
The term “cross-origin” refers to a different scheme, host, or port. A first-party subdomain can therefore be cross-origin even when an organization owns both hosts. Origin boundaries are distinct from site boundaries, and deployment details such as a CDN hostname, an asset domain, or a customer-hosted frame can change which policy applies. A resource that works on a local development host may have a different origin and response configuration in production.
Cross-origin isolation is often discussed alongside SharedArrayBuffer, but the API is only one use case. Some applications need the feature for supported libraries or runtime capabilities. The exact availability rules can vary by browser and platform release; a secure context and an isolated document are common prerequisites, not a promise that every environment exposes every feature. Check the specific API support data and test the deployed document. Never infer feature availability from a user-agent string or from the presence of a response header alone.
window.crossOriginIsolated tells application code whether the current global environment is isolated according to the browser. It does not explain which header or embedded resource prevented isolation. A useful diagnostic report therefore pairs that boolean with the final document URL, relevant response headers, browser release, and a controlled resource inventory. Keep the report focused on configuration facts; it does not need user data or unrelated browser attributes.
COOP and COEP have different jobs
COOP controls a document's relationship with top-level browsing contexts, including opener relationships. With Cross-Origin-Opener-Policy: same-origin, a page is placed into a browsing context group that separates it from cross-origin documents in relevant cases. This improves isolation between windows, but it can change expected behavior for flows that rely on window.opener, such as a popup returning a result to its launching page. The MDN COOP reference describes the policy values and their effects. Test popup-based login, payment, and support flows instead of assuming those integrations are unaffected.
COEP controls the loading of cross-origin resources that a document embeds. With Cross-Origin-Embedder-Policy: require-corp, a cross-origin resource generally needs to be fetched through CORS with a successful CORS response, or be served with a compatible Cross-Origin-Resource-Policy (CORP) response. A resource that previously loaded through a no-CORS request can be blocked if it does not opt in. The resource owner or CDN may need to return Access-Control-Allow-Origin for a CORS request or an appropriate Cross-Origin-Resource-Policy value for an eligible no-CORS resource. The correct header depends on the resource type, credentials, and intended sharing boundary.
The credentialless COEP mode can relax the CORP requirement for eligible no-CORS resources by loading them without credentials. It changes request behavior: cookies and other credentials are not sent for those requests. Browser support and detailed behavior should be checked against current browser documentation before choosing it. It is not a generic compatibility switch, and it is unsuitable when a resource needs authenticated access. The MDN cross-origin isolation guide summarizes the policy pairing and the consequences for applications.
These responsibilities are complementary. COOP alone does not impose COEP's embedded-resource checks. COEP alone does not provide the top-level separation required in the common isolated deployment. The page's final runtime state is the outcome of the complete policy and document relationship, not a manual setting. Do not weaken the policy globally to make one vendor script load; identify the resource, determine who controls it, and choose a supported CORS, CORP, proxy, or alternative integration that matches the intended access.
Embedded resources and origin boundaries
Before applying COEP, inventory every resource the page can embed or fetch: scripts, stylesheets, fonts, images, audio, video, workers, nested frames, and resources loaded by third-party code. Classify each as same-origin, cross-origin with CORS, cross-origin with CORP, or an integration that cannot meet the selected policy. Inspect actual network responses in staging. A resource URL alone does not reveal whether its response contains the required header, whether redirects change the origin, or whether a credentialed request has a compatible CORS response.
Use a compatibility table with a named owner and a decision for each dependency:
| Dependency case | Evidence to inspect | Deployment decision |
|---|---|---|
| Same-origin application asset | Final URL and response status | Keep same-origin; verify redirects remain in scope |
| Cross-origin asset intended for public use | CORS mode and Access-Control-Allow-Origin, or suitable CORP response | Configure the resource owner and test the actual response |
| Cross-origin request needs credentials | Credential mode, exact allowed origin, and credential response headers | Use a deliberate CORS contract; do not use credentialless as a substitute |
| Vendor resource cannot opt in | Owner, purpose, and whether the feature is essential | Replace, proxy under an approved design, defer, or retain a non-isolated fallback |
| Popup or cross-origin frame workflow | Opener behavior, frame origin, and policy relationship | Test the complete user journey with the target policy |
A cross-origin iframe is an independent document with its own origin and policy relationship. Do not assume that a top-level page's crossOriginIsolated value automatically describes every child frame or grants the child every capability. Confirm the embedding rules and any required delegation for the exact feature, then check the child's own runtime state in a fixture that records the expected origin. A frame may also require its own compatible response policy. If you do not control the frame, coordinate with its owner before relying on an isolated-only feature inside it.
The policy should follow least privilege. Allow only the origins and resource types the application needs, and keep third-party integrations from silently widening access. A wildcard CORS response may be valid for a public, non-credentialed asset, but it is not a universal solution for authenticated data. CORP values also describe who may embed a response; select one that matches the intended relationship rather than using the broadest value by default. Document who owns every required header, especially when the page, CDN, identity provider, and embedded service are managed by different teams.
A deterministic deployment fixture
The following fixture makes the isolation state visible, asserts an expectation supplied by the test case, and removes its temporary DOM even if an assertion or reporting step fails. Serve it from the same origin and through the same response-header path as the application. In an isolated candidate environment, configure the expected value as true; in a control environment without the complete policy, declare the expected value separately. Do not derive the expectation from the value being tested.
async function checkIsolation(expected) {
const host = document.createElement('section');
const status = document.createElement('output');
status.setAttribute('aria-live', 'polite');
host.append(status);
document.body.append(host);
try {
const isolated = window.crossOriginIsolated === true;
const sharedMemoryAvailable = typeof SharedArrayBuffer === 'function';
const passed = expected ? isolated && sharedMemoryAvailable : isolated === expected;
status.textContent = `${passed ? 'PASS' : 'FAIL'}: isolated=${isolated}; SharedArrayBuffer=${sharedMemoryAvailable}`;
if (!passed) throw new Error(status.textContent);
return { passed, isolated, sharedMemoryAvailable, visibleResult: status.textContent };
} finally {
host.remove();
}
}
// The test configuration declares this expectation for the candidate origin.
const result = await checkIsolation(true);
console.log(result.visibleResult);
The fixture reports two separate facts: the browser's isolation state and whether this environment exposes SharedArrayBuffer. A supported browser case can assert both; a browser outside the application's declared support range may record the API as unavailable and exercise the product fallback. The fallback should be tested as its own expected outcome, not relabeled as an isolation pass. The snippet does not allocate shared memory, start workers, or perform measurements. Its purpose is to verify response configuration and runtime eligibility without adding an unrelated workload.
For a resource compatibility test, load a small owned page that references one representative cross-origin asset from each required category. Give each asset a stable fixture URL and assert a user-visible loaded or failed state. Keep one fixture per policy case so a failed font does not obscure a successful script or frame. Include redirects and credential behavior only where the production dependency uses them. In teardown, remove fixture nodes and close the isolated test context; do not mutate shared production data.
Deploy, monitor, and roll back
Roll out in stages. First inventory cross-origin dependencies and identify resource owners. Next configure a staging origin with COOP and the selected COEP value, then run the fixture and the complete application journey. Verify the headers on the final document response rather than only at a load balancer or source configuration file; redirects, CDN rules, service workers, and host-specific routes can change the delivered response. Confirm crossOriginIsolated in the actual page after navigation and test each essential resource in its production request mode.
Exercise workflows that cross browsing contexts before broad release: popup-based authentication, payment handoff, customer frames, help widgets, and integrations that expect an opener reference. Test the lowest and highest supported browser releases plus a fallback control. Record the final URL, browser build, COOP and COEP values, crossOriginIsolated, failed resources, frame origins, and visible outcome; omit secrets and account data.
Accept the rollout only when crossOriginIsolated is true where required, essential resources load, and the core task still works in fallback mode. If a vendor resource blocks release, retain the fallback or replace the integration; do not weaken policy globally without documenting the change. Assign ownership: the application team owns the isolation requirement, hosting owns COOP/COEP on each canonical host, asset owners own CORS/CORP, and identity or payment providers own popup/frame compatibility. Record URL, status, redirect chain, headers, frame origins, and resource contract links without account or profile data.
For an accurate comparison, stage and production should use the same policy values. A different staging host does not prove that the production host opts in, and a developer proxy does not establish the public endpoint's CORS or credential behavior. Keep production hostnames, final response headers, redirects, and resource outcomes in the acceptance record. Mark optional resources with their visible fallback; do not promote a policy while an essential resource lacks a compatible response. Assign an owner to compare environments and repeat the fixture after a CDN rule, canonical host, browser support range, or vendor contract changes. Record whether the change affected isolation, a resource response, or only the fallback.
Before changing production headers, retain the prior policy and application version. If an essential integration fails, restore both together and rerun the fixture, asserting crossOriginIsolated === false and the expected fallback. Guard isolated-only code behind the runtime check. Keep transport security and unrelated response headers unchanged.
What BotBrowser can validate
BotBrowser supports controlled browser contexts for authorized application QA: teams can use isolated contexts to run an owned fixture against a declared browser build, verify the page's runtime isolation state, and compare user-visible fallback behavior without carrying state from an unrelated journey. The BotBrowser multi-account isolation documentation describes separate browser contexts for independent sessions. BotBrowser cannot make a document cross-origin isolated, supply COOP or COEP headers, change a third-party resource's CORS/CORP response, preserve popup behavior that the policy intentionally separates, or guarantee that SharedArrayBuffer is supported on every platform. The WHATWG HTML cross-origin isolation model and the site owner's deployment configuration remain authoritative. Use BotBrowser to observe a declared browser journey, while the application and infrastructure owners remain responsible for resource contracts, policy decisions, compatibility, and rollback.
For related work, see the browser release validation guide, the secure-context guide, and the browser API compatibility guide. They address release evidence, secure-context eligibility, and API fallback planning; this page focuses on the response-policy and resource changes needed for cross-origin isolation.
Record the release decision with the owner of each policy and resource contract. This makes a later rollback reviewable: the team can identify whether a document header, redirect, CDN response, or embedded dependency changed. Keep the record limited to technical responses and visible outcomes, and repeat the same checks after every policy change.
If an optional dependency fails, document the visible fallback. If it is essential, defer release until its owner confirms a compatible response.
For the deployment side of the same policy, the cross-origin isolation rollback checklist covers the URL scope, resource owners, staging, and rollback trigger.
Practical conclusion
Treat cross-origin isolation as a resource-contract change, not a flag flip: inventory every embedded origin, obtain its CORP/CORS behavior, ship COOP and COEP together with a verified fixture on production hostnames, and keep the prior header set and application path ready for rollback. Re-run the fixture whenever a CDN rule, browser support range, or vendor contract changes, and record the final URL, header values, and frame origins so a later failure is diagnosable without new instrumentation.
Sources
This article is part of the guide: Web Platform Surfaces: A Consistency Review Map
Related Articles
Cross-Origin Isolation Rollback: A Header Change Checklist
PlatformPermissions Policy for Embedded Browser Features
PlatformSame-Origin Policy and Site Isolation Explained
PlatformSecure Contexts: Why Advanced Browser APIs Need HTTPS
PlatformOrigin-Agent-Cluster: Predictable JavaScript Memory Isolation
PlatformCORS Browser Boundaries: Headers, Preflights, Credentials, and Cache
Run the same check in BotBrowser
Load a profile, keep the signals you just read about consistent inside the browser, and confirm the result on your own machine before a rollout.