Baseline is a computed summary of MDN compat data with known blind spots; here is what the definition promises, where it breaks, and a method to check a feature yourself.
Contents · 11 sections
Here is a question that sounds settled and isn't: can we drop the polyfill? Somebody on the team opens webstatus.dev, sees a green "Baseline" badge, and the pull request that removes the shim gets approved in five minutes. Most of the time that's fine. Sometimes it ships a bug to every user of one engine, and the badge was technically correct the whole time.
The obvious answer, "Baseline means it works everywhere", is incomplete in three specific ways. Baseline is computed, not judged: a script reads MDN's browser-compat-data and applies a rule. It summarizes a group of compat keys, so the part of the feature you need can be fine while the badge says no, or the reverse. And its inputs get corrected, sometimes years later, which can move a feature out of Baseline after you've already shipped on the strength of it.
This piece settles what the definition actually promises, reads the code that computes it, walks through the features where the badge and reality need a second look, and ends with a method you can run yourself. Every status in it was checked on October 18, 2026. If you're reading this later, the dates will have moved; the method is the part that keeps.
Baseline is two dates and a list of seven browsers
The public definition is short. web.dev's Baseline page describes two stages. A feature is newly available when it "is supported by all of the core browsers", and widely available once 30 months have passed since that newly interoperable date. Before that it has limited availability. The same page names the core set as Chrome (desktop and Android), Edge, Firefox (desktop and Android) and Safari (macOS and iOS), and says Baseline "was originated by the Chrome team and is now defined by the WebDX Community Group".
There's also a calendar layer. web.dev groups features into yearly targets: everything that becomes newly available in 2026 is "Baseline 2026", which the page calls "the latest and currently developing feature set". It's a label on top of the same two dates, not a third rule.
The page then makes a much bigger promise than the data can carry: if every feature you use is Baseline, "you can trust the level of browser compatibility". The rest of this article is about the distance between that sentence and the pipeline underneath it.
Keep one vocabulary difference in mind, because it trips up anyone who reads both the website and the package. webstatus.dev says newly, widely and limited. The web-features npm package says low, high and false. They are the same three states. I'll use the web.dev words in prose and the package words when quoting data.
The definition is stricter than the badge, and looser in one place
The normative text isn't on web.dev. It's docs/baseline.md in the web-features repository, maintained by the WebDX Community Group's owners group. Read it the way you'd read a spec, because several things that matter in practice live only there.
The low status depends on one dataset, by name
A feature gets the interoperable (low) status if "for each current stable release in the core browser set, the release supports the feature (as reported by the current version of @mdn/browser-compat-data, excluding those features identified as having partial_implementation)". There's no clause about tests, specs or bug trackers. If BCD says yes, it's yes. If BCD says partial, it's no.
The second condition is negative: the feature must not be marked as discouraged by its spec, and the owners group must not be applying an editorial override. So apart from the clock, two kinds of change can move a status: a change to BCD, or a human edit to the feature file, whether that's an override, a discouraged flag, or a change to which keys the feature maps.
The keystone date is the last introduction, and only the last
When a feature qualifies, its keystone date is "the last release date on which a browser introduced support for the feature". If support was withdrawn and reintroduced, "only the latest date applies". In other words, the slowest of the seven browsers sets the date, and a regression followed by a fix resets the clock to the fix.
You can see that in the reference implementation. support.ts in the compute-baseline package starts at each browser's current release and walks backwards until it finds a release without support; the release after that gap is the "initial support". index.ts then sorts every initial-support release (one per browser, and per key when a feature has several) by date and takes the latest. If any browser has no initial support, there is no keystone date and the status is false. And feature.ts is explicit that the check "treats qualifications such as partial implementations, prefixes, alternative names, and flags as wholly unsupported". So it's not only partial_implementation: a prefix or a flag counts as no support at all.
AbortSignal.any() makes a clean worked example. On webstatus.dev it arrived in Chrome 116 (2023-08-15), Edge 116 (2023-08-21), Safari 17.4 (2024-03-05) and Firefox 124 (2024-03-19). Firefox was last, so the keystone (low) date is 2024-03-19. Add 30 months and you get the high date that webstatus.dev reports today: 2026-09-19. Fig. 1 shows that computation.
Chrome Android 116, Firefox Android 124 and Safari iOS 17.4 ship on the same dates, so four lanes cover all seven core browsers. Date axis to scale; dates from webstatus.dev, 2026-10-18.
Widely available is computed against the data's clock, not yours
"30 months after the keystone date" needs a notion of now. The implementation doesn't use the system clock. The comment in index.ts says it uses "BCD's __meta.timestamp" as "a cutoff date approximating 'now'". So a feature flips to widely available when a web-features build picks up a BCD release whose timestamp is past the high date, not on the high date itself.
The lag is small but real. Going by the release dates on npm and each package's own data, version 3.39.0 (released 2026-09-17) still listed abortsignal-any as low. Version 3.40.0, released on 2026-09-24, listed it as high with a high date of 2026-09-19. If your tooling pins an older web-features, the badge you see is as old as your lockfile.
The Firefox ESR clause exists on paper and nowhere else
The high-status rule has a second condition that summaries leave out. The keystone date must be "on or before today's date minus 30 months and the dates of the following long-term support releases: Mozilla Firefox ESR, given by the release date for the latest x.0 release of Firefox ESR (or the previous x.0 release, when there are two active ESR releases)".
That sentence is hard to parse, and the maintainers agree. Issue #4009, "Definition of baseline high ESR clause is unclear", opened in May 2026, lays out two incompatible readings. In the same thread, a project collaborator says that because ESR has never in practice set the total duration, "there's no actual code enforcing or checking this". That matches what I found: the duration is a single constant, BASELINE_LOW_TO_HIGH_DURATION, set to 30 months in index.ts, and a search of the repository's TypeScript sources (commit 97c5a95, 2026-10-16) turned up no ESR handling. A clarifying PR #4010 was still open that day.
The data also shows why the "two active ESR releases" wording is a trap. Mozilla's product-details feed lists the current ESR as 153.5.0esr and a separate FIREFOX_ESR115 branch at 115.43.0esr. Per the major release history, 153.0 shipped on 2026-07-21 and 115.0 on 2023-07-04. If ESR 115 counted as the "previous x.0", AbortSignal.any() (keystone 2024-03-19) could not be widely available yet. It is. Another collaborator in issue #4009 explains that Firefox can currently have three ESR branches at once, because ESR 115 stayed alive for older Windows versions, and writes that they "don't expect ESR 115 to form part of the baseline definition". That's consistent with the data. The document still doesn't say it; PR #4010 would.
The goals promise more than the computation checks
The document's goals are ambitious. Baseline features "should not surprise a web developer with compatibility failures", and while all software has bugs, "Baseline features have narrow, known bugs." Its non-goals go further on the question this article opened with: developers "should be able to use Baseline to decide when to stop shipping a polyfill." Nothing in the computation tests any of that. The only thing that encodes "narrow, known bugs" is a BCD editor deciding to set partial_implementation, which is why the top-level await story later in this piece matters so much.
The non-goals also list what Baseline won't do, and two of those items change how you should read the badge. It doesn't "identify support in assistive technology", so a Baseline element can still be announced badly by a screen reader. And it is "a complement to, not a replacement for, detailed compatibility reporting", meaning the authors don't intend it to answer the question you're actually asking about your users. It also excludes non-browser runtimes such as Node.js and Deno.
The governance section says the status definition "is due for review by the owners group on 9 September 2026". As of October 18, the file's last change is from February 2026 and it still carries that date. I'll come back to that in the last section.
The status is computed from BCD keys, not from the spec
Baseline doesn't know what a "feature" is in any deep sense. A web-features entry is a YAML file with a name, a spec link and a list of BCD keys under compat_features. A build step computes the status and writes it to a generated .yml.dist file next to the source. The web-features repository is the place to read both. webstatus.dev then serves the same result per feature, with dates, from api.webstatus.dev/v1/features/<id>.
Fig. 2 traces that path for WebGPU and marks the three places where the answer can change without any browser shipping anything: which keys count (B), which qualifications count as no support (A), and editorial overrides (C).
By default a group takes the version of its least-supported key
The status of a feature with many keys is, by default, the status of all of them together. In index.ts, collateSupport takes the most recent initial-support release per browser across every key, and the keystone date comes from those. The scheduler feature file is the textbook case. Its generated header says Chrome 129, but the commented per-key block beneath it says api.Scheduler and api.Scheduler.postTask arrived in Chrome 94. The difference is api.Scheduler.yield, which is grouped into the same feature and arrived in Chrome 129.
If you only need scheduler.postTask(), the group version understates how long it's been in Chrome by 35 releases. If you need scheduler.yield(), the headline is the right number. Neither is wrong; they answer different questions.
Some headlines are pinned to one key
The default has an escape hatch, and three of this article's examples use it. The status overrides section of the web-features guidelines describes three ways to finesse a headline. The oldest is compute_from, which "selects one or more compat keys from which to calculate a status for the whole feature" and ignores the rest. The guidelines call it deprecated and planned for removal, but it's still in the data.
webgpu.yml maps 301 BCD keys in web-features 3.43.0 and computes its headline from exactly one of them, api.Navigator.gpu. temporal.yml maps 243 keys and computes from javascript.builtins.Temporal. navigation.yml maps 59 and computes from api.Navigation; there every key happens to agree, with a 2026-01-13 low date. So the headline can be greener or redder than the keys you call, and the only way to know which kind of headline you're looking at is to open the source YAML.
Per-key status exists, and it's the one you want
Newer packages carry a by_compat_key block next to the headline status in data.json. It's absent in 3.5.0 and first appears in 3.6.0, published 2025-10-21. For navigation, every key reads low with a 2026-01-13 date; for scheduler, you can see api.Scheduler.postTask at Chrome 94 and api.Scheduler.yield at Chrome 129 side by side. If your code depends on two methods out of fifty, the per-key status is the claim that matches your risk. The headline is a convenience.
One green badge and three limited ones, each for a different reason
Here's what the data said on October 18, 2026 for the features the rest of this piece uses. Each "no" or "yes" has a different cause, and the cause decides what you do next.
Navigation API: yes, and the WPT scores say read the details
The Navigation API is newly available on webstatus.dev, with a low date of 2026-01-13. Chrome has had it since 102 (2022-05-24). Safari 26.2 arrived on 2025-12-12, and Firefox 147 on 2026-01-13; Firefox was last, so it set the date.
The webstatus.dev API response for the feature also carries Web Platform Tests scores for its mapped tests. In the stable channel, Chrome scored 0.977, Firefox 0.916 and Safari 0.795. Baseline doesn't read those numbers at all. A Baseline feature where one engine passes about four in five of the mapped tests is "supported" in the BCD sense and still worth testing on your own flows. That isn't a criticism of either engine; it's a reminder that "supported" and "behaves identically" are different claims.
Temporal: no, because one engine hasn't shipped
Temporal is limited. Firefox shipped it in 139 (2025-05-27) and Chrome in 144 (2026-01-13), with Edge 144 following on 2026-01-21. BCD's Temporal entry lists Safari as "preview", which counts as unsupported for Baseline because it isn't a stable release, and Safari on iOS as false.
This is the easy kind of "no". It's also the kind that resolves by calendar rather than by argument: the proposal is finished, and TC39's finished-proposals list gives 2027 as its expected publication year. The audit script below turned up one more detail. BCD's PlainDate entry marks withCalendar() as partial in Firefox 139, because the islamic, islamic-rgsa and islamic-umalqura calendars aren't available, and the same flag repeats on sibling types. Because the headline is computed from the root key only, those entries don't touch it. When Safari ships, the headline can turn green while the per-key status for withCalendar() stays limited, for as long as Firefox's entries say partial.
WebGPU: no, because "partial" is a judgement call
WebGPU is limited and the generated webgpu.yml.dist lists Chrome 144, Chrome Android 121, Edge 144 and Safari 26, with no Firefox line at all. That looks like Firefox hasn't shipped. It has.
The headline key, api.Navigator.gpu, is in BCD's Navigator.json: Firefox 141, partial_implementation: true, "Supported on Windows only." The detail lives one level down. BCD's GPU.json records the same Firefox 141 partial entry for api.GPU with a list of notes: all contexts except service workers; Windows since 141; macOS Tahoe on Apple silicon since 145; older macOS on Apple silicon since 147; no Intel macOS; no Linux. Firefox for Android is version_added: false. Mozilla's own announcement for Firefox 141 says it plainly: WebGPU ships "on Windows", with Mac, Linux and Android to follow.
The interesting part is that Chrome desktop went through the same filter. In GPU.json, BCD records Chrome 113 to 144 as partial ("Supported on ChromeOS, macOS, and Windows") and full from 144, with a note that Linux support is limited to Intel Gen12+ GPUs. So Chrome's desktop version for Baseline is 144, not 113, for the same platform-coverage reason that Firefox is absent. The sources don't disagree about facts here. They disagree about where "enough platforms" begins, and BCD's editors draw that line one entry at a time.
Scheduler: no, and the missing engine hasn't taken a position
The Scheduler API is limited: Chrome 129 (group version), Firefox 142 (2025-08-19), no Safari. This "no" is different from Temporal's. There's no finished standard on a train; there's a WICG specification and one engine that hasn't said what it thinks. I'll come back to that in the section on standards positions.
Top-level await was widely available, then it wasn't
The case that should change how you treat a green badge is top-level await. It went from widely available to limited and back to newly available, and no browser shipped or unshipped anything during the drop. Fig. 3 lays the sequence out.
The original status was computed from data that missed a bug
Chrome and Firefox both shipped top-level await in version 89, on 2021-03-02 and 2021-06-01, per webstatus.dev. Safari 15 followed on 2021-09-20 (the date in BCD's Safari release list). The feature entered web-features late, in PR #2417, merged on 2024-12-12. The first package that contains it, 2.13.0 from 2024-12-16, already reads baseline: high, low date 2021-09-20, high date 2024-03-20, and 2.34.0 from April 2025 still says the same. So the status in Fig. 3 before December 2024 is what the rule gives for those dates, not a badge anyone saw at the time.
Safari had a bug the whole time. WebKit bug 242740, filed on 2022-07-14, is titled "ReferenceError when multiple modules are simultaneously importing a module containing a top-level await". The web-features maintainers' own write-up in issue #2957 says the bug had been present since Safari first shipped the feature, and that it was reported to BCD in July 2023.
The reclassification, the override, and the revert
The correction took a while to reach the badge, and the route it took is instructive:
- 2025-04-29. BCD merges PR #26510, "Safari only partially supports top-level await", marking Safari 15 onwards as
partial_implementation. - 2025-05-02. The BCD update lands in web-features through a routine dependency bump, PR #2921, and the computed status drops from
hightofalse. The maintainer withholds a release. - 2025-05-12. After discussing it on the WebDX call of May 8 (per issue #2957), the next bump, PR #2954, adds an editorial override that pins the feature back to
highwhile the owners group decides. - 2025-10-24. PR #3483 reverts the override. The first package without it in my checks is web-features 3.7.0, published 2025-11-03, where the feature reads
baseline: false. - 2026-06-11. BCD merges PR #29838, "Safari 27 correctly supports top-level await in modules", ahead of the release.
- 2026-09-14. Safari 27 ships. In BCD's await.json today, Safari 15 through 26 is partial ("Doesn't support multiple modules simultaneously importing a module containing a top-level await") and Safari 27 is full. web-features 3.39.0 (2026-09-17) is the first package in my checks that shows
lowwith a 2026-09-14 date; 3.38.0, a week earlier, still saysfalse.
The comments on issue #2957 are worth reading for the reasoning. One participant argued that developers use top-level await for months without trouble "until the day somebody adds a second top-level await" in a separate module, after which Safari users intermittently fail to load the page. That's the shape of bug a summary status is worst at: invisible in a demo, fatal in a large module graph.
The more interesting argument in that thread is about process. A collaborator who was wary of regressing a widely available feature suggested that the 30-month window should double as a triage window: problems serious enough to regress a status ought to surface within a few months of a feature becoming newly available, and one found after 24 months or more is possible evidence that the process failed. The same comment notes that this case never had that chance, because the web-features entry didn't exist for most of the window. That's the honest reading of the cushion. Widely available doesn't mean 30 months of verified interop; it means 30 months in which someone could have filed the BCD issue.
The engine side of the story
WebKit's post on fixing top-level await, published 2026-09-02, explains the cause. Safari's module loader had been written against the WHATWG Loader proposal, which it says was last updated in January 2016, and top-level await had been implemented "in terms of a proposal that was abandoned before any support for async/await existed in ECMAScript". The fix was to rewrite the loader from the ground up, starting in January 2026; the bug records the change landing in WebKit on 2026-04-14, five months before it shipped. The Safari 27.0 release post describes the new loader as implemented in native C++ and conforming "directly to the ECMAScript specification's module loading algorithms".
The failure mode is easy to reproduce in a page. This is a compressed version of the example in WebKit's post; per their write-up, the old loader resolved the second and third imports before the module had finished evaluating, so reading its exports threw. I haven't run it on a pre-27 Safari myself.
// A module that suspends at top level before defining its exports.
await new Promise((resolve) => setTimeout(resolve, 10));
export const cart = [];// Three concurrent dynamic imports of the same async module.
const loads = [1, 2, 3].map(async (n) => {
const mod = await import('./test-module.js');
try {
console.log(n, Object.keys(mod));
} catch (error) {
console.log(n, 'failed:', error.message);
}
});
await Promise.all(loads);Load main.js with <script type="module">. In a spec-conforming engine all three lines print ["cart"] in order 1, 2, 3; I confirmed that in Node 24.18.0, which uses V8, by running main.js renamed to main.mjs. WebKit's post shows the old Safari loader finishing in order 2, 3, 1, with the first two to finish failing with "Cannot access ... before initialization".
What the WPT data showed during all of this
Here's the part I didn't expect. WPT has had tests for how async modules interact with their siblings since November 2023: sibling-imports-not-blocked.any.js, run in a window and in a worker. Their directory's WEB_FEATURES.yml maps them to top-level-await, although that file was only added in January 2026.
webstatus.dev keeps a history of those mapped tests. Its test-count series for Safari stable starts on 2024-01-25 and shows Safari passing 0 of 2 in every run until 2026-09-16, then 2 of 2 from 2026-09-17 onwards. From the first package that contained the feature in December 2024 to the 3.7.0 package in November 2025, web-features said widely available while those runs were red. The series includes runs from two years before the mapping existed, so webstatus.dev evidently applies today's mapping to old results; nobody's dashboard connected those failures to the feature at the time. But the tests were public and the runs were red; the badge was the one people read.
I want to be careful about what that proves. The WPT test checks a related ordering property, not the exact reproduction in WebKit bug 242740, and I haven't confirmed that the failures had the same root cause. It's still a strong argument for checking tests next to the badge.
Each source fails in its own way
None of the four sources you'd consult is wrong in general. Each one has a predictable blind spot, and knowing which is which is most of the skill.
BCD: correct, editorial, and retroactive
MDN's browser-compat-data is the only input Baseline reads. Its partial_implementation flag is an editorial decision, as WebGPU shows, and corrections apply backwards: the top-level-await PR re-described every Safari release back to Safari 15 in 2021. Because only the latest introduction counts, a retroactive "partial" does more than lower the status. It erases the old keystone date and replaces it with whatever comes next.
The regression note proposal, issue #1971, still open since October 2024, asks that a status regression carry a type, a date, an explanation and a link, so tools could tell users why a feature fell out. Until that lands, the reasoning lives in YAML comments and GitHub threads. The source top-level-await.yml still carries a hand-written note dated 2025-05-02: the date, "high → false", the Safari bug, and links to the BCD PR and WebKit bug.
web-features: the headline may not speak for your key
By default the group status is the latest version of its least-supported key, as the scheduler example showed. That's a reasonable default for "can I use this API", and a misleading one for "can I use this method". And when a feature uses compute_from, as WebGPU and Temporal do, the headline speaks for one key and stays silent about the rest. Either way, read by_compat_key.
wpt.fyi: desktop by default, mobile by request
The default stable query, /api/runs?label=master&label=stable, returned four runs on 2026-10-18, all desktop: Chrome 155, Edge 155, Firefox 158 and Safari 27.0, all from 2026-10-17. Mobile runs exist but have to be requested per product, and they run less often. The latest stable chrome_android run was Chrome 153 from 2026-09-16; the latest firefox_android run was Firefox 158 from 2026-10-09. Asking for product=safari_ios returned "invalid browser name".
The Interop 2026 README lists mobile testing as a continuing investigation effort, now focused on testing mobile-specific behavior such as dynamic viewport changes. So two of the seven core browsers have public test data only on request, one of them a month old, and one has none that I could find, even though Baseline counts all seven.
caniuse: context, not evidence
caniuse is a separate presentation of compat data, with its own notes and its own maintainers. It's good for a fast look. When the answer decides whether a polyfill ships, confirm it against the BCD entry, which is where the Baseline computation reads from anyway.
WPT is the evidence you can execute
The useful thing about Web Platform Tests is that they connect to web-features directly. WPT directories carry WEB_FEATURES.yml files that map test files to web-features ids. The one in dom/abort maps abort-signal-any.any.js to both abortsignal-any and aborting, and everything else in the directory to aborting.
That turns "is it Baseline?" into a second question you can answer with data: do the mapped tests pass in all four engines? For AbortSignal.any() they do. A wpt.fyi search over the four desktop stable runs of 2026-10-17 returns 14 of 14 subtests passing in each browser, in both the window and worker variants. For top-level await, as shown above, the two questions had different answers for the eleven months or so that the badge said widely available.
Here's the query as a script. It takes the latest stable desktop runs and prints pass counts for any test path you give it. I ran it with Node 24.18.0 on 2026-10-18; the counts above are its output.
// Node 22+. Usage: node wpt.mjs /dom/abort/abort-signal-any
const path = process.argv[2];
const WPT = 'https://wpt.fyi/api';
const runs = await (await fetch(
`${WPT}/runs?label=master&label=stable&max-count=1`)).json();
const res = await fetch(`${WPT}/search`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
run_ids: runs.map((run) => run.id),
query: { exists: [{ pattern: path }] },
}),
});
const { results } = await res.json();
const names = runs.map((r) => `${r.browser_name} ${r.browser_version}`);
for (const { test, legacy_status: perRun } of results) {
const cells = perRun.map((s, i) => `${names[i]}: ${s.passes}/${s.total}`);
console.log(test, '\n ' + cells.join('\n '));
}Two caveats. A test path is a substring match, so /dom/abort/abort-signal-any also matches the crash test in that directory, which reports no subtests. And this tells you about desktop engines only; add product=chrome_android or product=firefox_android to the runs query if mobile matters to you, and remember the dates on those runs.
Standards positions hint at how long "limited" will last
Baseline describes the present. When a feature is limited, the useful question is how long it will stay that way, and the best public signal is whether the missing engine has said it wants the feature.
Mozilla publishes positions on proposed features, and WebKit does the same in its standards-positions repository. A positive position from the engine you're waiting on is the strongest public signal that it intends to build the feature. A request that sits for years without a position tells you it isn't near the top of anyone's list. webstatus.dev saves you a step: its feature API returns a vendor_positions array with links to the threads.
The scheduler is the example. Mozilla's thread on scheduler.postTask concluded in October 2021 that the API was worth prototyping, and it carries a positive label today; scheduler.yield() was labelled positive in June 2024. Firefox shipped the API in 142. For this feature, the webstatus.dev API lists exactly one vendor position, Mozilla's positive one. WebKit's request for a position on Prioritized Task Scheduling was opened on 2024-06-07 and, as of 2026-10-18, is still open with no position label. The thread includes WebKit feedback on the naming of yield() and related methods. That's engagement, not commitment.
Compare Temporal. The missing engine is the same, but Temporal is a finished TC39 proposal and BCD already lists Safari's support as "preview". Both features are limited today. I'd plan for those two waits to be very different lengths, and the positions data and the preview builds are why.
Six checks turn a badge into a decision
Put together, the check I'd run before dropping a polyfill or adopting an API looks like this:
- Find the feature id on webstatus.dev and read the API response, not only the badge: status, low and high dates, and which browser was last.
- Read the
.yml.distfile in web-features for the BCD keys, and the source.ymlfor acompute_frompin, an override, or a regression note in the comments. - Open the BCD entries for the keys you actually use. Look for
partial_implementation, flags and notes. Check the per-key status inby_compat_key. - Run the mapped WPT tests through wpt.fyi, desktop and, if your traffic is mobile-heavy, the mobile products.
- If it's limited, check both standards-positions repositories for the missing engine, starting from the
vendor_positionsin the API response. - Decide with your own analytics. Baseline's own document says it won't replace site-specific analysis.
Steps 1 to 3 automate well. This script reads the web-features and @mdn/browser-compat-data packages, fetches the live status from webstatus.dev, and lists any core-browser entry that BCD qualifies as partial, flagged, prefixed or renamed, the four qualifications compute-baseline counts as no support. I ran it with Node 24.18.0, web-features 3.43.0 and @mdn/browser-compat-data 8.1.6 on 2026-10-18. It uses JSON import attributes, which need a recent Node.
// Node 22+. npm i web-features @mdn/browser-compat-data
import { features } from 'web-features';
import bcd from '@mdn/browser-compat-data' with { type: 'json' };
const CORE = ['chrome', 'chrome_android', 'edge', 'firefox',
'firefox_android', 'safari', 'safari_ios'];
// Walk a dotted BCD key such as "api.GPU.requestAdapter".
function compatAt(key) {
return key.split('.').reduce((node, part) => node?.[part], bcd)
?.__compat;
}
// What compute-baseline treats as "not supported".
const QUALIFIERS = ['partial_implementation', 'flags', 'prefix',
'alternative_name'];
// Core browsers whose newest statement carries a qualifier.
function qualified(key) {
const support = compatAt(key)?.support ?? {};
const hits = [];
for (const browser of CORE) {
// The npm package has mirrors resolved, so every entry is real data.
const entry = [support[browser]].flat()[0];
const found = QUALIFIERS.filter((q) => entry?.[q]);
if (found.length) {
hits.push(`${browser} ${entry.version_added} ${found.join('+')}`);
}
}
return hits;
}The second half compares the package with the live API and prints a short report per feature:
async function audit(id) {
const feature = features[id];
const res = await fetch(`https://api.webstatus.dev/v1/features/${id}`);
const live = await res.json();
const notes = feature.compat_features.flatMap(
(key) => qualified(key).map((hit) => `${key}: ${hit}`));
console.log(id, {
package: feature.status.baseline,
webstatus: live.baseline?.status,
lowDate: live.baseline?.low_date ?? null,
keys: feature.compat_features.length,
qualified: [...new Set(notes)].slice(0, 3),
});
}
for (const id of ['navigation', 'temporal', 'webgpu',
'top-level-await', 'abortsignal-any', 'scheduler']) {
await audit(id);
}On 2026-10-18 it reported webgpu as false with 301 keys and api.GPU: firefox 141 partial_implementation first in the list, temporal as false with 243 keys and Firefox partial entries on withCalendar, top-level-await and navigation as low with no qualified entries, abortsignal-any as high, and scheduler as false with nothing qualified, since its problem is a missing engine rather than a partial one. The package and the live API agreed on all six (remember that low is newly and high is widely). When they don't, one of them is behind, and it's usually your lockfile.
Two limits worth knowing. The script reads only the first support statement per browser, which in every entry I checked is the current one, so it won't show a qualification that applied to older releases. And it walks every key in compat_features, so for a feature pinned with compute_from it reports qualifications the headline ignores. That's deliberate: those are the keys you might be calling.
What I'd do with a Baseline badge tomorrow
If you're dropping a polyfill, require widely available for the keys you call, not only for the feature group, and read the BCD notes. Widely available is a 30-month cushion. Newly available is the day the last engine shipped, which means users on that engine's previous release don't have it.
If you're adopting a newly available feature with a large surface, like the Navigation API, read the mapped WPT scores before you commit. A 0.795 score in one engine's stable channel is a reason to write integration tests on that engine for your exact flows, not a reason to wait.
If a feature is limited and you're deciding whether to wait, check the missing engine's standards position. A finished standard with a preview build (Temporal) and a WICG spec with an open position request (Scheduler) are not the same bet.
If you maintain a library, pin web-features deliberately and update it on a schedule, because the status you document comes from the package version you ran. And add a WPT check to your support matrix for anything you call out as Baseline. The top-level-await case shows the tests can be right while the badge is wrong.
What we don't know
- Whether the owners group reviewed the definition on schedule. The document said review was due on 9 September 2026. On 2026-10-18 the file hadn't changed since February 2026 and still carried that date. I couldn't find a record of the review's outcome.
- What the ESR clause means, and whether it will ever be enforced. Issue #4009 and PR #4010 were open on 2026-10-18. One project collaborator says no code checks it; another says ESR 115 shouldn't count. Until the text changes, the rule as written and the rule as computed differ.
- How a change to the core browser set would re-date existing features. The definition says this is "not yet defined" and points to issue #2133, still open.
- What happens to pinned headlines when
compute_fromgoes. The guidelines call it deprecated and planned for removal. WebGPU, Temporal and the Navigation API all use it today. If those headlines are recomputed from every key, some could move, and I found no published plan for how that migration would be dated or announced. - Whether Firefox WebGPU will become full support in BCD, and at which platform the editors will draw that line. Mozilla's post says Linux and Android are planned; BCD's notes say Linux and Intel macOS are unsupported as of today.
- Whether webstatus.dev keeps an audit trail of old keystone dates after a retroactive BCD change. For top-level await I reconstructed the history from old npm packages; I didn't find a place where webstatus.dev shows that the feature was once widely available.
- Whether the failing WPT tests for top-level await share a root cause with WebKit bug 242740. The timing matches (both resolved with Safari 27), and WebKit's release post says the new loader was validated against the Web Platform Tests, but I haven't confirmed the link from the WebKit side. Comparing the fix the bug points to, 311236@main, with the test's expectations would settle it.
- What Safari on iOS passes in WPT. The runs API rejected
safari_ios, and I found no other product name for it. Baseline counts iOS Safari as its own browser, but webstatus.dev reports no separate WPT score for it, so any test evidence for iOS is inferred from macOS Safari.
References
- Baseline. web.dev (Google)>. Accessed .
- web-features: Baseline (status definition). WebDX Community Group>. Accessed .
- web-features docs/baseline.md commit history. WebDX Community Group>. Accessed .
- WPT module/top-level-await commit history. Web Platform Tests>. Accessed .
- web-platform-dx/web-features. WebDX Community Group>. Accessed .
- web-features on npm (versions and release dates). npm registry>. Accessed .
- web-features 2.13.0 data.json (historical package). unpkg / npm>. Accessed .
- web-features 2.34.0 data.json (historical package). unpkg / npm>. Accessed .
- web-features 3.6.0 data.json (historical package). unpkg / npm>. Accessed .
- web-features 3.7.0 data.json (historical package). unpkg / npm>. Accessed .
- web-features 3.38.0 data.json (historical package). unpkg / npm>. Accessed .
- web-features 3.39.0 data.json (historical package). unpkg / npm>. Accessed .
- web-features 3.40.0 data.json (historical package). unpkg / npm>. Accessed .
- compute-baseline: baseline/index.ts. WebDX Community Group>. Accessed .
- compute-baseline: baseline/support.ts. WebDX Community Group>. Accessed .
- compute-baseline: browser-compat-data/feature.ts. WebDX Community Group>. Accessed .
- web-features feature guidelines: Status overrides. WebDX Community Group>. Accessed .
- Definition of baseline high ESR clause is unclear (issue #4009). WebDX Community Group>. Accessed .
- Clarify Baseline High ESR clause (PR #4010). WebDX Community Group>. Accessed .
- Define how the core browser set was determined (issue #2133). WebDX Community Group>. Accessed .
- Baseline status regressions should require a note (issue #1971). WebDX Community Group>. Accessed .
- Reconsideration: allow top-level await status regression (issue #2957). WebDX Community Group>. Accessed .
- Add various JavaScript features (PR #2417). WebDX Community Group>. Accessed .
- Bump @mdn/browser-compat-data from 6.0.9 to 6.0.11 (PR #2921). WebDX Community Group>. Accessed .
- Bump @mdn/browser-compat-data from 6.0.11 to 6.0.13 (PR #2954, adds the top-level await override). WebDX Community Group>. Accessed .
- Revert top-level await status override (PR #3483). WebDX Community Group>. Accessed .
- web-features webgpu.yml. WebDX Community Group>. Accessed .
- web-features webgpu.yml.dist. WebDX Community Group>. Accessed .
- web-features temporal.yml. WebDX Community Group>. Accessed .
- web-features navigation.yml. WebDX Community Group>. Accessed .
- web-features top-level-await.yml. WebDX Community Group>. Accessed .
- web-features scheduler.yml.dist. WebDX Community Group>. Accessed .
- mdn/browser-compat-data. MDN>. Accessed .
- BCD api/GPU.json. MDN>. Accessed .
- BCD api/Navigator.json. MDN>. Accessed .
- BCD javascript/operators/await.json. MDN>. Accessed .
- BCD javascript/builtins/Temporal.json. MDN>. Accessed .
- BCD javascript/builtins/Temporal/PlainDate.json. MDN>. Accessed .
- BCD browsers/safari.json. MDN>. Accessed .
- Safari only partially supports top-level await (BCD PR #26510). MDN>. Accessed .
- Safari 27 correctly supports top-level await in modules (BCD PR #29838). MDN>. Accessed .
- Web Platform Status: Navigation API. Web Platform Status (webstatus.dev)>. Accessed .
- Web Platform Status: Temporal. Web Platform Status (webstatus.dev)>. Accessed .
- Web Platform Status: WebGPU. Web Platform Status (webstatus.dev)>. Accessed .
- Web Platform Status: Top-level await. Web Platform Status (webstatus.dev)>. Accessed .
- Web Platform Status: AbortSignal.any(). Web Platform Status (webstatus.dev)>. Accessed .
- Web Platform Status: Scheduler API. Web Platform Status (webstatus.dev)>. Accessed .
- webstatus.dev API: scheduler. Web Platform Status (webstatus.dev)>. Accessed .
- webstatus.dev API: top-level-await WPT test counts, Safari stable. Web Platform Status (webstatus.dev)>. Accessed .
- Fixing Top-Level Await in Safari. WebKit>. Accessed .
- WebKit Features for Safari 27.0. WebKit>. Accessed .
- Bug 242740 - [JSC] ReferenceError when multiple modules are simultaneously importing a module containing a top-level await. WebKit Bugzilla>. Accessed .
- Shipping WebGPU on Windows in Firefox 141. Mozilla Gfx Team blog>. Accessed .
- wpt.fyi API: latest stable runs. Web Platform Tests>. Accessed .
- wpt.fyi API: latest stable chrome_android run. Web Platform Tests>. Accessed .
- wpt.fyi API: latest stable firefox_android run. Web Platform Tests>. Accessed .
- WPT dom/abort/WEB_FEATURES.yml. Web Platform Tests>. Accessed .
- WPT module/top-level-await/WEB_FEATURES.yml. Web Platform Tests>. Accessed .
- WPT sibling-imports-not-blocked.any.js. Web Platform Tests>. Accessed .
- Interop 2026: Mobile testing. Interop project>. Accessed .
- Firefox versions (product-details). Mozilla>. Accessed .
- Firefox major release dates (product-details). Mozilla>. Accessed .
- Mozilla standards positions. Mozilla>. Accessed .
- Scheduling APIs: scheduler.postTask (Mozilla standards-positions #546). Mozilla>. Accessed .
- Prioritized Task Scheduling: scheduler.yield() (Mozilla standards-positions #1039). Mozilla>. Accessed .
- WebKit standards positions. WebKit>. Accessed .
- Prioritized Task Scheduling (WebKit standards-positions #361). WebKit>. Accessed .
- Finished Proposals. Ecma TC39>. Accessed .