๐ JavaScript Deobfuscator and Beautifier
By Shihab Mia ยท Updated 2026-07-01
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.
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
- Paste the obfuscated JavaScript into the input box, or click Load sample to try it on a prepared snippet.
- Leave all four options ticked to decode escapes, decode %XX sequences, expand String.fromCharCode, and beautify, or untick any you do not want.
- Click Clean and beautify (it also runs automatically as you type).
- Read the result in the output box, using the indentation to follow the structure.
- Click Copy to put the cleaned code on your clipboard.
Formula & method
Worked examples
A hidden greeting stored as hex escapes: var m='\x48\x69';
- The scanner finds \x48 and converts it to the character with hex code 48, which is H.
- It finds \x69 and converts it to the character with hex code 69, which is i.
- 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)
- The arguments are all plain integers, so the call is safe to expand.
- Codes 60, 100, 105, 118, 62 map to the characters <, d, i, v, >.
- The whole call is replaced with the quoted literal it produces.
Result: '<div>'
A squashed one-liner: if(a){b();}else{c();}
- Newlines are inserted after each brace and semicolon.
- The opening brace of the if block raises the indent depth to 1.
- 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}
Common encodings this tool decodes
| Pattern | Example input | Decoded output | Meaning |
|---|---|---|---|
| \xHH | \x41 | A | Hex escape, 2 hex digits, one byte |
| \uHHHH | \u0041 | A | Unicode escape, 4 hex digits |
| %XX | %41 | A | Percent encoding (URI escape) |
| String.fromCharCode(n) | String.fromCharCode(65) | 'A' | Code point to character |
What it can and cannot do
| Task | Handled here |
|---|---|
| Decode hex, unicode and URI escapes | Yes |
| Expand numeric String.fromCharCode | Yes |
| Reindent minified code by brace depth | Yes |
| Rename obfuscated variable names | No |
| Unpack packed or eval-wrapped payloads | No |
| Undo control-flow flattening | No |
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.
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.
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.
Sources
- String.fromCharCode() reference , MDN Web Docs
- decodeURIComponent() reference , MDN Web Docs