Cross-Realm Browser Consistency and Privacy
Keep Window, Worker, and iframe observations within clear realm boundaries without treating JavaScript objects as an identity signal.
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.
This standards-focused guide helps teams design predictable Window, Worker, and iframe boundaries. BotBrowser can repeat an authorized realm workflow in a declared controlled context, while the application remains responsible for origin validation, data minimization, and user-visible recovery.
One page can contain several realms
The WHATWG HTML model defines these boundaries, and BotBrowser can repeat an authorized journey in a declared controlled context without turning a local check into a remote privacy guarantee.
A browser document is not the only JavaScript environment involved in a workflow. The top-level Window has its own global object and global object identity. A dedicated Worker has another global scope, and an iframe creates a separate document realm. Each realm has its own intrinsic objects, event loop participation, storage rules, and policy context. A reference such as Array or Object should therefore be interpreted inside the realm that created it.
The WHATWG HTML standard defines these environments as realms. This standards boundary matters because application code often uses “the browser” as if it were one JavaScript heap. It is not. Realm-aware code makes ownership visible and gives a test a stable place to assert behavior. BotBrowser can repeat such an owned test in a declared controlled context, but it cannot collapse the browser's realm model or certify a third-party page's privacy behavior.
This article is about consistency and privacy at those boundaries. It does not claim that every realm must expose identical objects or timing. The useful contract is narrower: an application should know which realm owns a value, exchange data through an explicit boundary, and avoid turning harmless realm differences into a persistent identifier.
What crosses a realm boundary
Same-origin frames can communicate with Window.postMessage, and a worker can communicate with its owner through postMessage. The structured clone algorithm copies many data values rather than sharing the original object. A cloned array created in the receiving realm is not the same object as the sender's array, even when its contents are equal. Transferable objects such as ArrayBuffer can instead move ownership; after transfer, the sender must treat the buffer as detached.
Cross-origin frames remain isolated by the same-origin policy. postMessage is still available, but the receiver must validate event.origin and, where appropriate, a sender identity or nonce. event.source is a WindowProxy reference, not proof that the message is trusted. Never use a message's shape, a realm's constructor identity, or a browser-specific exception as authentication.
Workers do not share the document DOM. A worker can receive data, perform computation, and return a result, but it cannot directly read the page's elements or assume the page's storage and permission state. A service worker has a different lifecycle and scope again; it is not interchangeable with a dedicated worker or an iframe.
Window and iframe ownership
An iframe has a Window object for its document, even though the embedding page also has a Window. The embedding page receives a WindowProxy when it refers to the frame. That proxy remains the handle used by messaging and navigation, while the document behind it can change. A test should therefore avoid treating a WindowProxy reference as a permanent document identity. Navigate the frame, then re-check the origin and protocol state before accepting a reply.
Same-origin access is an application choice, not a requirement for all frames. A same-origin frame can be granted direct DOM access by ordinary JavaScript, which may be convenient but expands the data boundary. A cross-origin frame cannot be inspected in the same way; the intended interface is a narrow message protocol. Keeping the protocol narrow makes later origin changes safer because the parent does not depend on incidental DOM reachability.
Worker lifecycle and shutdown
A worker can be terminated by its owner, and a worker can stop responding when its script fails or the browser suspends work. The message protocol should include a request identifier and a bounded timeout. On timeout, the page can display a user-visible fallback, cancel the operation, and decide whether a fresh worker is appropriate. Do not retry forever: repeated retries can duplicate a side effect or turn a temporary failure into resource pressure.
When a worker returns a result, validate the complete envelope before using the message data. Check the version, request identifier, result type, and any declared status. A message that contains the right field names but an unexpected type is still invalid. Logging the validation category is useful for engineering; retaining the full input may expose sensitive application data and is rarely necessary.
Structured clone is not serialization policy
Structured clone supports many built-in values, but support is not a reason to send every value available in an application. A Map, Set, or Blob may be technically cloneable while still being too large or too sensitive for a worker boundary. Define an application schema first, then choose the smallest representation. Plain records make compatibility and redaction easier than passing a graph of objects whose ownership is difficult to explain.
Cloning also changes identity. If a receiver uses an object as a key in a WeakMap, it cannot use the sender's object reference to retrieve the entry. If identity matters to the application, send a short-lived application key and define its scope. Do not use a browser-generated object identity as a user identifier, and do not assume that equality across realms has the same meaning as equality inside one realm.
Transferable resources
Transferring an ArrayBuffer, MessagePort, or other transferable avoids a copy but changes ownership. The sender must stop reading a transferred buffer and must not silently reuse it in a retry path. A transfer contract should say who closes or releases the resource and what happens when the receiver rejects the message. For a failed transfer, recreate a resource from synthetic or user-approved input rather than attempting to resurrect a detached object.
Use transfer only where its ownership benefit is clear. A small record is usually easier to validate and safer to retain than a large transferable value. If a transfer contains user content, the privacy review should cover its lifetime in both realms, the worker's error path, and the cleanup performed when the page is closed.
Message authentication and origin checks
Origin validation answers which web origin sent a message; it does not prove that the message expresses an authorized business action. Pair origin checks with a schema, an expected source window where appropriate, and an application authorization decision. Use an exact targetOrigin when sending rather than *, except when the recipient is intentionally opaque and the message contains no sensitive data. A nonce can bind a response to a request, but it is not a replacement for account authorization.
Do not accept a message merely because it arrived quickly or because its constructor names match the parent realm. Timing and constructor observations can vary with browser scheduling and implementation details. They are useful for debugging a declared fixture, not for deciding whether a remote sender is a person or a trusted account.
A test plan for owned applications
Start with a page and worker served by origins that the team controls. Use synthetic values and a fixed protocol version. Record the browser release, the declared profile, the frame origin, and the expected message sequence. Keep those labels in the test report so a later failure can distinguish an application change from a browser or host change.
The control path should complete a valid request and render a result. Candidate paths should vary one condition: an invalid version, an unexpected origin, a missing field, a detached transfer, or a worker timeout. Each condition needs an expected visible result and a cleanup action. This gives the team a useful failure fixture without probing a third-party service.
Repeat the fixture in a fresh controlled context when testing isolation. A fresh context can show whether state was accidentally inherited, but it does not prove that a remote server deleted data. Close pages, workers, and temporary servers in a finally block. Keep screenshots or logs bounded and redact values that are not needed to explain the result.
Accessible recovery
Realm failures are user-facing failures when a worker powers validation, search, rendering, or upload preparation. Announce a fallback status through the page's accessible status region, keep keyboard focus predictable, and provide a retry or local alternative when it is safe. An iframe that cannot load should expose a meaningful fallback in the embedding page rather than leaving an empty region. Accessibility checks belong to the application contract, not to a browser identity test.
Privacy review questions
Before shipping a realm protocol, ask what data crosses the boundary, why the receiving realm needs it, and how long each side retains it. Identify whether a frame is same-origin or cross-origin and whether the target origin can change after navigation. Decide whether diagnostics stay local, are aggregated, or are deleted after a support case. Do not use a realm label, constructor name, or feature matrix as a hidden analytics dimension.
The least-data design is usually easier to maintain. Send a field that states the operation and a bounded data record rather than the whole page state. Return a status and a result rather than echoing the original request. If a user cancels, clear queued messages and release transferable resources. Document these decisions so a future feature does not quietly widen the boundary.
Release and rollback
Realm behavior can change when an application updates its worker bundle, embeds a new frame, or changes its cross-origin headers. Keep a small regression fixture with the protocol version and expected visible states. Run it before a release and after a browser update that is in the support matrix. If the result changes, return to the last accepted bundle and isolate one variable before changing the fallback.
Do not interpret a changed constructor identity or feature list as proof of a browser defect. First compare the loaded script, origin, headers, permissions policy, and message sequence. A browser may legitimately expose a capability in one realm and not another. The correct product response may be a documented fallback rather than a claim that the browser is inconsistent.
Operational ownership
Assign owners for the page protocol, worker bundle, embedded frame, and privacy review. The owner of a frame should approve changes to its target origin and permissions. The owner of the worker should own timeout and shutdown behavior. The release record should link to the synthetic fixture and state which branches remain unverified, such as real devices, screen readers, or remote retention.
This separation keeps a realm issue actionable. A schema failure belongs to the protocol owner. A blocked feature belongs to the frame or policy owner. A missing browser capability belongs in compatibility research. A remote service's retention decision belongs to that service and its privacy process. BotBrowser can help repeat the declared local journey across contexts, but it does not transfer those responsibilities.
Consistency means an explicit contract
For a value sent from Window to Worker or iframe, define the schema, ownership, and lifetime. Send plain records, arrays, strings, and numbers that the receiver can validate. Include a version field when a message may outlive one release. Do not send a function, DOM node, or realm-specific prototype and expect it to retain behavior. If a transfer is required, document which side owns the transferred resource after delivery.
The following compact fixture demonstrates the boundary without collecting personal data:
const worker = new Worker('/realm-worker.js', { type: 'module' });
const request = { version: 1, values: [2, 3, 5] };
worker.onmessage = ({ data }) => {
if (data?.version !== 1 || !Array.isArray(data.values)) throw new Error('invalid reply');
console.log({ sum: data.values.reduce((a, b) => a + b, 0), realm: data.realm });
};
worker.postMessage(request);
// realm-worker.js
self.onmessage = ({ data }) => {
if (data?.version !== 1 || !Array.isArray(data.values)) return;
self.postMessage({ version: 1, values: data.values, realm: 'worker' });
};
The realm label is application data, not a browser fingerprint. It helps a test assert the intended route and should not be persisted as a user identity attribute.
Privacy boundaries to preserve
An iframe can observe what its own document and permissions expose. A same-origin iframe may have broader application access, while a cross-origin iframe should receive only the messages and capabilities deliberately delegated to it. Use a narrow postMessage protocol, an exact targetOrigin, and a declared sandbox or Permissions Policy where appropriate. Do not put account records, tokens, or unnecessary browser observations in a message merely because the channel is available.
Workers can reduce DOM exposure for computation, but moving code into a worker does not make inputs private from the page that supplied them or from a service that receives them. A worker can also observe APIs available in its own global scope. Treat data minimization, retention, and consent as application policy rather than as a consequence of choosing a worker.
Realm differences can be measurable: constructor identity, feature availability, language settings, and scheduling observations may differ by context. A single observation is not proof of a browser brand, device, or person. Do not combine realm probes into a covert cross-context identifier. Test only the capabilities needed by the application and discard diagnostic output after the review.
Decision table
| Observation | Owner | Safe action | Do not infer |
|---|---|---|---|
| Message fails schema validation | Receiving realm | Reject and report a synthetic error | Sender identity or malicious intent |
event.origin is unexpected | Receiver policy | Ignore and log a bounded event | That every message from the origin is trusted |
| Value is cloned | Structured clone | Validate contents and use receiver-owned objects | Shared prototype or object identity |
| Transferable is detached | Transfer contract | Stop using the sender's resource | Browser failure or user identity |
| Feature missing in a worker/iframe | Realm capability | Use a documented fallback | A unique device or browser |
BotBrowser capability and limitation
BotBrowser controlled contexts can repeat authorized Window, Worker, and iframe journeys with a declared profile and can compare visible message results across isolated contexts. This is useful for checking an application's own realm protocol, origin validation, and fallback behavior. BotBrowser does not make realms identical, grant cross-origin access, certify message authentication, or guarantee that every browser release exposes the same worker or iframe feature set. It cannot control what a remote site retains, and a local consistency check is not proof of anonymity or production privacy.
Realm testing also benefits from a clear evidence vocabulary. “Cloned” means the receiver obtained a distinct value through the structured clone algorithm. “Transferred” means ownership moved and the sender must stop using the original. “Rejected” means the receiver declined a message after checking its envelope or origin. “Unavailable” means a capability was not exposed in that realm under the declared policy. These labels describe observations; they do not rank a browser, device, or user.
For support, preserve the smallest reproducible record: the protocol version, synthetic request, expected origin, observed status, and cleanup result. A screenshot can show a visible fallback, but it cannot prove what a remote frame retained. A console error can identify a failed branch, but it cannot establish why a browser chose that branch without comparing the page, worker bundle, policy headers, and release. Keeping those distinctions in the runbook prevents a local test from becoming an unsupported privacy promise.
Public sources
Related reading: same-origin policy and cross-surface browser privacy.
For a release review, compare the same synthetic message sequence after changing one declared variable. A useful record contains the route, origin, protocol version, visible status, cleanup result, and the exact branch that was not exercised. This keeps a compatibility observation proportional to the question and prevents a local fixture from becoming an unbounded collection system.
- WHATWG HTML: Web application APIs and realms
- WHATWG HTML: Web messaging
- MDN: Using web workers
- MDN: Window.postMessage
- BotBrowser advanced features
Related Articles
Take BotBrowser from research to production
The guides cover the model first, then move into cross-platform validation, isolated contexts, and scale-ready browser deployment.