# Browser Feature Compatibility Lookup for Coding Agents (`grit-77/browser-feature-lookup`) Actor

Browser feature compatibility lookup from pinned MDN browser-compat-data. Export JSON rows per feature and browser with original support statements for coding-agent evidence.

- **URL**: https://apify.com/grit-77/browser-feature-lookup.md
- **Developed by:** [Grit](https://apify.com/grit-77) (community)
- **Categories:** Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.05 / 1,000 compatibility lookups

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Browser Feature Compatibility Lookup for Coding Agents

Retrieve exact browser support records from pinned official MDN JSON, with one row per requested feature/browser and the original support statements intact.

Use this Actor when a coding agent needs structured evidence about a web API, CSS feature, HTML feature or JavaScript built-in. It reads JSON from the official [mdn/browser-compat-data](https://github.com/mdn/browser-compat-data) repository. It does not determine whether your application works in every browser.

### What it returns

| Field | Meaning |
|---|---|
| `featurePath` | Exact, case-sensitive BCD path, for example `api.AbortController`. |
| `browser` | Exact BCD browser identifier, for example `chrome`, `firefox`, `safari`. |
| `versionAdded` | Original `version_added` string, boolean or null; an aligned array if the source has multiple statements. |
| `versionRemoved` | Original `version_removed`, or null when absent; aligned array for array support. |
| `partialImplementation` | Original partial flag, or null when absent; aligned array for array support. |
| `flags` | Original flag objects, or null when absent; array of per-statement flag values for array support. |
| `experimental`, `deprecated`, `standardTrack` | Feature status booleans; null if unavailable. |
| `supportStatements` | Original statement objects, including notes, prefixes, alternative names, flags and implementation links. |
| `rawSupport` | Exact original support object, array or `mirror` marker. |
| `lookupStatus` | `ok`, `error`, or `unresolved_mirror`. |
| `error` | Null on explicit successful records; otherwise a code and clear message. |
| `sourceRelease`, `sourceCommit` | Pinned official data release and full immutable commit. |
| `sourceFile`, `sourceUrl` | Verified official JSON file and its commit-specific raw URL. Null for an unmapped feature. |
| `retrievedAt` | UTC timestamp when the returned row was assembled. |

The original statement objects distinguish absent keys from explicit null values. An absent removal version does not prove a feature remains usable everywhere. `false` means the source records no support; `true` means support without a known version; null means unknown. Strings such as `preview` and `≤37` remain strings. No version comparison or universal compatibility verdict is added.

#### Raw mirror records

Some upstream JSON records contain the string `mirror`. MDN's package build expands these using browser-specific release metadata. This Actor preserves the marker and returns `lookupStatus: "unresolved_mirror"`, null version projections and an explicit uncharged error. It does not copy a desktop browser version into a different browser's row. This commonly affects mobile browsers and Chromium derivatives.

### Input

The Store prefill is:

```json
{
  "feature": "api.AbortController",
  "browsers": ["chrome", "firefox", "safari"],
  "maxItems": 3
}
```

For a batch, supply `features`; it can be combined with `feature`, with duplicate paths removed in first-occurrence order:

```json
{
  "features": ["api.AbortSignal.timeout", "css.properties.grid", "html.elements.input.type_color.accepts_css_colors"],
  "browsers": ["chrome", "firefox", "safari"],
  "maxItems": 9,
  "concurrency": 4
}
```

| Input | Default / limit |
|---|---|
| `feature` / `features` | At least one is required; up to 100 requested paths across both fields, each at most 256 characters. |
| `browsers` | Defaults to Chrome, Firefox and Safari; 1–32 identifiers before deduplication. |
| `maxItems` | Defaults to 100; 1–1,000 output rows, including error rows. |
| `concurrency` | Defaults to 4; 1–8 simultaneous JSON requests. |

Browser identifiers in this release: `bun`, `chrome`, `chrome_android`, `deno`, `edge`, `firefox`, `firefox_android`, `ie`, `nodejs`, `oculus`, `opera`, `opera_android`, `safari`, `safari_ios`, `samsunginternet_android`, `webview_android`, `webview_ios`. A browser can be valid globally but absent from a particular feature's support block.

#### Verified feature scope

The current mapping covers **1,268 compatibility paths in 36 targeted JSON files**, validated from the actual JSON keys and Git blob hashes. It includes selected API families (AbortController, AbortSignal, Clipboard, Crypto, Document, Element, FetchEvent, Geolocation, HTMLDialogElement, IntersectionObserver, Navigator, ReadableStream, ResizeObserver, ServiceWorker, URL, USB, WebSocket and Window), selected CSS properties/selectors/color data, dialog/input-color/script HTML data, and Array/Promise/Intl/Object/RegExp/Temporal built-ins.

The complete supported path inventory is `data/source_pin.json` → `featurePaths`. This is a bounded mapping, not the full MDN dataset. Paths such as `html.elements.input.type_color` use the dataset's actual keys, not a guessed path from a filename. Unmapped paths return `unmapped_feature`; a missing child under a mapped family returns `feature_not_found`. Results follow feature order, then browser order; the final feature can be partially returned when `maxItems` is reached.

### Output example

This excerpt comes from the real local `sample_output.json`:

```json
{
  "featurePath": "api.AbortController",
  "browser": "safari",
  "versionAdded": ["12.1", "11.1"],
  "versionRemoved": [null, "12.1"],
  "partialImplementation": [null, true],
  "flags": [null, null],
  "experimental": false,
  "deprecated": false,
  "standardTrack": true,
  "lookupStatus": "ok",
  "error": null
}
```

The complete row retains both original support statements, including the note that the earlier Safari implementation does not really abort fetch requests. Download the dataset as JSON to preserve nested structures and version types; flattened CSV exports may lose those distinctions.

### Pricing

Proposed event `compatibility_lookup`: **$0.00005 per successful explicit feature/browser row ($0.05 per 1,000)**. One browser row with multiple statements is one event. Error rows and unresolved mirrors are free. No Actor-start event is proposed. Pricing is not configured or published by this local build; platform fees depend on the eventual Store setup. See `PRICING.md` for dated Store evidence, the adjacent comparison and billing limitations.

### Source pin and bounded refresh

The data pin is **v8.1.4**, commit **7e64a56d3689f03f7e0ad911f603cf71c5b3c7c4**. Runtime requests use that full commit, not `main` or a floating latest release. Each targeted file is memoized once per run, with at most three attempts for transient transport, HTTP 429 and HTTP 5xx failures; delays are 0.5 and 1 second. A response is limited to 4 MiB and must match its pinned Git blob hash. There is no persistent runtime cache or automatic release change.

A maintainer can explicitly refresh the same targeted files to a named official release:

```powershell
C:/GritWork/earn/.venv/Scripts/python -m tools.refresh_pin --release v8.1.4
```

This command resolves the tag, checks the official tree, fetches at most 64 selected files with concurrency four and three-attempt bounds, reconstructs mappings from actual JSON keys, and replaces the pin only after the downloads verify. It uses two metadata endpoints (three for an annotated tag), each with the same attempt cap. Missing files or a truncated tree abort the refresh. Review changes, rerun tests, and regenerate the sample before publishing a newer data pin.

The dataset is licensed [CC0 1.0](https://github.com/mdn/browser-compat-data/blob/7e64a56d3689f03f7e0ad911f603cf71c5b3c7c4/LICENSE); a copy accompanies the pin. This Actor is not affiliated with MDN. It fetches no MDN article prose, screenshots or package download metrics.

### Local run and verification

Use the existing earn virtual environment; no extra package installation is needed for local tests. Docker installs the declared Apify/httpx dependencies from `requirements.txt`.

```powershell
$env:APIFY_LOCAL_STORAGE_DIR = "$PWD/storage"
New-Item -ItemType Directory -Force storage/key_value_stores/default | Out-Null
'{"feature":"api.AbortController","browsers":["chrome","firefox","safari"],"maxItems":3}' | Set-Content -Encoding utf8 storage/key_value_stores/default/INPUT.json
C:/GritWork/earn/.venv/Scripts/python -m src
C:/GritWork/earn/.venv/Scripts/python -m pytest tests -m "not live" -q -p no:cacheprovider
C:/GritWork/earn/.venv/Scripts/python -m pytest tests -m live -q -p no:cacheprovider
apify validate-schema
```

Local dataset rows are stored under `storage/datasets/default`. `SUMMARY` in the default key-value store records emitted rows, explicit/error rows, charged events and elapsed time. Local non-PPE execution calls the charge boundary but charges zero events; it is not a cloud settlement test. Use fresh local storage when measuring a run, because a repeated run can append to an existing dataset.

### Use with AI agents / MCP

Once the owner publishes the Actor, an agent can invoke it using Apify's [MCP integration](https://docs.apify.com/platform/integrations/mcp) or the Actor API, then read the default dataset's JSON items. No separate MCP server is included here. Supply exact BCD feature paths, check `lookupStatus` and `error` first, inspect all `supportStatements` and record `sourceCommit` with any recommendation. A `mirror` row, flag or partial implementation needs additional investigation; feature records do not establish whole-application compatibility.

### FAQ

**Can I paste an MDN article URL?** No. Supply exact feature paths from the verified inventory. The Actor intentionally retrieves open JSON data rather than article content.

**Why did a valid browser return an error?** A feature may omit that browser, or its raw record may delegate to `mirror`. Neither case is converted to false support.

**Does an unknown feature stop the batch?** Unknown paths, missing records and source failures become individual uncharged rows. Malformed top-level input fails with a clear validation message.

**How fresh is the data?** Every row states its pinned release and commit. New MDN edits are not used until an explicit pin refresh and rebuild.

**Are flags and historical removals discarded?** No. Original statements remain in order, and projected array fields remain aligned with those statements.

# Actor input Schema

## `feature` (type: `string`):

Exact BCD feature path in the verified mapping. Use features for a batch; values from both fields are combined and deduplicated.

## `features` (type: `array`):

Optional batch of exact feature paths; at most 100 paths across both feature fields. Supported paths are listed in data/source_pin.json.

## `browsers` (type: `array`):

Exact lowercase BCD browser identifiers. Unknown or absent browsers return uncharged error rows. Raw mirror records are explicit unresolved rows.

## `maxItems` (type: `integer`):

Hard cap on all feature/browser rows, including errors, before any downloads. Partial final feature is allowed.

## `concurrency` (type: `integer`):

Maximum simultaneous official JSON file requests. Repeated paths are fetched once per run.

## Actor input object example

```json
{
  "feature": "api.AbortController",
  "browsers": [
    "chrome",
    "firefox",
    "safari"
  ],
  "maxItems": 3,
  "concurrency": 4
}
```

# Actor output Schema

## `dataset` (type: `string`):

JSON feature/browser rows including all support statements and explicit lookup errors.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "feature": "api.AbortController",
    "browsers": [
        "chrome",
        "firefox",
        "safari"
    ],
    "maxItems": 3
};

// Run the Actor and wait for it to finish
const run = await client.actor("grit-77/browser-feature-lookup").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "feature": "api.AbortController",
    "browsers": [
        "chrome",
        "firefox",
        "safari",
    ],
    "maxItems": 3,
}

# Run the Actor and wait for it to finish
run = client.actor("grit-77/browser-feature-lookup").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "feature": "api.AbortController",
  "browsers": [
    "chrome",
    "firefox",
    "safari"
  ],
  "maxItems": 3
}' |
apify call grit-77/browser-feature-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,grit-77/browser-feature-lookup"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/YXw8oSJ6Wh4PACNTf/builds/C0NjhrIkS7X4961Vb/openapi.json
