Browser API Compatibility Data and Feature Fallbacks
Use public compatibility data and runtime feature detection to choose resilient browser API fallbacks.
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.
Browser compatibility data is planning evidence, not a promise that every browser exposes an API identically. A support table can tell a team which releases deserve a test, which secure-context requirement needs a staging certificate, and which partial implementation needs a separate assertion. It cannot tell the application that a user has granted permission, that a service is reachable, or that a business operation completed. A resilient implementation treats those as separate observations. First define the user task and its acceptable result. Then select a primary API, identify a useful alternative, and make the transition visible when the primary route is unavailable. This approach keeps compatibility work privacy-aware: capability checks describe what the current page can attempt, not who is operating the page or what device they own. The same discipline applies to a public form, an authenticated dashboard, and a high-volume test suite. The reader should understand the expected behavior without knowing a browser's hidden mechanics. The practical unit of planning is not a browser name but a user-visible capability. For example, “share this report” may be satisfied by Web Share, a copy-link control, or an email action. “Choose a file” may use the File System Access API or a normal file input. “Sign in with a credential” may use WebAuthn or a clearly labeled password route. Write the equivalence and the differences down before measuring support. A fallback can have lower fidelity and still be correct when it preserves the task, communicates the tradeoff, and protects the data already entered. A compatibility review should therefore ask what the user can finish, not merely whether a property exists. This wording also prevents support teams from overpromising on a browser release whose API is present but constrained by policy, permissions, private browsing settings, or an embedding context.
Compatibility data sources
The MDN Browser Compatibility Data project records support by browser and version. Read the feature entry, release ranges, notes, flags, secure-context requirements, and partial-support caveats together. A green cell is useful for selecting an initial matrix, but a note about an experimental flag can change the test plan. Record the data revision or retrieval date in the test record so a later release can explain why a case changed. Chrome's feature-detection guidance is a practical companion: test the capability that the task needs rather than parsing a user-agent string. User-agent parsing makes assumptions about identity and often misses embedded browsers, policy settings, and permission state. For each feature, write the minimum supported browser set, the condition that makes the API usable, the expected exception or rejection, and the fallback owner. That small record prevents a compatibility table from becoming an unsupported promise.
Compatibility work benefits from distinct expectations. A browser release can implement a method but reject its call because the page is not secure. A method can be present and return a promise that rejects because the user denied a prompt. A successful browser call can still be followed by an application-level error from the server. Keep those layers in the test report. For every candidate API, write down its required context, permission behavior, exception or rejection shape, visible success signal, visible failure signal, and alternative action. This record is more durable than a screenshot of a support table and makes a release review auditable without collecting profile data. It also lets a support engineer reproduce one declared state instead of guessing from a browser label. The same separation is useful during incident response. If a method is missing, investigate the declared browser and origin context. If the method rejects with a permission error, investigate the prompt, policy, and user choice. If the browser call succeeds but the UI remains pending, investigate application event handling and server acknowledgement. Do not collapse all three into “browser incompatibility.” The test report can include a normalized state, the original exception name, the visible message, and the next action. It can also include a link to the public compatibility entry and the exact fixture revision. That gives a maintainer enough information to reproduce the branch while avoiding sensitive snapshots of a profile or account. A small normalized report is easier to compare across releases than a raw console dump.
Feature detection principles
Ask whether the operation can be performed in the current page. Test for the method, construct a small safe object, or call a documented capability check. Keep detection local to the feature and perform it immediately before use when permissions or page state can change. Do not treat a property on navigator as proof that the API will succeed. Detection should be cheap, side-effect free, and easy to exercise in a synthetic page. A wrapper should return a small state such as available, missing, denied, failed, or completed; callers can then choose a visible path without duplicating browser-specific assumptions. The wrapper should also preserve the user's input while changing paths, because a fallback that discards a draft is a data-loss defect rather than a compatibility improvement.
The decision boundary should be explicit. Available means only that the primary call is reasonable to try. Missing selects the alternative without an invisible retry. Denied explains the permission result and preserves the alternative. Failed records a bounded failure and avoids repeatedly prompting or spinning. Completed should be reserved for the user-visible or application-level completion signal, not merely for a resolved browser promise. This distinction matters for Web Share, Clipboard, Geolocation, Notifications, File System Access, and WebAuthn, where permission and origin policy are part of real behavior. It also makes cross-browser tests comparable: each browser reports the same state vocabulary even when its underlying exception differs. A state machine is easier to review than a chain of user-agent branches.
Decision table
| Observation | Decision | User-visible result | Evidence boundary |
|---|---|---|---|
| API and required method exist | Try the primary path once | Announce progress and keep cancel available | Browser capability only |
| API is absent or blocked by context | Use the alternative | Keep the task available with equivalent instructions | Compatibility and context |
| API exists but permission is denied | Explain the denial and offer the alternative | Preserve user control; do not reprompt in a loop | Permission result |
| Call rejects or throws | Classify the failure and stop retrying | Show a recoverable error and alternative action | Runtime behavior |
| Browser call resolves | Verify the application outcome | Confirm only the result the user can observe | Browser plus application signal |
Failure fixture
Use a synthetic page to exercise missing-method, denied-permission, rejected-promise, and delayed-completion paths. A fixture should stub only the owned test surface, reset its state for each attempt, and assert the message or control a real user sees. For a share flow, replace navigator.share with a function that rejects, then verify that a copy-link button becomes available. For a clipboard flow, expose the method but reject the promise, then verify that the text remains selectable. Do not patch a browser fingerprint, collect unrelated properties, or claim that a synthetic rejection proves a production service is down. The fixture demonstrates the application's branch and cleanup, not universal browser behavior. A deterministic fixture should include a timeout, a bounded retry count of zero or one, and cleanup in finally so a failed test cannot poison the next attempt. Keep synthetic URLs and titles obviously non-production, and assert both the error message and the continued usability of the fallback.
async function runShareOrCopy() {
const host = document.createElement('div');
host.innerHTML = '<p id="status"></p><button id="fallback" hidden>Copy link</button>';
document.body.append(host);
const status = host.querySelector('#status');
const fallback = host.querySelector('#fallback');
const canShare = typeof navigator.share === 'function';
if (!canShare) {
fallback.hidden = false;
status.textContent = 'Use the available alternative';
console.assert(!fallback.hidden && status.textContent.length > 0);
host.remove();
return { state: 'missing', action: 'copy-link' };
}
try {
await navigator.share({ title: 'Synthetic item', url: '/fixture' });
status.textContent = 'Shared';
console.assert(status.textContent === 'Shared');
host.remove();
return { state: 'completed', action: 'none' };
} catch (error) {
fallback.hidden = false;
status.textContent = 'Use the available alternative';
console.assert(!fallback.hidden && status.textContent.length > 0);
host.remove();
return { state: error?.name === 'NotAllowedError' ? 'denied' : 'failed', action: 'copy-link' };
}
}
Progressive enhancement and maintenance
Design the core task so it remains useful without the optional API. A copyable URL, ordinary file input, typed address, or keyboard-operable control is often better than a browser-specific approximation. Preserve entered data when switching paths, explain why the alternative is shown, and make the alternative reachable without a second permission prompt. Accessibility is part of compatibility: focus should move to the new status, labels should describe the action, and error text should be available to assistive technology. A fallback that technically works but hides the next action is not complete. Document whether the fallback has lower fidelity, slower performance, or different security properties so product teams can make an informed choice.
Recheck support data when browser releases, permissions, secure-context requirements, or origin policies change. Keep a compatibility ledger with the feature name, source URL and revision date, declared test browsers, detected state, fallback chosen, visible outcome, and owner for the next review. Separate browser observations from server observations and avoid retaining raw profile, credential, location, or personal content. When a release changes behavior, add a fixture for the new state before changing production branching. This keeps progressive enhancement maintainable instead of turning it into a collection of untested user-agent exceptions. Review the ledger after framework upgrades and remove detectors that no longer represent a supported product path. Maintenance also needs an explicit ownership boundary. The front-end owner decides how a denied prompt is explained and where focus moves. The application owner decides what counts as a committed record and how an interrupted operation is resumed. The test owner decides which synthetic fixtures are safe to repeat and which artifacts are deleted after the assertion. Public release notes inform those decisions but do not make them on the team's behalf. When a capability is intentionally optional, document that choice in the product requirement so a future engineer does not make the primary API mandatory. Measure the visible outcome at the same boundary for every browser. A screenshot can prove that a button appeared, but it cannot prove that a remote record exists. A resolved promise can prove that the browser accepted a request, but it cannot prove that a user saw the result. Use a stable status message, an application acknowledgement, or an owned test endpoint when that distinction matters. Keep timing thresholds realistic and report timeouts as timeouts rather than silently converting them into missing-feature states. This makes a failed compatibility run actionable and avoids hiding service regressions behind a generic alternative.
BotBrowser capability and limitation
BotBrowser can provide controlled browser contexts for authorized compatibility journeys and repeatable synthetic fallback checks. Teams can use an isolated context to run the same owned test page across a declared browser release set, record capability state, and compare the visible branch without sharing mutable session storage between attempts. That is useful for regression evidence around permission prompts, rejected promises, secure-context setup, and fallback controls. The result should identify the page, API, browser release, context assumptions, fixture version, and observed user-visible outcome. It should not be presented as a universal support claim or evidence about a person. Keep the release set explicit and retain only the assertions needed to explain the outcome.
BotBrowser does not guarantee that an API exists on every origin, grant permission, make an insecure context secure, control an operating-system policy, or replace application accessibility and fallback design. It does not turn a passing synthetic journey into proof that an upstream service, account, server record, or business transaction succeeded. The test author owns fixtures and assertions, the application owns permission messaging and server outcomes, and the browser environment supplies one bounded observation. BotBrowser isolation documentation is product evidence for repeatability, not a substitute for MDN data, runtime checks, or production monitoring. Treat an unavailable API as an expected branch, not as an instruction to alter a browser profile.
For adjacent implementation details, compare the WebDriver BiDi events and browser automation guide and the Credential Management API sign-in guide. Both illustrate why browser signals and application completion should be reported separately. Reuse the same localized links in translated editions so readers can continue to a related technical example without leaving their language path. A compatibility report is strongest when it names the feature, declared context, observed state, visible fallback, and evidence source in one short record. A useful record can also state whether the observation came from a fresh context, whether the page was served over HTTPS, whether a permission prompt was expected, and whether the assertion stopped at the browser boundary or continued to an owned application acknowledgement. These fields explain why two apparently identical runs may differ without assigning a person or device an inferred identity. They help a team decide whether to update the matrix, improve fallback copy, or investigate a service-level failure. A Clipboard test should distinguish a missing method, a denied permission, and a successful write followed by a visible status. A Geolocation test should distinguish an insecure context, user denial, timeout, and a returned position that the application rejects as stale. A WebAuthn test should distinguish an unsupported authenticator, a cancelled ceremony, an origin mismatch, and a server rejection. Each route needs a keyboard path and deterministic assertion. Start the matrix with releases the product actually supports, add partial-support cases, and remove a case only after an owner confirms that the product no longer serves that environment. The matrix is a decision record, not a popularity ranking, and the alternative remains valuable because policy and permission can change the result.
Include the reason for each alternative, the person responsible for its copy, and the date when evidence should be refreshed. This makes a compatibility review useful to engineers, support staff, and accessibility reviewers at the same time. It gives release notes a precise scope: a change may affect one API, one origin condition, or one permission branch rather than every browser. Keep the explanation close to the control so a person can finish the task even when the primary capability disappears between page load and button activation. A short record can name the expected state, the observed state, and the next action without exposing account content.
A release review should preserve the first meaningful failure, distinguish a timeout from an absent feature, and state which visible control remains available. That small discipline keeps compatibility evidence honest when several layers fail together.
A final review should name the browser context, permission state, visible result, and alternative action so another engineer can reproduce the decision without private data. It should also identify the source revision and the next review date. This keeps a support answer precise when policies change.
The review should preserve the original exception name, state whether the page was secure, and identify the control that remained usable. These details keep a compatibility decision reproducible during a later release.
Compatibility notes should remain close to the tested control and should state whether the fallback preserved the user's input. This makes the decision useful during support, release review, and accessibility testing.
Record the visible status and next action plainly so the result remains understandable after the browser release changes.
Sources
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.