How to obfuscate JavaScript code

Paste JavaScript and the tool returns the same program with local names renamed, string literals written as \xNN and \uNNNN escapes, dotted property access turned into bracket notation, and comments removed. The code keeps running with the same result; everything is processed in this browser tab and nothing is sent anywhere.

This is obfuscation to make casual reading harder, not encryption. The logic is still in there, so do not rely on it to hide API keys or business rules, and keep the readable original: debugging the output by hand is unpleasant.

  1. Paste or type the script into the textarea; the obfuscated version replaces the previous output. Press Obfuscate JavaScript, or Ctrl/⌘+Enter, after each edit.
  2. Press Copy to take the result and Clear to empty both panes before the next script.
  3. Before shipping the output, run it once against a small sample whose result you know; the transform preserves behaviour, and the check costs a minute.
  4. Keep the original file. The obfuscated copy is for distribution; the readable source is what you keep editing.

What the obfuscator changes, and what it cannot protect

What the obfuscator changes

Comments are removed but line breaks stay, so deleting a // note can never swallow the following line. Identifiers declared inside the pasted snippet — variables, functions, parameters, classes, catch bindings — are renamed to short generated names through the scope chain; names that come from outside, including globals, stay unchanged.

String literals are rewritten character by character as \xNN or \uNNNN escapes, and a "use strict" directive is left as written. Dotted member access turns into bracket access: console.log becomes console["\x6c\x6f\x67"], and optional chaining follows the same rule (a?.b becomes a?.["b"]). After new and import the syntax is left alone, and #private fields are not touched.

What it is not

Not encryption, not minification. Obfuscated strings get longer rather than shorter, and a determined reader can still follow the logic — the point is to discourage skimming and copying, not to make reversal impossible.

It is a single pass over the code, not a bundler: imports are not resolved, modern syntax is not transpiled, and nothing about how the file is loaded changes. Pasting the same script twice produces different outputs because the generated names are seeded from the source; fine for distribution, unhelpful for comparing builds.

Behaviour under test

The output is tested to return the same values as the input: classes, arrow functions, template literals with nested ${} expressions, async/await, spread, optional chaining, nullish coalescing and regex literals all pass. Module code keeps its import and export names, so it still loads as a module.

Scripts that use eval or with are not renamed — skipping renaming is the only safe choice there — though escaping and bracket conversion still apply. A file of around 80 KB processes in a few tens of milliseconds, and an already obfuscated script can be obfuscated again if you want a second pass.

Recent tools: