ToolNimba

๐Ÿ” JavaScript Deobfuscator and Beautifier

Shihab Mia By Shihab Mia ยท Updated 2026-08-02

What to decode and format
0
Input chars
0
Output chars
0
Escapes decoded
0
Output lines

Loading sample...

Readability aid only. This decodes common escapes and reindents by brace depth so you can read the code. It is not a full unminifier and it never runs (evaluates) your input, so packed, renamed, or control-flow-flattened code will still look scrambled.

This tool makes lightly obfuscated JavaScript readable again. It decodes the common tricks that hide code from a quick glance: hex escapes like \x48, unicode escapes like \u0048, percent-encoded strings like %2Fapi, and String.fromCharCode(72,73) calls, then it reindents everything by brace depth so the structure is easy to follow. It never runs (evaluates) your input, so it is safe to paste code you do not trust, and everything happens in your browser so nothing is uploaded.

What is the JavaScript Deobfuscator and Beautifier?

Obfuscation is any transformation that keeps code working while making it hard for a human to read. The lightest and most common forms are pure encoding: instead of writing the character H, a script writes \x48 (its hex value), \u0048 (its unicode escape), or hides a whole string inside String.fromCharCode(72, ...). URLs and payloads are often percent-encoded as %2F, %20 and so on, the same encoding you see in a browser address bar. None of these change what the code does. They only change how it looks, so a good first step in reading unfamiliar JavaScript is to reverse the encoding and put the real characters back.

This deobfuscator does exactly that decoding, and only that decoding. It walks the text with a set of pattern replacements: every \xHH becomes its single character, every \uHHHH becomes its character, every %XX is turned back into its byte through the browser's own decodeURIComponent, and any String.fromCharCode call whose arguments are plain numbers is replaced with the literal string those numbers spell. Crucially, it does none of this by executing the code. A malicious script can hide a call like eval(atob(...)) that only reveals its payload when it runs, so any tool that runs your input to unpack it is itself a security risk. This tool uses safe text substitution, which means it can never trigger a payload, but also means it will not unwrap things that only exist at runtime.

After decoding, the beautifier restores structure. Minified code is usually squashed onto one line with every optional space and newline removed. The formatter inserts a newline after each semicolon and around each curly brace, then indents every line by the running brace depth at two spaces per level, so a function body sits one level in, a nested if sits two levels in, and so on. The result is not guaranteed to be byte-for-byte identical to the original source (the numbering and spacing are reconstructed, not recovered), but it reads like normal code and lets you follow the control flow.

Tools that unpack JavaScript generally fall into three families. Text-substitution tools, like this one, scan the raw text for known patterns and replace them without ever running the code; they are fast, safe, and limited to encodings that are visible in the source. AST-based tools instead parse the code into an abstract syntax tree, a structured model of every statement and expression, which lets them safely rename variables, fold constant expressions, and even unravel control-flow flattening because they understand the code's structure rather than just its text. Sandboxed evaluators go a step further and actually run the obfuscated bootstrap function, such as an obfuscator.io string-array rotator or a Dean Edwards packer, inside an isolated environment so the real payload reveals itself the same way it would in a browser, just without the risk of it touching your real page. Each approach trades safety for power: text substitution is the safest and the least capable, sandboxed evaluation is the most capable and carries the most risk if the sandbox is not properly isolated.

It is important to be honest about the limits. This is a readability aid, not a full unminifier or a reverse-engineering suite. It will not rename single-letter variables back to meaningful names, undo control-flow flattening, unpack the dean-edwards p,a,c,k,e,d format, decrypt runtime-generated strings, or handle nested layers that decode themselves as they run. For those you need a tool that actually parses and, in some cases, safely sandboxes the code. What this tool does well is the eighty percent case: a snippet that looks scary only because it is full of \x escapes and squashed onto one line becomes plain, indented JavaScript you can actually read.

A note on the beautifier's naive brace counting: because it does not parse strings, a curly brace that appears inside a string literal or a regular expression will be counted as a real brace and can throw the indentation off by a level. This is a deliberate trade-off that keeps the tool tiny, fast, and eval-free. If the indentation looks wrong on a particular line, it is almost always because a brace was hiding inside a string, and the decoded text itself is still correct.

When to use it

  • Reading a suspicious inline script found on a web page before deciding whether it is safe, without ever running it.
  • Turning a one-line minified snippet from a bug report or a Stack Overflow answer into indented code you can follow.
  • Decoding strings that were hidden with \xHH or \uHHHH escapes so you can see the real URLs, messages, or selectors.
  • Expanding String.fromCharCode(...) sequences that spell out hidden text such as a tag name or an endpoint.
  • Recovering the readable form of a percent-encoded payload copied from a network request or a URL.
  • Teaching or learning how basic JavaScript obfuscation works by watching escapes turn back into plain characters.

