{"id":13424892,"url":"https://github.com/mozilla/webextension-polyfill","last_synced_at":"2025-05-15T00:03:55.375Z","repository":{"id":38868619,"uuid":"70184134","full_name":"mozilla/webextension-polyfill","owner":"mozilla","description":"A lightweight polyfill library for Promise-based WebExtension APIs in Chrome","archived":false,"fork":false,"pushed_at":"2025-05-07T08:43:06.000Z","size":337,"stargazers_count":2884,"open_issues_count":45,"forks_count":219,"subscribers_count":44,"default_branch":"master","last_synced_at":"2025-05-07T23:37:18.160Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mozilla.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-10-06T19:02:50.000Z","updated_at":"2025-05-07T04:29:24.000Z","dependencies_parsed_at":"2024-01-08T05:06:15.626Z","dependency_job_id":"eff16ef4-ab1d-49ff-ab13-eaf33dfa1c45","html_url":"https://github.com/mozilla/webextension-polyfill","commit_stats":{"total_commits":262,"total_committers":33,"mean_commits":"7.9393939393939394","dds":0.7519083969465649,"last_synced_commit":"6a42cbeaf637ba3f1283bdcdd657afd06454ca55"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla%2Fwebextension-polyfill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla%2Fwebextension-polyfill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla%2Fwebextension-polyfill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla%2Fwebextension-polyfill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mozilla","download_url":"https://codeload.github.com/mozilla/webextension-polyfill/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253775404,"owners_count":21962342,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T00:01:00.616Z","updated_at":"2025-05-15T00:03:55.307Z","avatar_url":"https://github.com/mozilla.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Libraries and Frameworks","Packages","Tools"],"sub_categories":["Development","Safari Related"],"readme":"# WebExtension `browser` API Polyfill\n\nThis library allows extensions that use the Promise-based WebExtension/BrowserExt API being standardized by the\n[W3 Browser Extensions][w3-browserext] group to run on Google Chrome with minimal or no changes.\n\n[![CircleCI](https://circleci.com/gh/mozilla/webextension-polyfill.svg?style=svg)](https://circleci.com/gh/mozilla/webextension-polyfill)\n[![codecov](https://codecov.io/gh/mozilla/webextension-polyfill/branch/master/graph/badge.svg)](https://codecov.io/gh/mozilla/webextension-polyfill)\n[![devDependency Status](https://david-dm.org/mozilla/webextension-polyfill/dev-status.svg)](https://david-dm.org/mozilla/webextension-polyfill#info=devDependencies)\n[![npm version](https://badge.fury.io/js/webextension-polyfill.svg)](https://badge.fury.io/js/webextension-polyfill)\n\n\u003e This library doesn't (and it is not going to) polyfill API methods or options that are missing on Chrome but natively provided\n\u003e on Firefox, and so the extension has to do its own \"runtime feature detection\" in those cases (and then eventually polyfill the\n\u003e missing feature on its own or enable/disable some of the features accordingly).\n\n[w3-browserext]: https://www.w3.org/community/browserext/\n\nTable of contents\n=================\n\n* [Supported Browsers](#supported-browsers)\n* [Installation](#installation)\n* [Basic Setup](#basic-setup)\n  * [Basic Setup with ES6 module loader](#basic-setup-with-es6-module-loader)\n  * [Basic Setup with module bundlers](#basic-setup-with-module-bundlers)\n  * [Usage with webpack without bundling](#usage-with-webpack-without-bundling)\n* [Using the Promise-based APIs](#using-the-promise-based-apis)\n* [Examples](#examples)\n* [Usage with TypeScript](#usage-with-typescript)\n* [Known Limitations and Incompatibilities](#known-limitations-and-incompatibilities)\n* [Contributing to this project](#contributing-to-this-project)\n\nSupported Browsers\n==================\n\n| Browser                   | Support Level                                                                                      |\n| ------------------------- | -------------------------------------------------------------------------------------------------- |\n| Chrome                    | *Officially Supported* (with automated tests)                                                        |\n| Firefox                   | *Officially Supported as a NO-OP* (with automated tests for comparison with the behaviors on Chrome) |\n| Opera / Edge (\u003e=79.0.309) | *Unofficially Supported* as a Chrome-compatible target (but not explicitly tested in automation)     |\n\nThe polyfill is being tested explicitly (with automated tests that run on every pull request) on **officially supported**\nbrowsers (that are currently the last stable versions of Chrome and Firefox).\n\nOn Firefox, this library is actually acting as a NO-OP: it detects that the `browser` API object is already defined\nand it does not create any custom wrappers.\nFirefox is still included in the automated tests, to ensure that no wrappers are being created when running on Firefox,\nand for comparison with the behaviors implemented by the library on Chrome.\n\n## Installation\n\nA new version of the library is built from this repository and released as an npm package.\n\nThe npm package is named after this repo: [webextension-polyfill](https://www.npmjs.com/package/webextension-polyfill).\n\nFor the extension that already include a package.json file, the last released version of this library can be quickly installed using:\n\n```\nnpm install --save-dev webextension-polyfill\n```\n\nInside the `dist/` directory of the npm package, there are both the minified and non-minified builds (and their related source map files):\n\n- node_modules/webextension-polyfill/dist/browser-polyfill.js\n- node_modules/webextension-polyfill/dist/browser-polyfill.min.js\n\nFor extensions that do not include a package.json file and/or prefer to download and add the library directly into their own code repository, all the versions released on npm are also available for direct download from unpkg.com:\n\n- https://unpkg.com/webextension-polyfill/dist/\n\nand linked to the Github releases:\n\n- https://github.com/mozilla/webextension-polyfill/releases\n\n## Basic Setup\n\nIn order to use the polyfill, it must be loaded into any context where `browser` APIs are accessed. The most common cases\nare background and content scripts, which can be specified in `manifest.json` (make sure to include the `browser-polyfill.js` script before any other scripts that use it):\n\n```javascript\n{\n  // ...\n\n  \"background\": {\n    \"scripts\": [\n      \"browser-polyfill.js\",\n      \"background.js\"\n    ]\n  },\n\n  \"content_scripts\": [{\n    // ...\n    \"js\": [\n      \"browser-polyfill.js\",\n      \"content.js\"\n    ]\n  }]\n}\n```\n\nFor HTML documents, such as `browserAction` popups, or tab pages, it must be\nincluded more explicitly:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cscript type=\"application/javascript\" src=\"browser-polyfill.js\"\u003e\u003c/script\u003e\n    \u003cscript type=\"application/javascript\" src=\"popup.js\"\u003e\u003c/script\u003e\n  \u003c/head\u003e\n  \u003c!-- ... --\u003e\n\u003c/html\u003e\n```\n\nAnd for dynamically-injected content scripts loaded by `tabs.executeScript`,\nit must be injected by a separate `executeScript` call, unless it has\nalready been loaded via a `content_scripts` declaration in\n`manifest.json`:\n\n```javascript\nbrowser.tabs.executeScript({file: \"browser-polyfill.js\"});\nbrowser.tabs.executeScript({file: \"content.js\"}).then(result =\u003e {\n  // ...\n});\n```\n\n### Basic Setup with ES6 module loader\n\nThe polyfill can also be loaded using the native ES6 module loader available in\nthe recent browsers versions.\n\nBe aware that the polyfill module does not export the `browser` API object,\nbut defines the `browser` object in the global namespace (i.e. `window`).\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cscript type=\"module\" src=\"browser-polyfill.js\"\u003e\u003c/script\u003e\n    \u003cscript type=\"module\" src=\"background.js\"\u003e\u003c/script\u003e\n  \u003c/head\u003e\n  \u003c!-- ... --\u003e\n\u003c/html\u003e\n```\n\n```javascript\n// In background.js (loaded after browser-polyfill.js) the `browser`\n// API object is already defined and provides the promise-based APIs.\nbrowser.runtime.onMessage.addListener(...);\n```\n\n### Basic Setup with module bundlers\n\nThis library is built as a **UMD module** (Universal Module Definition), and so it can also be used with module bundlers (and explicitly tested on both **webpack** and **browserify**) or AMD module loaders.\n\n**src/background.js**:\n```javascript\nvar browser = require(\"webextension-polyfill\");\n\nbrowser.runtime.onMessage.addListener(async (msg, sender) =\u003e {\n  console.log(\"BG page received message\", msg, \"from\", sender);\n  console.log(\"Stored data\", await browser.storage.local.get());\n});\n\nbrowser.browserAction.onClicked.addListener(() =\u003e {\n  browser.tabs.executeScript({file: \"content.js\"});\n});\n```\n\n**src/content.js**:\n```javascript\nvar browser = require(\"webextension-polyfill\");\n\nbrowser.storage.local.set({\n  [window.location.hostname]: document.title,\n}).then(() =\u003e {\n  browser.runtime.sendMessage(`Saved document title for ${window.location.hostname}`);\n});\n```\n\nBy using `require(\"webextension-polyfill\")`, the module bundler will use the non-minified version of this library, and the extension is supposed to minify the entire generated bundles as part of its own build steps.\n\nIf the extension doesn't minify its own sources, it is still possible to explicitly ask the module bundler to use the minified version of this library, e.g.:\n\n```javascript\nvar browser = require(\"webextension-polyfill/dist/browser-polyfill.min\");\n\n...\n```\n\n### Usage with webpack without bundling\n\nThe previous section explains how to bundle `webextension-polyfill` in each script. An alternative method is to include a single copy of the library in your extension, and load the library as shown in [Basic Setup](#basic-setup). You will need to install [copy-webpack-plugin](https://www.npmjs.com/package/copy-webpack-plugin):\n\n```sh\nnpm install --save-dev copy-webpack-plugin\n```\n\n**In `webpack.config.js`,** import the plugin and configure it this way. It will copy the minified file into your _output_ folder, wherever your other webpack files are generated.\n\n```js\nconst CopyWebpackPlugin = require('copy-webpack-plugin');\n\nmodule.exports = {\n  /* Your regular webpack config, probably including something like this:\n  output: {\n    path: path.join(__dirname, 'distribution'),\n    filename: '[name].js'\n  },\n  */\n  plugins: [\n    new CopyWebpackPlugin({\n      patterns: [{\n        from: 'node_modules/webextension-polyfill/dist/browser-polyfill.js',\n      }],\n    })\n  ]\n}\n```\n\nAnd then include the file in each context, using the `manifest.json` just like in [Basic Setup](#basic-setup).\n\n## Using the Promise-based APIs\n\nThe Promise-based APIs in the `browser` namespace work, for the most part,\nvery similarly to the callback-based APIs in Chrome's `chrome` namespace.\nThe major differences are:\n\n* Rather than receiving a callback argument, every async function returns a\n  `Promise` object, which resolves or rejects when the operation completes.\n\n* Rather than checking the `chrome.runtime.lastError` property from every\n  callback, code which needs to explicitly deal with errors registers a\n  separate Promise rejection handler.\n\n* Rather than receiving a `sendResponse` callback to send a response,\n  `onMessage` listeners simply return a Promise whose resolution value is\n  used as a reply.\n\n* Rather than nesting callbacks when a sequence of operations depend on each\n  other, Promise chaining is generally used instead.\n\n* The resulting Promises can be also used with `async` and `await`, rather\n  than dealt with directly.\n\n## Examples\n\nThe following code will retrieve a list of URLs patterns from the `storage`\nAPI, retrieve a list of tabs which match any of them, reload each of those\ntabs, and notify the user that is has been done:\n\n```javascript\nbrowser.storage.local.get(\"urls\").then(({urls}) =\u003e {\n  return browser.tabs.query({url: urls});\n}).then(tabs =\u003e {\n  return Promise.all(\n    Array.from(tabs, tab =\u003e browser.tabs.reload(tab.id))\n  );\n}).then(() =\u003e {\n  return browser.notifications.create({\n    type: \"basic\",\n    iconUrl: \"icon.png\",\n    title: \"Tabs reloaded\",\n    message: \"Your tabs have been reloaded\",\n  });\n}).catch(error =\u003e {\n  console.error(`An error occurred while reloading tabs: ${error.message}`);\n});\n```\n\nOr, using an async function:\n\n```javascript\nasync function reloadTabs() {\n  try {\n    let {urls} = await browser.storage.local.get(\"urls\");\n\n    let tabs = await browser.tabs.query({url: urls});\n\n    await Promise.all(\n      Array.from(tabs, tab =\u003e browser.tabs.reload(tab.id))\n    );\n\n    await browser.notifications.create({\n      type: \"basic\",\n      iconUrl: \"icon.png\",\n      title: \"Tabs reloaded\",\n      message: \"Your tabs have been reloaded\",\n    });\n  } catch (error) {\n    console.error(`An error occurred while reloading tabs: ${error.message}`);\n  }\n}\n```\n\nIt's also possible to use Promises effectively using two-way messaging.\nCommunication between a background page and a tab content script, for example,\nlooks something like this from the background page side:\n\n```javascript\nbrowser.tabs.sendMessage(tabId, \"get-ids\").then(results =\u003e {\n  processResults(results);\n});\n```\n\nAnd like this from the content script:\n\n```javascript\nbrowser.runtime.onMessage.addListener(msg =\u003e {\n  if (msg == \"get-ids\") {\n    return browser.storage.local.get(\"idPattern\").then(({idPattern}) =\u003e {\n      return Array.from(document.querySelectorAll(idPattern),\n                        elem =\u003e elem.textContent);\n    });\n  }\n});\n```\n\nor:\n\n```javascript\nbrowser.runtime.onMessage.addListener(async function(msg) {\n  if (msg == \"get-ids\") {\n    let {idPattern} = await browser.storage.local.get(\"idPattern\");\n\n    return Array.from(document.querySelectorAll(idPattern),\n                      elem =\u003e elem.textContent);\n  }\n});\n```\n\nOr vice versa.\n\n## Usage with TypeScript\n\nThere are multiple projects that add TypeScript support to your web-extension project:\n\n| Project | Description |\n| ------------- | ------------- |\n| [@types/webextension-polyfill](https://www.npmjs.com/package/@types/webextension-polyfill) | Types and JS-Doc are automatically generated from the mozilla schema files, so it is always up-to-date with the latest APIs. Formerly known as [webextension-polyfill-ts](https://github.com/Lusito/webextension-polyfill-ts). |\n| [@types/chrome](https://www.npmjs.com/package/@types/chrome) | Manually maintained types and JS-Doc. Only contains types for chrome extensions though! |\n\n## Known Limitations and Incompatibilities\n\nThis library tries to minimize the amount of \"special handling\" that a cross-browser extension has to do to be able to run on the supported browsers from a single codebase, but there are still cases when polyfillling the missing or incompatible behaviors or features is not possible or out of the scope of this polyfill.\n\nThis section aims to keep track of the most common issues that an extension may have.\n\n### No callback supported by the Promise-based APIs on Chrome\n\nWhile some of the asynchronous API methods in Firefox (the ones that return a promise) also support the callback parameter (mostly as a side effect of the backward compatibility with the callback-based APIs available on Chrome), the Promise-based APIs provided by this library do not support the callback parameter (See [\"#102 Cannot call browser.storage.local.get with callback\"][I-102]).\n\n### No promise returned on Chrome for some API methods\n\nThis library takes its knowledge of the APIs to wrap and their signatures from a metadata JSON file:\n[api-metadata.json](api-metadata.json).\n\nIf an API method is not yet included in this \"API metadata\" file, it will not be recognized.\nPromises are not supported for unrecognized APIs, and callbacks have to be used for them.\n\nChrome-only APIs have no promise version, because extensions that use such APIs\nwould not be compatible with Firefox.\n\nFile an issue in this repository for API methods that support callbacks in Chrome *and*\nFirefox but are currently missing from the \"API metadata\" file.\n\n### Issues that happen only when running on Firefox\n\nWhen an extension that uses this library doesn't behave as expected on Firefox, it is almost never an issue in this polyfill, but an issue with the native implementation in Firefox.\n\n\"Firefox only\" issues should be reported upstream on Bugzilla:\n- https://bugzilla.mozilla.org/enter_bug.cgi?product=WebExtensions\u0026component=Untriaged\n\n### API methods or options that are only available when running in Firefox\n\nThis library does not provide any polyfill for API methods and options that are only available on Firefox, and they are actually considered out of the scope of this library.\n\n### tabs.executeScript\n\nOn Firefox `browser.tabs.executeScript` returns a promise which resolves to the result of the content script code that has been executed, which can be an immediate value or a Promise.\n\nOn Chrome, the `browser.tabs.executeScript` API method as polyfilled by this library also returns a promise which resolves to the result of the content script code, but only immediate values are supported.\nIf the content script code result is a Promise, the promise returned by `browser.tabs.executeScript` will be resolved to `undefined`.\n\n### MSEdge support\n\nMSEdge versions \u003e= 79.0.309 are unofficially supported as a Chrome-compatible target (as for Opera or other Chrome-based browsers that also support extensions).\n\nMSEdge versions older than 79.0.309 are **unsupported**, for extension developers that still have to work on extensions for older MSEdge versions, the MSEdge `--ms-preload` manifest key and the [Microsoft Edge Extension Toolkit](https://docs.microsoft.com/en-us/microsoft-edge/extensions/guides/porting-chrome-extensions)'s Chrome API bridge can be used to be able to load the webextension-polyfill without any MSEdge specific changes.\n\nThe following Github repository provides some additional detail about this strategy and a minimal test extension that shows how to put it together:\n\n- https://github.com/rpl/example-msedge-extension-with-webextension-polyfill\n\n## Contributing to this project\n\nRead the [contributing section](CONTRIBUTING.md) for additional information about how to build the library from this repository and how to contribute and test changes.\n\n[PR-114]: https://github.com/mozilla/webextension-polyfill/pull/114\n[I-102]: https://github.com/mozilla/webextension-polyfill/issues/102#issuecomment-379365343\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmozilla%2Fwebextension-polyfill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmozilla%2Fwebextension-polyfill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmozilla%2Fwebextension-polyfill/lists"}