The AfterPack Blog
announcementjavascript obfuscationsecurityAI

Announcing AfterPack: a free JavaScript obfuscator for the web

by Nikita Savchenko10 min read

Today we're launching three things:

  • AfterPack, a modern JavaScript obfuscator for the AI era. It turns your production build into a different program every time: a new shape on every build, and on every request inside a Cloudflare Worker.
  • A refreshed site scanner that finds what's readable in any website's code: public source maps, readable logic and leaked credentials.
  • An online playground to try AfterPack on your own code, right in your browser.

AfterPack (afterpack.dev), the JavaScript obfuscator, works with any framework. The CLI and plugins are open source, the local engine is free, and Pro cloud builds start at $49 a month. Start with npx afterpack@latest after a build, or ask your coding agent to add it.

Meet AfterPack: a free build tool that makes shipped code unreadable to scanners and people, and a moving target for AI. Every build ships completely different code, so a script written to patch one release — a cheat, a userscript, a bypass — doesn't fit the next. A tool written against your code should stop working at your next release, and now, inside your own Cloudflare Worker, it can stop working at your very next request.

Why obfuscate JavaScript now that AI can read it?

Because whatever AI can read, it can also rewrite and repackage. Point a coding agent at your bundle, and a few minutes later someone holds your pricing rules, your paywall check or your anti-bot logic as clean, editable source, along with a script that patches or bypasses them. That used to be a specialist's job; now it's a prompt. And the patch keeps working for as long as your code keeps its shape. Minification was never hiding that code: the Claude Code "leak" was a readable bundle that had been sitting on npm since launch. What a minified bundle still gives away, and how to check your own site, is covered in what users can see in your JavaScript and how to protect it.

In May 2026, I gave two popular obfuscators' own flagship demos to Claude Code with one four-paragraph prompt. Claude Opus 4.6 came back with clean source in 10 minutes, Claude Opus 4.7 in 20. They were small demos, not whole apps, and those models are already a generation behind today's.

Your pricing rules, license checks, anti-fraud heuristics and unreleased features have always been in the bundle. What changed is who can read them, and how fast. What you still control is how much of that work carries over to your next release.

Can obfuscated JavaScript be reversed?

Yes. Given enough time, any obfuscator's output can be reversed, AfterPack's included. What AfterPack changes is carry-over: how much of the work to reverse one release still applies to the next. In our own measurement (September 2026, six seeds × five samples), under 6% of what a deobfuscator recovered from one build still resolved on the next (how we measured).

Logic someone has already read also stays read: if they worked out your discount rule once, a new build won't make them forget it.

What can expire is the tool built on that read. A script that strips a license check, a patcher for a paywall, an extractor that pulls your scoring rules out of every release: each is written against the structure of one build. The most popular open-source obfuscator emits fixed output shapes, and free public deobfuscators ship hardcoded recognizers for them, so a tool written once keeps working on every future build.

AfterPack starts from a new random seed on every build. Identifier names, encoded strings, the decoder's signature, state numbering and masked constants all come out different, so the details a tool hard-codes change every time. Run the engine inside a Worker and the window shrinks from a release to a single request.

What's in AfterPack?

A CLI, plugins for the bundlers you already use, a WebAssembly build for Workers, Pro cloud builds, a report of what each build protected, and a free site scanner.

FactAfterPack
What it isA JavaScript obfuscator for production builds: it rewrites what your bundler produces, not your source files
EngineRust, run locally by the CLI and the plugins, or as WebAssembly (@afterpack/wasm) inside your own Worker
OutputDifferent on every build by default in the CLI and the plugins; pin a seed only when you need identical bytes
LicenseCLI and plugins Apache-2.0; the engine is free to use under the AfterPack Engine License
PriceLocal engine free; Pro from $49 a month (plans)
Startnpx afterpack@latest after your build, or a framework plugin

What the table doesn't show:

  • Framework plugins for Next.js, Vite, webpack, Astro, Nuxt, SvelteKit, Svelte, Vue, Angular, Parcel, esbuild, Rollup and Electron. Your normal production build emits obfuscated output.
  • Pro: pass a key and the same call runs in AfterPack's cloud, with directives that aim heavier protection at the code that matters. If the key or the cloud is unavailable, the build fails instead of quietly shipping less.
  • The Protection Map: an HTML report of your original source with every token colored by how much transformation it went through. It's written when your build emits a source map; the plugins can turn that on for you.
  • The free security scanner, also available as npx afterpack audit <url>.

What does AfterPack's obfuscated output look like?

Identifiers vanish and string literals are encoded behind a runtime decoder; how much more happens depends on the preset. light (the default) encodes strings and rewrites syntax, adding no structural layers — the right baseline for most projects. medium makes production code meaningfully harder to follow; hard is for code that matters, like pricing, gating and license checks; extreme sets the highest complexity of the presets, best aimed at one function or file rather than a whole bundle.

A 139-byte function, before:

1export function discount(plan, seats) {
2 if (plan === "team" && seats >= 10) return 0.2;
3 if (plan === "team") return 0.1;
4 return 0;
5}

And after one npx afterpack@latest run at the default light preset (27 September 2026):

