# Obfuscate JavaScript inside a Cloudflare Worker

Run the Free engine inside your own Worker with @afterpack/wasm, pass a key so the same call runs Pro, and what an AfterPack-supplied wrapper on Workers for Platforms would change.

Source: https://www.afterpack.dev/docs/workers

"AfterPack in a Worker" means one of three things, and they are not interchangeable. The Free engine can run inside **your** Worker today, as a WebAssembly module you install from npm. [Pro](https://www.afterpack.dev/docs/pro) runs in **AfterPack's** cloud, reachable from a Worker like from anywhere else. An AfterPack-operated Pro that runs inside your Workers for Platforms account is roadmapped and does not exist yet.

This page covers all three, in that order.

## The Free engine, inside your own Worker

[`@afterpack/wasm`](https://npmjs.com/package/@afterpack/wasm) is the Free engine compiled to WebAssembly. It is the same Rust engine the [CLI](https://www.afterpack.dev/docs/cli) and the [framework plugins](https://www.afterpack.dev/docs/frameworks) run, built for `wasm32` instead of your machine's architecture.

```bash
npm install @afterpack/wasm
```

```javascript
import { obfuscate } from "@afterpack/wasm";

export default {
  async fetch(request) {
    const source = await request.text();
    const result = await obfuscate({ path: "app.js", source }, { preset: "hard" });
    return new Response(result.bytes, {
      headers: { "content-type": "application/javascript" },
    });
  },
};
```

That is the whole integration. No `init` call, no `nodejs_compat` flag, no wrangler rule for the `.wasm` file. The module has no WebAssembly imports, so it instantiates synchronously the first time you call `obfuscate`, and the package's `exports` map hands your bundler a Worker-shaped entry on its own. The same import works in Node, where a different entry reads the binary off disk.

The surface is identical to [`@afterpack/core`](https://npmjs.com/package/@afterpack/core) — `obfuscate`, `obfuscateAll`, `version`, all async, all throwing on a build that cannot ship. Configuration is the same object documented on [Configuration](https://www.afterpack.dev/docs/config), including [`preset`](https://www.afterpack.dev/docs/config#preset) and [`seed`](https://www.afterpack.dev/docs/config#seed).

> **Use `@afterpack/core` unless you can't**
>
> `@afterpack/core` ships a native binary and is faster. Reach for `@afterpack/wasm` when the host cannot load one: a Worker, a sandboxed CI image, an edge function.

### What it costs you

The engine binary ships inside the package, already compiled.

| | Size |
|---|---|
| Raw `.wasm` | 4.65 MiB |
| Gzipped | 1.41 MiB |

Cloudflare's Worker size limit is 3 MB compressed on the free plan and 10 MB on paid, so the engine fits either. What the free plan does not fit is the *work*: it caps CPU at 10 ms per invocation, and obfuscating a 185 KB bundle at [`complexity`](https://www.afterpack.dev/docs/config) 8 takes a few hundred milliseconds. Anything past a demo wants Workers Paid.

A Worker that obfuscates the same asset on every request pays that CPU every time. Caching the result for a rotation window, or doing the work in your build and serving the output, keeps the bill down where a new shape per request is not what you are after.

### What the package you host can and cannot do

The `.wasm` you install performs Free protection. Pro transforms run only on AfterPack's infrastructure, so the package holds nothing to unlock: no key check to bypass, no switch that turns a hosted copy into a Pro build. A [`key`](https://www.afterpack.dev/docs/config#key) routes work to [the cloud](https://www.afterpack.dev/docs/cloud-api); it does not enable anything locally.

The published package carries an npm provenance record — package version, the workflow that built it, and the artifact digest — so you can tie the bytes you installed to the build that produced them.

## Pro, today: the cloud API

The Pro engine is not part of this package and will not be. It runs only on AfterPack's own infrastructure; that is the point of the tier boundary above. What the package does carry is the client for it.

Reaching it from a Worker is the same call you already write: pass a [`key`](https://www.afterpack.dev/docs/config#key) to `@afterpack/wasm` and the same `obfuscate()` runs Pro. The package makes the Pro request to [`POST /v1/obfuscate/batch`](https://www.afterpack.dev/docs/cloud-api) under the hood, so a Worker never codes the API by hand. The [Cloud API reference](https://www.afterpack.dev/docs/cloud-api) is the full wire contract, and [Deployment modes](https://www.afterpack.dev/docs/deployment-modes) explains what changes when the engine moves.

Two consequences worth being explicit about. Your source leaves your Worker and is processed in AfterPack's cloud — in memory, not persisted, per [Privacy & data handling](https://www.afterpack.dev/docs/privacy). And the build [fails closed](https://www.afterpack.dev/docs/diagnostics#fail-closed-no-exceptions) if the cloud cannot be reached.

> **Pro will never ship as a wasm you host**
>
> A package that claims to run Pro transforms on your own infrastructure is not ours. Check the npm provenance record before installing anything under this name.

## Roadmapped: AfterPack-operated Pro on Workers for Platforms

The shape that does not exist yet: an AfterPack-supplied wrapper for Workers, running inside a Workers for Platforms dispatch namespace. There is no package to install and no worker-to-worker request — the Pro build executes at the edge without a round trip out of Cloudflare's network.

It is on the roadmap and has no date. Nothing on this page depends on it, and [Deployment modes](https://www.afterpack.dev/docs/deployment-modes) describes what ships today. For the requirement "source must never leave our infrastructure", the answer is the Free local engine — not a future edge product.

## Choosing

| You want | Use |
|---|---|
| Obfuscation in a Worker, nothing leaves your account | [`@afterpack/wasm`](https://npmjs.com/package/@afterpack/wasm), this page |
| Obfuscation in a normal Node build | [`@afterpack/core`](https://www.afterpack.dev/docs/frameworks) or the [CLI](https://www.afterpack.dev/docs/cli) |
| [Pro](https://www.afterpack.dev/docs/pro) hardening and per-region [directives](https://www.afterpack.dev/docs/directives) | The same call with a [`key`](https://www.afterpack.dev/docs/config#key), which reaches the [cloud API](https://www.afterpack.dev/docs/cloud-api) |
| Pro, at the edge, in an AfterPack-supplied wrapper | Not available |

## Next

- [Deployment modes](https://www.afterpack.dev/docs/deployment-modes): local versus cloud, and what each one stores.
- [Cloud API reference](https://www.afterpack.dev/docs/cloud-api): the contract a Worker calls for Pro builds.
- [Configuration](https://www.afterpack.dev/docs/config): every key both packages accept.
- [Tiers](https://www.afterpack.dev/docs/tiers): what Free includes, and what Pro adds.
- [Privacy & data handling](https://www.afterpack.dev/docs/privacy): what leaves your machine in each mode.
