# Obfuscate a browser extension before you publish it

A published extension is a zip anyone can unpack and read. What obfuscating the background and content scripts changes, and the store policy to check before you ship one.

Source: https://www.afterpack.dev/docs/use-cases/browser-extensions

Anyone can unzip a published extension and read everything inside it. Whether you are allowed to ship an obfuscated one depends on the store.

## A published extension is a downloadable copy of your source

A published extension is a downloadable copy of your source. The package a store serves is a zip file, and unpacking one is a right click. The background script, the content scripts and any bundled logic are then ordinary files on disk. Anyone can read the interesting part, lift it, and reupload a fork under another name.

## Check the store policy first

Store policy decides whether you can ship an obfuscated extension at all. The restrictions differ by store and they change, and a reviewer may require you to submit readable or original sources alongside the package you upload. Read your store's current policy before you ship an obfuscated build, and plan for a source archive being asked for.

Obfuscation is not a way to get a build through review or to keep what your extension does away from a reviewer. If a store asks what the code does, answer that question.

## What an obfuscated extension build changes

Where an obfuscated build is allowed, the output fits what the platform requires of it. It runs without `eval`, which an extension's content-security-policy forbids.

Every build draws a fresh [`seed`](https://www.afterpack.dev/docs/config#seed) and comes out in a different shape. A fork or a patch someone built against one version of your package does not carry over to the next version you publish.

## Run it over the packed output

Run the CLI over your built output directory as a post-build step, or use the AfterPack plugin for your bundler when one is wired in:

```bash
npx afterpack@latest dist/ --preset=hard
```

Only `.js`, `.mjs` and `.cjs` files are collected, so `manifest.json` and anything under `_locales/` passes through untouched. Use [`paths.exclude`](https://www.afterpack.dev/docs/config#paths-exclude) for a vendored SDK you want left alone, and [`paths.include`](https://www.afterpack.dev/docs/config#paths-include) to reach a `node_modules/` copy bundled into the package. If a symbol name has to stay the same across your own files, pin it with [`identifiers.reserved`](https://www.afterpack.dev/docs/config#identifiers-reserved).

Build every context in one run, background service worker and content scripts together, so they share a seed and the message types both sides depend on stay in agreement.

## Check the package before you zip it

Open the [Protection Map](https://www.afterpack.dev/docs/protection-map) after a build to confirm the scripts you meant to protect were covered. Keep [`sourceMap.enabled`](https://www.afterpack.dev/docs/config#sourceMap-enabled) off for the package you upload, since a map inside the zip is as complete a source read as shipping the original files. Run [`afterpack verify`](https://www.afterpack.dev/docs/cli#afterpack-verify-dir) on the directory you are about to zip, so a build where protection did not apply fails before it reaches the store.

## What this does not stop for an extension

A new shape on every release raises the cost of keeping a fork or a patch current with your extension, and that cost is paid again each time you publish.

It does not stop anyone reading, forking or reuploading the package, and a key or token inside the extension is not made safe by being encoded. [What to do about an API key you must ship](https://www.afterpack.dev/docs/use-cases/shipped-api-keys) covers that case.

## Next

- [CLI reference](https://www.afterpack.dev/docs/cli): running AfterPack as a post-build step.
- [Quickstart](https://www.afterpack.dev/docs/quickstart): a first build before you have a pipeline.
- [Shipped API keys](https://www.afterpack.dev/docs/use-cases/shipped-api-keys): what obfuscation does and does not do for a credential in the bundle.
