No Bundler Required

Your JavaScript never went through a bundler. It still ships to the browser.

Almost every guide to protecting JavaScript opens with a step you cannot perform: add a plugin to your webpack config. Plenty of working software has no webpack config, no package.json and no build at all — script tags, a few hundred kilobytes of jQuery-era code, and logic written directly into the pages that serve it. That code is just as readable as a React bundle, and often more valuable, because it is where the business rules actually live.

Sound Familiar?

<script src="js/app.js"></script>

No entry point, no dependency graph, no output directory. Just files the server hands to the browser exactly as they sit on disk.

Desktop appFolders and file lists, no terminal, no package manager.
Mixed filesScript inside .html, .php, .asp and .jsp pages.
Nothing to installYour project stays exactly as it is.
The Assumption

“Add it to your pipeline” assumes you have one

The standard protection workflow — bundle, then protect the output, then ship the protected directory — depends on three things a build-free project does not have: a single output artifact, a place to hang a plugin, and a directory that can be safely overwritten. Remove those and the advice does not degrade gracefully. It stops applying.

There is no output directory

Bundled projects have src/ and dist/, and protection lives in the gap between them. Here the file the developer edits and the file the browser downloads are the same file. Protecting in place overwrites your source, so the first real decision is where the protected copy goes.

Every file is an entry point

A bundler has one entry and follows the imports. A page with eleven script tags has eleven entries, loaded in an order defined by the markup, sharing one global namespace. Nothing declares the dependencies, so nothing can verify them — including the protector.

Some of the code is not in a .js file

Inline <script> blocks, onclick attributes, and script emitted by PHP or ASP.NET with server values interpolated into it. A tool that only accepts .js input cannot reach any of it, and that is frequently where the interesting logic sits.

Nobody wants npm here

Adding a package manager, a lockfile and a Node version requirement to a project that has run happily without them for a decade is a real cost, paid by whoever maintains it next. It is a reasonable thing to refuse, and it should not cost you protection.

Step One

Find out where your JavaScript actually lives

Before choosing a tool, inventory the code. In build-free projects it is almost never all in one place, and the parts people forget are the parts worth protecting. Four locations, in rough order of how often they get missed:

1. External script files

The .js files under js/, scripts/ or assets/. Easy to find, easy to protect, and usually the first thing people do. Separate your own code from the vendor libraries sitting beside it — protecting a copy of jQuery costs build time, adds risk and protects nothing.

2. Inline script blocks

Script written directly into a page between <script> tags. This is where page-specific logic accumulates: the pricing calculation, the eligibility rule, the thing that was “temporary.” Reaching it requires a tool that can process the surrounding page rather than only plain .js.

3. Event-handler attributes

onclick, onsubmit, onchange. Technically JavaScript, structurally markup. They matter less for what they contain than for what they reference: every one of them names a global function that therefore cannot be renamed.

4. Server-generated script

JavaScript that PHP, ASP.NET or JSP writes into the response, often with values interpolated. Handle this carefully: the server tags are not JavaScript and must survive byte-identical, which is exactly what mixed-file processing is designed to guarantee.

A mixed file, before
<?php $tier = $user->plan; ?>
<script>
  var PLAN = "<?php echo $tier; ?>";
  function canExport() {
    return PLAN === "pro" || PLAN === "enterprise";
  }
</script>
<button onclick="canExport() && doExport()">Export</button>
Read It As An Attacker

Three problems in eight lines

  • The rule is published. Anyone viewing source learns that export is gated on two plan strings, and that the gate is a client-side comparison.
  • The PHP must not move. The server tag has to come through untouched, so this file cannot be handed to a plain JavaScript parser.
  • Two names are pinned. canExport and doExport are referenced from an attribute, so renaming them silently breaks the button.

Protection raises the cost of reading that rule. It does not make the rule authoritative — if export matters commercially, the server must check it too. See why client-side checks are deterrents rather than boundaries.

Step Two

Three workflows, none of which need a bundler

Pick by the size of the job and by where your source is allowed to go. All three drive the same protection engine and the same option set.

The online tool, for a first look

Paste a file, choose a preset, read the output. Best for finding out what protection does to your code before committing to anything. It sends the JavaScript you paste to the service, so use a representative file rather than your most sensitive one while you are still evaluating. Open the online obfuscator.

The desktop app, for real work

A Windows application that takes folders and file lists, remembers them as a project, and protects the selection on demand. No terminal, no configuration file, no package manager. This is the workflow build-free projects should default to, and the reason the desktop app exists. Download it here.

The local CLI, when you want it automated

When protecting the release becomes a step someone must remember, cli\jso-local.exe from the desktop package runs the same source-local pipeline headlessly on a Windows build agent — a scheduled task or a CI job, still with no npm in your project. The command-line guide covers the arguments.

Mixed Files

Protecting script that lives inside a page

This is the capability that decides whether a build-free project can be protected properly or only partially, so it is worth understanding before you plan a rollout.

What MixedServer does

It targets files that are not pure JavaScript — an .aspx, .php, .jsp or .html page with script blocks and server tags interleaved. The script regions are located and protected; everything around them is left byte-identical. Without it, the protector sees one file of unparseable text and can do nothing useful with it. It is an Enterprise-plan option, and it is documented under other features.

Why mixed files deserve more caution

Mixed files are more fragile than plain JavaScript, because the tool is reasoning about two languages at once and only one of them is yours to rewrite. Keep a backup, protect a copy rather than the original, and load every affected page in a browser before shipping. The failure mode is visible immediately, which is the good news.

