Compatibility
Published
There is now a population arriving at your pages that did not exist when most runtime protection was designed: agents driving a browser on behalf of a user who is often your paying customer. This site already covers whether protection stops automated collection and what happens to detection code that runs on the machine it is detecting. This article is the third and more practical question: when one of these sessions hits a protected build, does your application still work — and which options decide that.
What an agent does to your page, and what it never does
Two shapes turn up, and they behave differently enough to be worth separating.
The first is in-page: an extension or embedded agent with script running in your document, reading the DOM and the accessibility tree, dispatching events, and typically wrapping platform functions so it can observe what the page is doing. The second is external: a real browser driven through an automation protocol, where nothing is injected into your page but every interaction is synthesised.
Neither of them reads your JavaScript. An agent operates your interface the way a person does, from rendered text and structure, and it has no more need for your source than your users have. That single fact settles the confidentiality half of the question immediately: code transformations neither help nor hinder here, because nothing in the agent's workflow involves comprehending your program.
What is left is compatibility, and there the first shape matters a great deal, because wrapping platform functions is precisely the behaviour one of the runtime options exists to detect.
The collision, stated exactly
The anti monkey patching guard works by taking a set of platform entry points, recording what they are at start-up, and re-checking them periodically. The default watch list is not a secret and it is worth reading in full, because the overlap with instrumentation is the whole story: the function constructor and its string conversion, eval, JSON serialisation and parsing, several array methods, object property definition and descriptor inspection, promise resolution, setTimeout and clearTimeout, fetch, the XML request object, web sockets, event listener registration, the beacon, storage reads and writes, and the web crypto digest.
Now consider what an in-page agent needs to do its job. It observes network activity, so it wraps the request machinery. It needs to know when the page reacts, so it wraps event registration. It waits for asynchronous work, so it touches timers and promise resolution. It inspects state, so it reads storage. The two lists are close to the same list, which is not a coincidence — the guard was aimed at exactly this class of behaviour, in the era when it meant something more obviously hostile.
Beyond identity comparison, the guard also converts each function to its string form and looks for the marker that indicates a native implementation. A wrapper is an ordinary JavaScript function and does not carry it. Verification repeats on a five second heartbeat, so a session that starts clean and acquires an agent mid-way trips within seconds.
The part that surprises people: patching that happened first
The behaviour worth planning around is not the ordinary trip. It is what happens when a function was already replaced before your bundle executed — which is the normal case for an extension, since extensions commonly run at document start, well before your application code.
With the clean realm option enabled, the guard opens a hidden frame and reads pristine copies of the built-ins from that fresh context. It then compares what the current page has against them. If the page's version already fails to look native while the pristine copy does, it records that entry as pre-tampered during set-up.
The consequence is the sharp part. The verification routine treats that recorded flag as an immediate failure, and the flag describes what was true when the list was built rather than what is true now. There is no path back: every subsequent heartbeat evaluates the same stored entry and reaches the same conclusion. So an extension that wrapped fetch before your first line ran does not produce a transient warning that clears when the user disables it — it produces a guard that reports failure from its first check onward, for the life of the page.
Whether that is desirable depends entirely on what you configured the failure action to do, which is why the next section matters more than any of this.
Choose the failure action for the population you will actually catch
The runtime defense wrapper supports several responses when a guard trips: throwing, blanking the page, redirecting to a URL, reloading, invoking a callback of your own, and degrading. Teams tend to pick one while imagining an attacker and then ship it to everyone.
Look honestly at who trips these guards in production. Accessibility overlays and assistive extensions, which patch aggressively by design. Password managers. Translation tools. Corporate security extensions. Session replay and analytics your own marketing team installed. Developer extensions your customer forgot they had. And, increasingly, agents completing a task on behalf of a user who is paying you. Genuine tampering is a real but small share of that traffic.
Blanking the page or reloading it converts every one of those into a broken product with no explanation, and reloading in particular risks a loop for a user whose environment is not going to change. Throwing is nearly as bad in a single-page application, where an exception in the wrong place takes out the view. Degrading, or calling back into your own handler, converts the same event into a reduced feature plus a telemetry signal you can actually study — and studying it is how you find out that ninety percent of your trips are an accessibility extension. If you choose redirecting, supply a destination; leaving it empty falls back to throwing, and the engine warns about it at build time.
The same reasoning applies to the developer tools key option, which carries a cost the name does not advertise. Alongside the keyboard shortcuts it suppresses, it registers a handler that prevents the default context menu across the whole page. That menu is not a mouse-only feature: it is reachable from the dedicated context menu key and from a standard keyboard combination, and it is the route to the browser's own reading, translation, spell-checking and search facilities. Suppressing it removes a keyboard-reachable path for every user, which the accessibility article and the European Accessibility Act page both treat as a real cost rather than a theoretical one.
Frames, and a hostname that is not there
One more interaction catches teams that use the domain lock. The guard reads the hostname of the document it is running in, and it checks for an empty value before it consults your allowlist — an empty hostname fires the failure action immediately.
That is deliberate and usually correct, since it covers a file opened from disk or a page reconstructed in a synthetic context. It also means that any environment which renders your content in a frame with no ordinary origin — a blank frame written by script, a preview surface, a sandboxed container — fails the check before your allowlist is even reached. Agent tooling and preview features do this more often than typical browsing does. The ad tech article covers the same mechanism from the delivery side, and the framing article covers why the same guard does not prevent a hostile embed, which is the direction people usually expect it to work.
A configuration that survives contact with reality
Five decisions, in order.
Decide your policy before your settings. Is agent-driven usage something you want to permit, price, limit or refuse? That is a product question with revenue attached, and answering it first prevents you from implementing an accidental policy through a build flag.
Keep the guard, adjust the list. The watch list is configurable in both directions: entries can be removed by dotted path, and your own can be added. If your analytics vendor wraps the request machinery and your session tooling wraps event registration, exclude those specific paths rather than switching the guard off. Building that list is a useful exercise in its own right, because most teams discover they do not know what patches their pages.
Set a failure action you would be comfortable serving to a customer. Degrade or callback, with telemetry. Reserve the destructive actions for a build where you have measured the trip rate and know what is in it.
Split the build when the settings need to differ. If you genuinely need aggressive integrity checking around one feature, protect that bundle separately with its own configuration rather than imposing it on your whole application. The same advice appears in the bot detection article for the same underlying reason: one set of options rarely fits an entire product.
Put the rule where it can be enforced. Rate limits, entitlement and terms live on your server, where you can see the whole account rather than one page, and where changing your mind does not require a release. A guard running in a browser you do not control is a source of signal, not a place to keep a decision you care about.
Frequently asked questions
Does obfuscation itself stop an AI browser agent from using my app?
No, and the reason is structural rather than a limitation. An agent operates your interface: it reads rendered text, the accessibility tree and the document, then clicks and types. It never needs to read your JavaScript, any more than a person using your product does. Transformations that change how readable your code is therefore have no bearing on whether an agent can complete a task. That is worth internalising before configuring anything, because it means the interesting question is not confidentiality but compatibility.
Which options can actually interfere with an agent-driven session?
The runtime guards, not the code transformations. Three in particular. The anti monkey patching guard, because in-page agents and instrumentation libraries work by wrapping the same platform functions it watches. The developer tools key blocking, because it registers a global handler that suppresses the context menu for everyone. And the domain lock, because agents sometimes render content in frames whose hostname is empty, which the guard treats as a failure before it ever consults your allowlist. The transformations themselves are inert here.
What is on the default watch list?
A specific and public set of platform entry points: the function constructor and its string conversion, eval, JSON parsing and serialisation, several array methods, object property definition and inspection, promise resolution, timers, fetch, the XML request object, web sockets, event listener registration, the beacon, storage reads and writes, and the web crypto digest. Read that list next to what a browser extension does to instrument a page and the overlap is close to total. It also checks each function's own string form for the native code marker and re-verifies on a five second heartbeat.
What happens when a function was already patched before my bundle loaded?
This is the case worth knowing about, because it does not behave like an ordinary trip. When the clean realm option is on, the guard opens a hidden frame to read pristine copies of the built-ins, then compares what the page currently has against them. If a function was replaced before your code ran, it records that as pre-tampered at set-up time. The verification routine treats that flag as an immediate failure, and it is a property of the recorded entry rather than of the current moment, so every subsequent heartbeat reaches the same conclusion. An extension that wraps fetch at document start therefore puts the guard into a failing state from its first check onward.
How much does the developer tools key option affect ordinary users?
More than its name suggests, and the detail is in the context menu rather than the keys. Alongside the keyboard shortcuts it suppresses, the option registers a global handler that prevents the default context menu everywhere on the page. The context menu is not only a mouse feature: it is also produced by the dedicated context menu key and by a common keyboard combination, and it is the route to browser reading, translation, spell checking and search. Suppressing it removes a keyboard-reachable path for everyone, which is an accessibility cost rather than an anti-analysis benefit.
Which failure action should we choose if we run these guards at all?
One that degrades rather than one that destroys, because the population tripping these guards includes people you want. The available actions cover throwing, blanking the page, redirecting, reloading, invoking your own callback, and degrading. Blanking or reloading turns a false positive into a broken product for an assistive extension user or a customer whose agent completed their task. Degrading or calling back turns the same event into a reduced feature and a telemetry signal you can act on. If you pick redirecting, supply a destination, since an empty one falls back to throwing.
Can we allow our own instrumentation without disabling the guard entirely?
Yes, and this is the setting most teams should be using rather than turning the whole guard off. The watch list is adjustable: a comma or newline separated list of dotted API paths is removed from it, and a second list adds paths of your own. So if your analytics vendor legitimately wraps the request machinery and your session tooling wraps event registration, exclude those specific entries and keep the rest of the list working. That is a much better outcome than a binary decision, and it forces a useful inventory of what actually patches your page.
Where does the decision about agent access actually belong?
On your server, in the same place every other authorisation decision belongs. If agent-driven usage is something you want to permit, price or limit, express that as account policy, rate limits and terms, where you can measure it and change it without a deployment. A build setting cannot make that decision, because it runs on the user's machine and sees only a page it cannot fully characterise. The guards are useful telemetry about what is happening in your pages, and they are a poor place to put a rule you care about enforcing.
Related reading