How to use the JavaScript Deobfuscator and Beautifier

  1. Paste the obfuscated JavaScript into the input box, or click Load sample to try it on a prepared snippet.
  2. Leave all four options ticked to decode escapes, decode %XX sequences, expand String.fromCharCode, and beautify, or untick any you do not want.
  3. Click Clean and beautify (it also runs automatically as you type).
  4. Read the result in the output box, using the indentation to follow the structure.
  5. Click Copy to put the cleaned code on your clipboard.

Formula & method

For each \xHH: output = String.fromCharCode(parse(HH as base 16)). For each \uHHHH: output = String.fromCharCode(parse(HHHH as base 16)). For each %XX run: output = decodeURIComponent(match). For String.fromCharCode(n1, n2, ...): output = the quoted string of those code points. Beautify: insert a newline after ; { and }, then indent each line by 2 x (running brace depth) spaces.
From scrambled to readableObfuscated inputvar m='\x48\x69';t=String.fromCharCode(60,62);p='%2Fapi';if(a){f();}decode+ formatReadable outputvar m = 'Hi';t = '<>';p = '/api';if (a) {f();}No eval. Everything runs in your browser.

Worked examples

A hidden greeting stored as hex escapes: var m='\x48\x69';

  1. The scanner finds \x48 and converts it to the character with hex code 48, which is H.
  2. It finds \x69 and converts it to the character with hex code 69, which is i.
  3. The string literal now reads 'Hi', and the escapes decoded counter shows 2.

Result: var m = 'Hi';

A tag name hidden with char codes: String.fromCharCode(60,100,105,118,62)

  1. The arguments are all plain integers, so the call is safe to expand.
  2. Codes 60, 100, 105, 118, 62 map to the characters <, d, i, v, >.
  3. The whole call is replaced with the quoted literal it produces.

Result: '<div>'

A squashed one-liner: if(a){b();}else{c();}

  1. Newlines are inserted after each brace and semicolon.
  2. The opening brace of the if block raises the indent depth to 1.
  3. The statement inside is indented two spaces; the closing brace drops the depth back to 0.

Result: if (a) {\n b();\n}\nelse {\n c();\n}

A percent-encoded API path: var u='%2Fapi%2Fv1%2Fusers%3Fid%3D42';

  1. The %2F runs are found and passed through decodeURIComponent, which turns each one into /.
  2. %3F decodes to ? and %3D decodes to =, the same way a browser decodes a query string.
  3. The rebuilt string reads as a normal path with a query parameter.

Result: var u = '/api/v1/users?id=42';

Common encodings this tool decodes

PatternExample inputDecoded outputMeaning
\xHH\x41AHex escape, 2 hex digits, one byte
\uHHHH\u0041AUnicode escape, 4 hex digits
%XX%41APercent encoding (URI escape)
String.fromCharCode(n)String.fromCharCode(65)'A'Code point to character

What it can and cannot do

TaskHandled here
Decode hex, unicode and URI escapesYes
Expand numeric String.fromCharCodeYes
Reindent minified code by brace depthYes
Rename obfuscated variable namesNo
Unpack packed or eval-wrapped payloadsNo
Undo control-flow flatteningNo

Obfuscation formats beyond this tool, and how to unpack them

FormatWhat it looks likeHow to deal with it
Base64 payloadatob('aGVsbG8=')Decode the Base64 string separately, then paste the result back in here
Dean Edwards packereval(function(p,a,c,k,e,d){...}('...',62,40,'...'.split('|'),0,{}))Use a dedicated unpacker, such as de4js, that safely evaluates the packer function in a sandbox
obfuscator.io string arrayvar _0x1a2b=['\x68\x69']; function _0x3f(a){return _0x1a2b[a];}Run the array-rotation logic in a sandboxed evaluator to resolve indices back to strings
Control-flow flatteningA single while (true) { switch (state) { ... } } loop replacing normal branchingNeeds a tool that rebuilds the control-flow graph, not a text-based decoder
JSFuckEvery character written using only [ ] ( ) ! +, for example []+[]+[]+[]Use a JSFuck-specific decoder; there are no hex, unicode or fromCharCode patterns for this tool to find