Where the source goes

Paid Local Advanced handles mixed HTML and server-script files on the machine itself, splitting and reassembling them on-device and writing the protection report locally, with only a source-free entitlement check going online. Local Standard is fully offline but processes plain ES5 .js only — no mixed-file extraction. Security and processing states each boundary exactly.

What to leave alone

Template files whose script is three lines of analytics wiring, vendor libraries, and anything a search engine needs to read. Protecting a page has a cost in debuggability that you pay every time something breaks there. Spend it where the logic is worth something.

Step Three

The four settings that decide whether this goes smoothly

Build-free projects fail in a different place than bundled ones. Almost all of it traces back to a single structural fact: with no module system, everything lives in one global scope, and a name is the only thing holding two files together.

Global renaming is the risky one

In a bundled project, module scope means renaming an internal name is provably safe. Here, formatPrice defined in utils.js and called from checkout.js is a contract with nothing enforcing it. If the two files are protected separately, each gets its own answer and the call breaks. Start with globals untouched; enable renaming only once you know which names cross files, and protect those files together when you do.

Reserve every name your markup mentions

Each function named in an onclick, each global your templates reference, each callback a third-party script calls back into. These are a public API that happens to look private. Grep your markup for handler attributes and treat the results as a reserved list — and accept that a reserved name stays readable in the output.

Load order still matters

Protection preserves the semantics of each file, not the assumptions between them. A file relying on a global that a later script defines was already fragile; protection can change timing enough to expose it. If something breaks only in the protected build, check load order before blaming a transform.

Old browsers, old syntax

Legacy projects often must keep supporting older browsers. Protection can emit constructs those browsers reject, which is what the compatibility analyzer is for — declare the target and let the tool tell you before your users do. Compatibility validation covers it.

Rollout

A sequence that does not put your site at risk

1. One file, standard preset

Pick the single most valuable script. Protect it at the mildest setting, deploy it, and watch. One file is the only change size where a problem is unambiguous, and it teaches you more about your own code than any amount of planning.

2. Widen, keep globals

Add the rest of your own .js files, still without renaming globals. This is usually where the reserved-name list gets its real entries, discovered by something breaking in a browser rather than by inspection.

3. Then mixed files, then strength

Bring in the inline and server-generated script only once plain files are stable, and raise the preset last. Two variables at once turns a five-minute fix into an afternoon. The verification ladder is the same discipline in more detail.

Keep the protected output in a separate folder from your source and deploy from there. It is the single habit that prevents the worst outcome available to a build-free project: protecting in place, committing it, and discovering weeks later that the readable original is gone. If you already have a version-control history, that is your safety net — if you do not, make a copy before the first run rather than after the first mistake.

Frequently Asked

Build-free protection questions, answered

Do I need npm or Node.js to obfuscate my JavaScript?

No. The Windows desktop app protects files and folders directly from a graphical interface with no package manager, no configuration file and no terminal. The online tool handles a single file or a paste. npm is one delivery route among several, and it is the wrong one for a project that has no other reason to install it.

Can you obfuscate JavaScript that is written inside an HTML or PHP file?

Yes, with the MixedServer option, which is an Enterprise-plan capability. It locates the script regions inside a mixed file — an .html, .php, .asp, .aspx or .jsp page with script blocks and server tags interleaved — protects those regions, and leaves every byte around them untouched. Without that option the protector sees one file of text it cannot parse.

Will obfuscation break my inline onclick handlers?

It will if you let the function names change. An attribute like onclick="saveOrder()" is markup, not JavaScript the protector can see, so it still names the old function after the script has been renamed. Either reserve those function names or move the wiring into addEventListener, which removes the dependency on a global name entirely.

Is renaming global variables safe in a project with no modules?

Treat it as the option most likely to break you. Without a module system every script shares one global scope, so a name defined in one file and used in another is a contract between files that the protector cannot see when it processes them separately. Start with globals left alone, and only enable renaming once you know which names cross file boundaries.

How do I protect a site with a hundred script files and no pipeline?

Use a desktop project. It stores the source folder, the output folder, the file selection and the option set, so protecting the next release is one button rather than a hundred decisions. When you eventually want it automated, the same pipeline runs headlessly through the jso-local executable on a Windows build agent.

Does my source code leave my machine?

That depends on which mode you choose, and the difference is worth stating precisely. The online tool, the npm CLI in its default mode and hosted desktop mode all send the selected JavaScript to the service. WinUI Local Standard processes plain ES5 .js files entirely offline with no credentials. Paid Local Advanced keeps modern .js/.jsx and mixed HTML/server-script source on the machine, with only a source-free entitlement check going online.

Start Now

Open the file you would least like to lose

Find the script that encodes something your competitors do not know — the pricing rule, the scoring formula, the integration nobody else has bothered to build — and read it the way a visitor with developer tools would. If it explains itself in under a minute, that is your starting point, and one file is enough to begin.

Related Guides

Nearby reading

Other guides that assume less about your toolchain than most protection advice does:

Does obfuscation break UMD and module wrappers? · Protecting a progressive web app · WordPress plugins · Widgets and SDKs · Minification vs obfuscation · Is an online obfuscator safe? · When protected code stops working · Protecting JavaScript (overview) · Kiosks and embedded devices · ASP.NET, Razor and Blazor · Obfuscating htmx and Alpine apps · Low-code platforms