Use this guide when a project already knows the open-source javascript-obfuscator package and wants to move release protection to JavaScript Obfuscator account workflows, presets, and hosted HTTP API protection.
Choose the right workflow
Stay with local-only tooling Use a local npm obfuscator when source code cannot leave the build machine and you only need local package transforms. |
Use jso-protector Use the hosted JavaScript Obfuscator API when you want dashboard credentials, shared presets, CI guardrails, release manifests, and the same account-backed protection features as the web workflow. |
For regulated or sensitive projects, review Security and Processing before enabling hosted API protection.
Replace the package command
npm remove javascript-obfuscator
npm install --save-dev jso-protector
npx jso-protector --init
Set dashboard API credentials in CI or your local shell. The package reads both short and long environment names.
set JSO_API_KEY=base64-api-key
set JSO_API_PASSWORD=base64-api-password
set JAVASCRIPT_OBFUSCATOR_API_KEY=base64-api-key
set JAVASCRIPT_OBFUSCATOR_API_PASSWORD=base64-api-password
Map familiar options
String array and string encoding
stringArray, stringArrayEncoding, and related settings usually map to MoveStrings, EncodeStrings, and EncryptStrings. |
Identifier renaming
identifierNamesGenerator and rename settings usually map to ReplaceNames, RenameGlobals, RenameMembers, and IdentityStyle. |
Reserved names
reservedNames maps to reservedNames in config or repeatable --reserved-name flags. The value is sent as VariableExclusion. |
Control-flow transforms
controlFlowFlattening, dead-code, and transformation options usually map to DeepObfuscate, ReorderCode, FlatTransform, AddDeadCode, and DeadcodeLevel. |
Output compacting
compact and formatting choices usually map to SelfCompression, CompressionRatio, WriteFormats, and related formatting options. |
Domain or time locks Use LockDomain, LockDomainList, LockDate, and LockDateValue from the HTTP API options. |
The names are not a one-to-one copy of the open-source package. Run jso-protector --list-options --json to inspect the supported API option names, jso-protector --list-migration-map --json to inspect migration coverage, and jso-protector --explain-compat self-defending --json to inspect one mapped or review-only option before porting a large config. The migration map includes mapped, direct, approximate, review-only, and total known option counts for migration tooling.
Generate a starter config
Use the migration command to convert a common javascript-obfuscator JSON or trusted CommonJS config file into a starter jso.config.json. The command maps familiar options where possible, lists review items for settings that are not one-to-one, reports source option, mapped, review-only, unmapped, and automatic coverage counts, then prints the next validate, dry-run, doctor, release-check, and protect commands.
jso-protector --migrate-javascript-obfuscator javascript-obfuscator.json --output jso.config.json
jso-protector --migrate-javascript-obfuscator javascript-obfuscator.config.cjs --output jso.config.json
jso-protector --config jso.config.json --validate-config --json
Use JSON output when internal tooling needs the generated config plus the per-config summary, mapped options, review items, and unmapped option lists.
jso-protector --migrate-javascript-obfuscator javascript-obfuscator.json --json
CommonJS source configs execute as Node.js code, so only migrate configs from your own repository or another trusted source.
Simple package scripts can also keep familiar CLI flags while moving to the hosted API workflow.
jso-protector src/app.js
jso-protector dist --output dist-protected --options-preset high-obfuscation --control-flow-flattening --string-array-encoding rc4 --reserved-names "^PublicApi$"
For direct single-file scripts, jso-protector src/app.js writes src/app-obfuscated.js when no --output or config output is set. Folder and config-file workflows keep using the configured output folder, usually dist-protected.
Mapped compatibility flags include --options-preset, --parse-html, --string-array, --string-array-encoding, --unicode-escape-sequence, --control-flow-flattening, --dead-code-injection, --dead-code-injection-threshold, --identifier-names-generator, --rename-globals, --rename-properties, --reserved-names, --domain-lock, --target, and --compact. parseHtml protects marked inline HTML scripts when paired with <script data-javascript-obfuscator>. --options-preset default and low-obfuscation map to standard, medium-obfuscation maps to balanced, and high-obfuscation maps to maximum.
The CLI also accepts common review-only flags such as --source-map, --source-map-sources-mode, --identifier-names-cache, --identifier-names-cache-path, --self-defending, --debug-protection, --disable-console-output, --reserved-strings, --rename-properties-mode, --numbers-to-expressions, --seed, --split-strings, and string-array wrapper flags so older scripts do not fail immediately. These emit compatibility warnings when there is no one-to-one hosted API mapping.
Port a config gradually
{
"$schema": "./node_modules/jso-protector/jso.config.schema.json",
"apiKey": "$JSO_API_KEY",
"apiPassword": "$JSO_API_PASSWORD",
"input": "dist",
"output": "dist-protected",
"preset": "balanced",
"exclude": ["**/*.map", "**/vendor/**", "**/polyfills-*.js"],
"parseHtml": false,
"honorConditionalComments": false,
"reservedNames": ["^PublicApi$", "^renderWidget$"],
"manifest": "dist-protected/jso-manifest.json",
"maxGrowthRatio": 8,
"options": {
"OptimizationMode": "Web",
"LockDomain": false
}
}
Start with preset: "balanced", protect only first-party build output, then add API options one group at a time.
Replace direct Node usage
const { obfuscate, obfuscateMultiple, getOptionsByPreset, protectCode } = require("jso-protector");
const obfuscationResult = await obfuscate(sourceCode, {
apiKey: process.env.JSO_API_KEY,
apiPassword: process.env.JSO_API_PASSWORD,
controlFlowFlattening: true,
identifierNamesGenerator: "hexadecimal",
reservedNames: ["^PublicApi$"],
stringArrayEncoding: ["rc4"]
}, "app.js");
const protectedCode = obfuscationResult.getObfuscatedCode();
const alsoProtectedCode = obfuscationResult.toString();
const multipleResults = await obfuscateMultiple({
"foo.js": "var foo = 1;",
"bar.js": "var bar = 2;"
}, {
apiKey: process.env.JSO_API_KEY,
apiPassword: process.env.JSO_API_PASSWORD,
...getOptionsByPreset("balanced")
});
obfuscate(code, options, fileName) and obfuscateMultiple(sourceCodesObject, options) are the closest replacements for JavaScriptObfuscator.obfuscate(...) and JavaScriptObfuscator.obfuscateMultiple(...), but they return Promises because protection happens through the hosted HTTP API. They accept common javascript-obfuscator option names directly, including stringArray, stringArrayEncoding, controlFlowFlattening, deadCodeInjection, deadCodeInjectionThreshold, identifierNamesGenerator, renameGlobals, renameProperties, reservedNames, compact, and target.
Use getOptionsByPreset("standard" | "balanced" | "maximum") when replacing preset lookup helpers, and translateJavascriptObfuscatorOptions(sourceOptions, overrides) when migration tooling needs to inspect the mapped hosted API config before making the API call. Existing custom build scripts can also use protectCode(options, code, fileName) when they prefer the JavaScript Obfuscator API naming.
const { protectCode } = require("jso-protector");
const protectedCode = await protectCode({
apiKey: process.env.JSO_API_KEY,
apiPassword: process.env.JSO_API_PASSWORD,
preset: "balanced",
reservedNames: ["^PublicApi$"]
}, sourceCode, "app.js");
For complete build output, prefer the CLI or a bundle plugin because they can remove stale source maps, write release manifests, and enforce size budgets.
Replace bundler plugins
const jsoProtector = require("jso-protector/vite");
module.exports = {
plugins: [
jsoProtector({
apiKey: process.env.JSO_API_KEY,
apiPassword: process.env.JSO_API_PASSWORD,
preset: "balanced",
include: ["assets/*.js"],
exclude: ["**/vendor/**"],
manifest: "dist/jso-manifest.json",
maxGrowthRatio: 8
})
]
};
Equivalent entrypoints are available for jso-protector/rollup, jso-protector/webpack, jso-protector/webpack-loader, jso-protector/browserify, jso-protector/esbuild, jso-protector/gulp, and jso-protector/grunt.
What JSO adds on top of the OSS package
The free javascript-obfuscator npm package covers identifier renaming, string-array hoisting, basic dead code, and control-flow flattening. JSO's hosted protection adds capabilities that don't exist in the OSS lineage:
Polymorphic per-build decoder Every API call produces a byte-different output even when the input and options are identical. Verifiable via the Report.PolymorphismFingerprint in every response. The OSS package re-uses a deterministic decoder shape across runs. |
VM bytecode protection (beta) Source compiles to bytecode running on a per-build polymorphic interpreter. Substantively different protection class from the static transforms the OSS package ships. |
Runtime Defense suite Debug protection, console suppression, self-defending integrity heartbeat, devtools-key blocking, headless detection, session-token lock, fingerprint lock, challenge lock, signed RSA envelopes, beacon callback. None of these exist in the OSS package. |
Compatibility analyzer Static-analysis pass that flags identifiers escaping the bundle (DOM hooks, framework lifecycle names, public APIs) before protection runs, with suggested VariableExclusion entries. The OSS package has no such pre-pass. |
BuildId + audit-friendly response Every API response carries a stable BuildId, the full enabled-options list, identifier maps, compatibility findings, and a polymorphism fingerprint. The OSS package returns the protected code as a string with no audit metadata. |
Local stack-trace symbolication jso-symbolicate demangles production stack traces against the saved identifier map, with first-class integrations for Sentry, Bugsnag, Rollbar, and Datadog. The OSS package emits no symbolication-friendly output. |
Marketplace integrations Official VS Code extension, GitHub Action, and CI templates for GitLab CI, CircleCI, Jenkins, Azure Pipelines, and Bitbucket Pipelines. The OSS package leaves CI integration as an exercise. |
Hosted dashboard credentials and audit history API keys are revocable from the dashboard; every request is logged with project name, release label, file count, and timestamp. The OSS package has no credential or audit-log surface. |
None of the above requires you to abandon the OSS package; you can run both in parallel during evaluation. JSO is the right path when you need the polymorphism, the runtime defense, the audit story, or the symbolication wiring; the OSS package is the right path when local-only transforms suffice and you don't mind hand-rolling the rest.
Migration checklist
- Run
jso-protector --dry-run --json and confirm the file list.
- Exclude vendor bundles, polyfills, generated framework runtime files, and source maps.
- Add
reservedNames for public globals, framework entry points, and names called by external code.
- Protect into a separate output folder first, then run browser smoke tests against that folder.
- Add
manifest, maxOutputBytes, or maxGrowthRatio once the protected output is stable.