1export function discount(N, O) {
2 if (N === Jr("T|P4") && O >= 10) return 0.2;
3 if (N === Jr("T|P4")) return 0.1;
4 return 0;
5}

"team" is gone, replaced by a ciphertext and a decoder call; run it again and the names, the ciphertext and the decoder's signature all come out different. At light, numbers such as 10, 0.2 and 0.1 stay readable; medium and up also mask integer constants like that 10. There's overhead for the decoder that ships alongside the encoded strings, so a file this small comes out proportionally larger than a real bundle would: on a real bundle, light runs 1.9 to 2.4 times the input, gzipped (presets).

Paste your own function into the playground to see what each preset does to it — no install, no account.

Try AfterPack right now

  • Paste code: the playground obfuscates whatever you paste, right in the browser, no install.
  • Scan your site: the security scanner shows what your production JavaScript already exposes.
  • One prompt: point a coding agent at it — Add AfterPack to this project: read afterpack.dev/llms.txt, follow the quickstart for my framework, then run a production build and show me the Protection Map.
  • One command: run npx afterpack@latest after your next build.

Obfuscate JavaScript per request in a Cloudflare Worker

@afterpack/wasm runs the engine as WebAssembly inside your own Worker, so a fresh seed on every call obfuscates each response differently:

1import { obfuscate } from "@afterpack/wasm";
2
3export default {
4 async fetch(request) {
5 const upstream = await fetch("https://example.com/app.js"); // your origin's bundle
6 if (!upstream.ok) return upstream;
7 const source = await upstream.text();
8 const result = await obfuscate(
9 { path: "app.js", source },
10 { preset: "hard", seed: crypto.randomUUID() },
11 );
12 return new Response(result.bytes, {
13 headers: { "content-type": "application/javascript" },
14 });
15 },
16};

If we run that handler in Node on an Apple M2 Max (27 September 2026), serving the discount file from a local origin, four requests come back as four different outputs, each returning the right discounts. Once the module is warm, each obfuscation takes under 4 ms; the first call, which instantiates the engine, takes about 40 ms. That's a 139-byte input; a real bundle costs far more CPU, and it's paid on every response. The Workers guide covers the plan limits and when caching one shape per rotation window is the better trade.

The full setup, with wrangler config, one cached shape per time window and real curl output, is in the tutorial on how to obfuscate JavaScript on every request with Cloudflare Workers.

How to obfuscate a Next.js, Vite, webpack or any other build

Run the CLI after your build, or install the plugin for your bundler so every production build comes out obfuscated. The CLI needs no setup; run this in the project root after building:

npx afterpack@latest

It finds your build output (dist/, .next/, .output/, build/ or out/), rewrites it in place and keeps a backup; npx afterpack@latest restore undoes the run.

To make obfuscation part of the build itself, install the plugin for your bundler:

npm install -D @afterpack/next # or @afterpack/vite, @afterpack/webpack

Each plugin takes one small config change, such as wrapping your Next.js config in withAfterpack(config); frameworks shows it for every supported bundler, from Astro to Parcel. To see what your live site exposes today, run it through the scanner first.

What are AfterPack's limits?

AfterPack raises the cost of reading your code and of reusing tooling against it; it cannot hide values from someone who instruments the running program, so secrets and anything that grants access belong on your server. What it does give you comes with the build you already run: a new target every release, with no extra step to remember.

What's next for AfterPack?

Next is network obfuscation: network transport cloaking will run your API requests and responses through a codec that changes with every build. Cross-module obfuscation will tie logic together across module boundaries, and AfterPack on Workers for Platforms will serve a new shape per request with nothing to install. Past JavaScript, we're heading for HTML and CSS.

AfterPack FAQ

Is AfterPack free?

Yes. The CLI, the framework plugins and the local engine are free, and your source never leaves your machine. Pro adds cloud builds and per-region directives from $49 a month, and a registered Free workspace gets 10 MB of Pro builds a month. The full table is on plans and tiers.

Is AfterPack open source?

The CLI and the framework plugins are, under Apache-2.0, on GitHub. The engine they run is free to use under the AfterPack Engine License.

Does obfuscation slow my code down?

Modestly, and more at stronger presets. The default is light. Raise the preset for a whole project, or use a Pro directive to aim hard or extreme at only the functions that need it.

How is AfterPack different from other JavaScript obfuscators?

It works on your production build through a plugin for the bundler you already use, and by default every build produces different output, so a deobfuscator written for one release mostly stops working on the next. Build time, output size and carry-over, measured side by side with other obfuscators, are on the comparison page.

Does obfuscation hide API keys?

No. Anything your running code uses can be observed by someone who runs it in a browser they control, so keep API keys and other secrets on your server. Encoding does keep a key out of a grep and out of automated secret scanners, which buys time to rotate one that shipped by accident (best practices).


Found a bug, or want a bundler we don't cover yet? Open an issue on GitHub with your bundler and its version; that's where I read feedback.

The code you ship has always been readable. From today, what someone learns from one release no longer has to carry over to the next.

— Nikita

Stay updated

Follow AfterPack for release notes and write-ups.