Safe External URL Handling for Browser Profiles
Keep external URL handling aligned with the selected platform profile while preserving standard web navigation.
Want the structured docs for Fingerprint?
This article lives in the editorial library. For step-by-step setup, reference material, and ongoing updates, jump into the docs section.
Why external URLs need a platform policy
Operating systems allow applications to register custom URL schemes, also known as protocol handlers. When an application like Slack, VS Code, Zoom, or Steam is installed, it registers a protocol (such as slack://, vscode://, zoommtg://, or steam://) that enables other applications and websites to launch it directly through a URL. This system powers deep linking, allowing a website to open a specific app view, join a meeting, or launch a game through a simple link click.
However, the mechanism that makes protocol handlers useful also makes them a fingerprinting surface. Websites can attempt to navigate to custom protocol URLs and observe the browser's response. The behavior differs depending on whether the protocol's associated application is installed: the browser may show a prompt to open the app, redirect silently, display an error, or simply do nothing. By testing a list of known protocol schemes, a website can build a profile of which applications are installed on the visitor's device, creating a highly distinctive fingerprint.
Privacy Impact
Protocol-based application detection is one of the most privacy-invasive fingerprinting techniques because it reveals information about the user's software environment rather than their hardware. While hardware fingerprints identify the device, application fingerprints identify the person and their activities.
The privacy implications are significant:
- Software inventory: By testing common protocol handlers (Spotify, Discord, Telegram, WhatsApp, Steam, Epic Games, Zoom, Teams, VS Code, Sublime Text, and dozens more), a website can determine which applications are installed.
- Behavioral profiling: Installed applications reveal interests, profession, and behavior patterns. A developer with
vscode://,iterm2://, anddocker://presents a different profile from a gamer withsteam://,epicgames://, anddiscord://. - Device uniqueness: The specific combination of installed applications is highly unique. Even among devices with identical hardware, the installed software set varies dramatically between users.
- Cross-browser tracking: Protocol handlers are registered at the OS level, not the browser level. This means the same application fingerprint persists across all browsers on the device, enabling cross-browser tracking.
A landmark 2021 study by FingerprintJS demonstrated that protocol-based fingerprinting could test 32 popular applications in seconds, producing a fingerprint that uniquely identified 95% of test subjects. The technique worked across Chrome, Firefox, Edge, and other browsers. The research prompted browser vendors to begin implementing mitigations, but the fundamental vulnerability persists in many scenarios.
The technique is particularly concerning because it requires no permissions and can be performed silently. There is no notification to the user that their installed applications are being probed.
How external URL handling affects privacy
How Protocol Detection Works
Protocol detection exploits the browser's behavior when navigating to a URL with an unknown or registered custom scheme. Several techniques have been developed:
iframe navigation method: A website creates a hidden iframe and sets its src to a custom protocol URL (e.g., slack://open). If Slack is installed, the browser attempts to handle the navigation. If not, the iframe receives an error. The timing and behavior of this response differ based on whether the handler exists.
Popup window method: Opening a window.open() to a custom protocol URL produces different behavior depending on handler registration. On some browsers, the popup is consumed by the application handler. On others, it remains as a blank window.
Focus/blur detection: When a protocol handler launches an external application, the browser window loses focus. By monitoring blur and focus events, a website can detect whether an application was successfully launched.
Timing-based detection: The time taken for the browser to process a protocol navigation varies depending on whether a handler exists. Installed handlers produce a faster or slower response (depending on the browser) than unregistered protocols, and this timing difference is measurable.
Browser-Specific Behavior
Different browsers handle unknown protocols differently:
- Chrome: Shows a dialog asking if the user wants to open the application (for known handlers) or does nothing / shows a minimal error (for unknown protocols). The dialog's presence and behavior can be detected programmatically.
- Firefox: Shows its own handler dialog for registered protocols and an error page for unregistered ones. The navigation behavior reveals handler registration.
- Safari: Has implemented mitigations that limit protocol probing, but timing-based detection still works in some scenarios.
- Edge: Similar behavior to Chrome (Chromium-based), with additional protocol prompts.
The Flood Handler Problem
Protocol-based fingerprinting can use differences in external URL behavior as an additional signal about the local environment. A profile policy reduces that variability without requiring a deployment to inventory desktop applications.
Timing Normalization Challenges
The core challenge in protocol detection is timing. When a browser processes a navigation to a custom protocol URL:
- It checks the OS protocol handler registry
- If a handler exists, it prepares to launch the application (or show a prompt)
- If no handler exists, it falls through to an error state
Steps 2 and 3 take different amounts of time, and this timing difference is the primary signal. Even when browsers attempt to normalize the visible behavior (showing the same UI for both cases), the underlying processing time often differs.
Installed Application Lists
Common protocols tested in fingerprinting scripts include:
- Communication:
slack://,discord://,telegram://,whatsapp://,signal:// - Development:
vscode://,sublime://,atom://,docker:// - Gaming:
steam://,epicgames://,uplay:// - Productivity:
notion://,evernote://,todoist:// - Media:
spotify://,vlc://,figma:// - Meetings:
zoommtg://,msteams://,webex://
Each additional protocol tested adds entropy to the fingerprint. Testing 30-40 protocols produces a sufficiently unique combination for reliable identification.
Limits of profile-only controls
VPNs and Proxy Servers
VPNs have no effect on protocol handler detection. Protocol registration is a local OS property, and detection happens entirely within the browser. Network-level privacy tools cannot modify protocol handler behavior.
Incognito and Private Browsing
Private browsing modes do not alter protocol handler registration. The same applications are installed in incognito as in a normal window, because protocol handlers are registered at the OS level, not in the browser profile.
Browser Extensions
Extensions can attempt to intercept protocol navigation:
- Blocking iframe navigation: An extension can block all custom protocol navigations in iframes, but this breaks legitimate deep links and is easily detected because the blocking behavior itself is observable.
- Normalizing timing: Extensions can add delays to all protocol navigations to normalize timing, but the overhead of the extension's interception is itself detectable, and the delay must be carefully calibrated to avoid breaking legitimate protocol links.
- Disabling popups: Blocking
window.open()for custom protocols can also break legitimate application launching.
Browser Mitigations
Modern browsers have implemented some protections:
- Chrome added rate limiting for protocol handler checks
- Safari implemented stricter same-origin policies for protocol navigation
- Firefox added user gesture requirements for some protocol navigation methods
These mitigations reduce the effectiveness of rapid-fire protocol probing but do not eliminate the fundamental timing differences that enable detection.
BotBrowser profile-aligned handling
BotBrowser aligns protocol handler behavior with the selected profile so local desktop applications do not silently change the profile's expected behavior.
Timing Normalization
BotBrowser normalizes the timing of protocol navigation processing so that registered and unregistered protocols produce indistinguishable timing signatures. This eliminates the primary signal used in protocol-based fingerprinting:
chrome --bot-profile="path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Uniform Behavioral Response
Beyond timing, BotBrowser ensures that the observable behavior (error states, focus/blur events, iframe status) is consistent for all protocol navigation attempts. The browser does not reveal whether a handler exists through any behavioral channel.
Legitimate Protocol Links
The protection does not block protocol navigation entirely. When a user or automation script explicitly follows a protocol link as part of a normal workflow, the navigation proceeds. Only the probing behavior, rapid enumeration of protocol handlers through timing and behavioral analysis, is neutralized.
Profile Integration
Protocol handler protection is part of the broader fingerprint profile. It works alongside OS identification, browser version signals, and other platform-specific behaviors to maintain a consistent identity:
chrome --bot-profile="path/to/profile.enc" \
--bot-noise-seed=42 \
--proxy-server="socks5://user:pass@proxy:1080" \
--user-data-dir="$(mktemp -d)"
No Host Environment Leaks
The key guarantee is that the host machine's installed applications do not leak through protocol handler queries. Whether the host has Slack, Steam, VS Code, or no custom applications installed, the protocol handler behavior is controlled by the profile, not the host environment.
External URLs in the current release
Android-target browser contexts now keep unsupported external URL schemes isolated from desktop host applications. Standard web navigation remains available in the context. This matters when an Android profile runs on a desktop worker because the worker's installed applications should not determine how that mobile profile behaves.
The policy is scoped to the context. A desktop-oriented context can use its own approved handling, while an Android-target context follows the mobile platform boundary. Keep the selected platform, profile revision, and context assignment together in the deployment record so support can explain the expected outcome.
This change does not require a list of desktop applications in the profile. The operating rule is simpler: normal web links stay in the browser, supported application flows follow the selected platform policy, and unsupported external URLs from an Android-target context do not open an unrelated desktop application.
Use a fresh context after changing the target platform. Reusing a context created with a different platform assignment makes the validation result difficult to interpret. The same rule applies when a deployment switches profile families as part of a release.
For rollout, choose normal application paths that contain both web navigation and an approved external-link action. Confirm that the web path completes and that the Android-target context remains separated from desktop-only application handling. Record the profile family, target platform, browser release, and application outcome.
Keep the check outcome-based. There is no need to enumerate installed software on the worker. The relevant release question is whether the context follows its declared platform boundary while the application continues to complete its intended web workflow.
Assigning the profile policy
Basic CLI Usage
Protocol handler protection is automatic when loading a profile:
chrome --bot-profile="path/to/profile.enc" \
--user-data-dir="$(mktemp -d)"
Playwright Integration
const { chromium } = require('playwright-core');
(async () => {
const browser = await chromium.launch({
executablePath: 'path/to/botbrowser/chrome',
args: [
'--bot-profile=path/to/profile.enc',
],
headless: true,
});
const context = await browser.newContext({ viewport: null });
const page = await context.newPage();
await page.goto('https://example.com');
// Protocol handler queries will produce uniform responses
// regardless of host machine's installed applications
await browser.close();
})();
Puppeteer Integration
const puppeteer = require('puppeteer-core');
(async () => {
const browser = await puppeteer.launch({
executablePath: 'path/to/botbrowser/chrome',
args: [
'--bot-profile=path/to/profile.enc',
],
headless: true,
defaultViewport: null,
});
const page = await browser.newPage();
await page.goto('https://example.com');
// Protocol handler signals are controlled by the profile
await browser.close();
})();
Combined with Application Identity Protection
For complete application-level privacy:
chrome --bot-profile="path/to/profile.enc" \
--bot-noise-seed=42 \
--bot-config-timezone="Europe/London" \
--bot-config-locale="en-GB" \
--user-data-dir="$(mktemp -d)"
Validating application behavior
After launching BotBrowser with a profile, verify protocol handler protection:
// Test protocol handler timing consistency
async function testProtocolTiming(protocol) {
const start = performance.now();
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
document.body.appendChild(iframe);
return new Promise(resolve => {
iframe.onload = () => {
resolve(performance.now() - start);
document.body.removeChild(iframe);
};
iframe.onerror = () => {
resolve(performance.now() - start);
document.body.removeChild(iframe);
};
iframe.src = `${protocol}://test`;
setTimeout(() => {
resolve(performance.now() - start);
if (iframe.parentNode) document.body.removeChild(iframe);
}, 500);
});
}
// Both registered and unregistered protocols should
// produce similar timing
const timing1 = await testProtocolTiming('slack');
const timing2 = await testProtocolTiming('nonexistentprotocol12345');
console.log('Slack timing:', timing1);
console.log('Unknown protocol timing:', timing2);
console.log('Difference:', Math.abs(timing1 - timing2));
What to check:
- Timing differences between known and unknown protocols are minimal (within noise range)
- No focus/blur events are triggered by protocol probes
- Protocol detection test pages (like SchemeFlood.com) show uniform results
- The host machine's installed applications are not detectable through protocol queries
Deployment safeguards
-
Use complete profiles. Protocol handler protection works best as part of a comprehensive profile that controls all fingerprint surfaces consistently.
-
Test the approved application flow. Confirm that web navigation and expected external-link behavior match the selected platform profile.
-
Combine with other protections. Protocol handler detection is often used alongside Canvas, WebGL, and font fingerprinting. Use a complete profile to ensure all vectors are covered.
-
Keep profiles updated. As browsers implement new protocol handler mitigations and detection techniques evolve, updated profiles ensure continued protection.
-
Avoid installing unnecessary applications on the host. While BotBrowser prevents protocol leaks, minimizing the host's installed application set reduces the overall attack surface.
External URL questions
Can protocol detection identify specific application versions?
Generally no. Protocol handler detection reveals whether an application is installed, not which version. However, some applications register version-specific protocol schemes, which can narrow the version range.
Does protocol detection work on all operating systems?
The technique works on Windows, macOS, and Linux, but the specific behavior varies by OS. Windows protocol handlers are registered in the Windows Registry. macOS uses Info.plist declarations in application bundles. Linux uses .desktop files. BotBrowser normalizes behavior regardless of the host OS.
Can websites detect protocol handler protection?
JavaScript interception can add page-specific behavior. BotBrowser applies the selected profile policy consistently across the context.
Does this break legitimate protocol links?
No. BotBrowser's protection targets the probing behavior used for fingerprinting, not legitimate protocol navigation. When a user or script explicitly follows a protocol link as part of a normal workflow, the navigation functions normally.
How many protocols can be tested in a fingerprinting script?
The number varies by site and is not a useful deployment target. Validate the approved application outcome and keep the profile assignment consistent across the release.
Is this the same as the "scheme flooding" attack?
Scheme flooding is one form of protocol-based fingerprinting. BotBrowser applies a consistent profile policy to external URL handling.
Do mobile browsers support protocol detection?
Yes, but with more restrictions. Mobile browsers (particularly Safari on iOS) have stricter policies around protocol handler navigation. BotBrowser profiles for mobile configurations include the appropriate protocol handling behavior for the target mobile platform.
Does registerProtocolHandler() play a role?
The navigator.registerProtocolHandler() API allows websites to register themselves as handlers for specific protocols. This is a separate concern from application-installed protocol detection. BotBrowser controls both the detection signals and the registration behavior as part of the profile.
Rollout and support ownership
Give the external URL policy the same owner as the platform profile. That owner should know whether a deployment uses Android or desktop-oriented contexts, which application links are part of the approved workflow, and which outcome requires rollback. Keeping this responsibility with the profile avoids a separate URL policy drifting away from the declared platform.
Start rollout with a representative worker and a fresh context. Use the intended browser release, profile revision, target platform, and application version. Confirm ordinary web navigation first, then exercise the approved external-link path. Record the application result rather than a list of software installed on the worker.
Expand by deployment group after both paths behave as expected. Keep the prior profile and browser release available until the rollout completes. If an Android-target context causes an unexpected desktop action or the application web path stops completing, restore the last reviewed release unit before changing other inputs.
Support records should include the browser release, profile family, target platform, context assignment, application path, and outcome. Those fields establish whether the declared platform boundary was followed. Full navigation histories and desktop application inventories are not needed for routine release support.
Review the policy when the application introduces a new external-link workflow or when a profile changes platform family. Retire validation paths that no longer exist in the application. A short, current set of approved checks is easier to operate than a growing collection of historical links.
Include worker platform changes in the review. Moving the same deployment between desktop operating systems can change which local applications are available, but an Android-target context should continue to follow its declared mobile boundary. Repeat the approved web and external-link checks after such a move, using the same profile family and application path. This confirms the portable application outcome without turning local software inventory into deployment configuration.
Keep user-facing recovery clear. If an approved external action cannot continue under the selected platform policy, the application should present its normal fallback or remain on the web path. The deployment should not silently switch to a desktop application that belongs to a different platform assignment.
Keeping platform behavior consistent
Custom URL handlers can expose information about the desktop environment. BotBrowser aligns external URL handling with the selected platform profile. Android-target contexts keep unsupported external URLs separated from desktop host applications while preserving standard web navigation. See the features page and the Android emulation documentation for maintained configuration guidance.
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.