Common mistakes to avoid

  • Expecting it to fully reverse heavy obfuscation. This is a readability aid. It decodes escapes and reindents code, but it will not rename variables, unpack self-decrypting payloads, or undo control-flow flattening. For those you need a dedicated parsing or sandboxing tool.
  • Assuming it runs the code to unpack it. It never evaluates your input. That keeps you safe from malicious payloads, but it also means anything hidden behind a runtime eval or atob call will stay hidden, because it only exists once the code executes.
  • Trusting the indentation after a brace inside a string. The beautifier counts every curly brace, including ones inside string literals or regular expressions, so a brace hidden in a string can push the indent off by a level. The decoded characters are still correct; only the spacing is affected.
  • Pasting code from an untrusted source and then running it anyway. Reading a script here does not make it safe to execute. Deobfuscation helps you understand what code would do; it does not vet it. Never run untrusted JavaScript on a real page or server just because you can now read it.
  • Expecting obfuscator.io or packer code to unpack automatically. This tool only substitutes literal escape patterns it can see in the source. It does not simulate the array-rotation loop obfuscator.io generates, and it does not evaluate a Dean Edwards eval(function(p,a,c,k,e,d)) packer, so code obfuscated with those tools will decode only partially, if at all.
  • Confusing minification with obfuscation. Minified code from a bundler like Terser or esbuild has short variable names and no whitespace, but it is not hiding anything; running just the beautify step here already makes it readable. True obfuscation adds encoding or structural tricks on top of that, which is what the decoders in this tool target.

Glossary

Obfuscation
Transforming code so it still works but is hard for a person to read, usually by encoding strings and stripping formatting.
Hex escape (\xHH)
A way to write a character using two hexadecimal digits, for example \x41 for the letter A.
Unicode escape (\uHHHH)
A way to write a character using four hexadecimal digits of its unicode code point, for example \u0041 for A.
Percent encoding
URL-style encoding where a byte is written as a percent sign followed by two hex digits, such as %20 for a space.
String.fromCharCode
A JavaScript method that builds a string from a list of numeric character codes, often used to hide readable text.
Beautify
Reformatting compressed code by adding newlines and consistent indentation so its structure becomes visible.
Packer (eval-based obfuscation)
A format, popularized by Dean Edwards, that stores code as a compressed string and rebuilds it with a small decoder function wrapped in eval when the script runs.
Control-flow flattening
An obfuscation technique that replaces normal if and loop structures with a single dispatcher loop driven by a state variable, making the true execution order hard to see by reading the text.

Frequently asked questions

What does a JavaScript deobfuscator do?

It reverses the encoding tricks that hide readable code. This one decodes hex, unicode and percent escapes, expands numeric String.fromCharCode calls, and reindents the result so you can read the logic. It does not execute the code.

Is it safe to paste malicious or untrusted JavaScript here?

Yes, for reading. The tool only does text substitution and never evaluates your input, so no payload can be triggered by decoding it. It runs entirely in your browser and uploads nothing. Reading code still does not make it safe to run.

Will it fully unminify or restore the original source?

No. It is a readability aid, not a full unminifier. It cannot restore original variable names, comments, or exact formatting, and it does not unpack self-decrypting or control-flow-flattened code. It makes escaped, squashed code readable.

Why is the indentation sometimes slightly off?

The beautifier counts curly braces without parsing strings, so a brace inside a string literal or regular expression is counted as real and can shift the indent by a level. The decoded characters are still correct; only the spacing is affected.

Does it decode Base64 or atob payloads?

Not directly. Base64 blobs are usually decoded at runtime by atob or eval, which this tool deliberately never calls. You can decode a Base64 string separately and paste the result back in to keep reading.

Can I turn off the beautifier and only decode the strings?

Yes. Each step has its own checkbox. Untick Beautify to keep the original line layout while still decoding escapes and expanding String.fromCharCode, or untick any decoder you do not need.

Can it deobfuscate code produced by obfuscator.io?

Only partially. Obfuscator.io hides strings in a rotated array and replaces names with hex identifiers like _0x1a2b; this tool will still decode any \x or \u escapes inside that array, but it does not simulate the rotation loop or resolve which index maps to which string. A sandboxed unpacker such as de4js is built for that specific format.

What is the difference between minified and obfuscated JavaScript?

Minified code has whitespace stripped and variable names shortened purely to reduce file size; nothing is hidden, and beautifying it alone restores readability. Obfuscated code goes further and deliberately encodes strings or restructures logic to resist reading. This tool handles the encoding layer that obfuscation adds on top of minification.

Does it handle the Dean Edwards eval(function(p,a,c,k,e,d)) packer format?

No. That packer stores the real code as a compressed, encoded string and only reconstructs it by running a small decoder function through eval. Because this tool never evaluates input, it will show you the packer wrapper as-is rather than the code inside it. Use a dedicated packer-aware unpacker for that format.

Is there a limit to how much code I can paste in?

There is no hard cap, but very large files (tens of thousands of lines) can make the browser tab slow to respond because every pattern match and reindent pass runs in memory on your device. For huge bundles, work on the relevant function or file at a time rather than an entire minified vendor bundle.

Sources