Download public browser extensions from official stores
extension-from-store

- Chrome Web Store, Microsoft Edge Add-ons, Firefox AMO
- Promise-based API
- Node.js + CLI support
Install
npm i extension-from-storeUsage
Via Node.js:
import {fetchExtensionFromStore} from 'extension-from-store'
const url =
'https://chromewebstore.google.com/detail/adblock-plus-free-ad-bloc/cfhdojbkjhnklbpkdaibdccddilifddb'
const options = {
outDir: './extensions',
userAgent: 'my-tool/1.0.0',
extract: true,
logger: {
onInfo: (message) => console.log(message),
onWarn: (message) => console.warn(message),
onError: (message, error) => console.error(message, error)
}
}
await fetchExtensionFromStore(url, options)Via browser entrypoint:
import {fetchExtensionFromStoreBrowser} from 'extension-from-store/browser'
const result = await fetchExtensionFromStoreBrowser(
'https://chromewebstore.google.com/detail/adblock-plus-free-ad-bloc/cfhdojbkjhnklbpkdaibdccddilifddb',
)
console.log(result.meta)
console.log(result.files.find((file) => file.path === 'manifest.json')?.text)The browser entry keeps everything in memory and returns archive bytes, extracted files, and parsed manifest metadata. It does not write to disk.
Via core helpers:
import {
detectStoreFromUrl,
extractChromeIdFromUrl,
getChromeDownloadUrl,
parseManifestInfo,
stripCrxHeader,
} from 'extension-from-store/core'Via CLI (default command is fetch):
npx extension-from-store --url "<store-item-url>"
npx extension-from-store --url "<store-item-url>" --out ./my-exts
npx extension-from-store --url "<store-item-url>" --version 2.1.0 --extract
npx extension-from-store --url "<store-item-url>" --extractThe store is detected from the URL.
Output
<out>/
<identifier>@<resolved-version>/
extension.meta.json
...
If the target folder already exists, the operation fails.
By default, extension-from-store downloads the archive without extraction. When you pass --extract, it unpacks the archive and writes metadata.
When extraction is disabled, the archive is saved as:
<out>/<identifier>[@<version>].crx
<out>/<identifier>[@<version>].xpi
Extraction Rules
.crx: strip CRX header, extract ZIP payload.xpi: treat as ZIP- No normalization, no rewriting, no formatting
extension.meta.json
{
"store": "chrome | edge | firefox",
"identifier": "<identifier derived from the URL>",
"version": "<resolved version>",
"manifestVersion": 2 | 3
}This file is written by extension-from-store to the same folder as the extracted files.
CLI Flags
| Flag | Required | Description |
|---|---|---|
--url <string> |
Yes | Extension URL |
--out <path> |
No | Output directory (default: ./extensions) |
--version <string> |
No | Version hint |
--user-agent <string> |
No | Override user agent |
--extract |
No | Extract after download (default: download only) |
--quiet |
No | Suppress info logs |
--verbose |
No | Emit verbose info logs |
--json |
No | JSON lines output to stdout |
Logging
Library logging is opt-in via the logger hooks. The library never writes directly to stdout/stderr.
Exit Codes
0success1invalid input2unsupported store3not found / not public4download failed5extraction failed6filesystem conflict7store incompatibility
Related projects
- browser-extension-manifest-fields
- browser-extension-capabilities
- browser-extension-compat-data
- chrome-extension-manifest-json-schema
- parse5-asset-patcher
License
MIT (c) Cezar Augusto.