Documentation

Migrating from javascript-obfuscator

Reference guides for release workflows, command-line usage, cross-file protections, and the desktop app.

Inside the Docs

Practical guides for real release work.

How-to guides Start with release sequencing and command-line usage, then move into feature-specific references.
Advanced protection Browse cross-file controls like Replace Globals and Protect Members when a build spans multiple scripts.

Migrating from javascript-obfuscator

  • npm CLI, Node API, Vite, Rollup, Webpack, esbuild

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, time, browser, or OS locks
Use LockDomain, LockDomainList, LockDate/LockDateValue for expiry, LockStartDate/LockStartDateValue for activation, and explicit LockBrowserList/LockOSList allowlists for runtime policy. JS-Confuser lock.startDate maps automatically; browser/OS policies require explicit canonical lists and use spoofable runtime signals.

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, competitor-gap, and protect commands. When any review-only item is present, it also prints the migration-review next command. When source-map review items are present, it prints the post-protect source-map-evidence next command. When identifier cache, custom dictionary, or runtime-defense review items are present, it also prints the identifier-cache-review or runtime-defense-review next command so focused source-free replacement packets are not missed.

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, --compact, --self-defending, and --debug-protection. The last two map to the hosted SelfDefending and DebugProtection runtime guards. 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.

stringArrayIndexShift maps approximately to native StringArrayIndexShift. Enabling it adds a deterministic nonzero one-slot offset to plain and encrypted string tables. It does not reproduce the competitor's randomized shift magnitude, so test the protected build in its target runtime.

stringArrayShuffle maps directly to native StringArrayShuffle. It randomizes unique moved-string order and rewrites every lookup before plain or encrypted table emission. Default builds use fresh entropy; supplying Seed makes the shuffled artifact reproducible.

stringArrayRotate maps directly to native StringArrayRotate. Multi-value tables receive a nonzero cyclic offset chosen per build, with every lookup rewritten. Rotation composes with shuffle, shifting, and encryption and is reproducible under Seed.

stringArrayIndexesType maps directly to native StringArrayIndexesType. Both hexadecimal-number and hexadecimal-numeric-string are supported, including mixed lists. Numeric strings are explicitly coerced before array access; mixed selection is reproducible under Seed.

stringArrayThreshold maps directly to native StringArrayThreshold. Values from 0 through 1 make one stable decision per unique eligible literal; zero moves none, one moves all, duplicate literals stay consistent, and partial selection is reproducible under Seed.

stringArrayCallsTransform and its 0-1 threshold map directly to native secondary index-table indirection. Selected calls become nested lookups, the enabled default is 0.5, and Seed makes per-call selection reproducible. It composes with shifting, shuffle, rotation, encryption, index representations, and compression.

Wrapper type, chaining, and parameter controls map directly to bounded native wrappers: variable aliases or functions, 2-5 function parameters, and optional predecessor chains. Count maps approximately to 0-10 root-level wrappers because JSO does not reproduce the competitor's per-function-scope placement. Seed makes wrapper selection and noise arguments reproducible.

transformObjectKeys maps approximately to native safe data-key transformation. Identifier and quoted data keys become computed moved-string lookups. Numeric keys, methods/accessors, shorthand-sensitive members, and __proto__ remain literal so property and prototype semantics do not change.

--debug-protection-interval, --disable-console-output, --domain-lock-redirect-url, --seed, --reserved-strings, --force-transform-strings, --split-strings, and --split-strings-chunk-length map directly. String splitting uses fixed chunks of 1-1024 characters (default 10) while preserving directives, reserved literals, object keys, template segments, import/require specifiers, mixed-server markers, and Unicode surrogate pairs. String-array shuffle, rotation, index representation, call indirection, wrapper type/chaining/parameter controls, and thresholds map to native controls; index shift, wrapper count, and safe object-key transformation retain documented approximation boundaries. --numbers-to-expressions maps approximately to native EncodeNumbers. Source-map, identifier-cache, rename-mode, simplify, and strict-mode workflow fields remain review-only and require release-policy review.

Quoted class method, accessor, and field names remain literal because class definition grammar does not accept concatenation expressions in those positions.

For JS-Confuser, lock.antiDebug, lock.integrity/lock.selfDefending, lock.startDate, and lock.tamperProtection map approximately to native DebugProtection, SelfDefending, LockStartDate, and AntiMonkeyPatching. Numeric probability values collapse to enabled/disabled switches, so protected-browser validation remains required. Arbitrary countermeasure functions and custom locks remain review-only and are never executed by migration tooling.

JS-Confuser stringSplitting maps approximately to native SplitStrings. Boolean values map directly; numeric probabilities greater than zero enable fixed-length splitting. Custom selector functions remain review-only and are never executed by migration tooling.

When the migration report lists any review-only items, run the all-up migration review first. It gives release owners one source-free checklist across source-map policy, identifier-cache replacement, runtime-defense behavior, CLI compatibility warnings, saved report/manifest readiness, follow-up commands, and protected-build smoke evidence.

jso-protector --config jso.config.json --migration-review \
  --migration-review-output reports/migration-review.md

The migration review packet includes a Migration Review Assistant for BYO AI or internal reviewers. It turns manual review tracks, source-map policy, identifier-cache replacement, runtime-defense behavior, source-reading command boundaries, release metadata, and protected-build smoke into owner actions. The packet names field groups and actions, but omits source code, protected output, source-map contents, cache contents, dictionary values, prefixes, domains, URLs, dates, seed values, reserved expressions, raw config files, API credentials, provider keys, customer data, and secrets.

For projects that previously depended on deterministic identifier-name cache reuse or custom naming dictionaries, generate a source-free replacement packet before release approval. It turns the old cache assumption into review evidence: reserved-name rules, saved API report, release manifest, and protected-build smoke results.

jso-protector --config jso.config.json --identifier-cache-review \
  --identifier-cache-review-output reports/identifier-cache-review.md

The identifier-cache packet includes an Identifier Cache Review Assistant for BYO AI or internal reviewers. It names the review-only fields and counts but omits cache contents, dictionary values, prefixes, reserved-name expressions, source code, raw config files, API credentials, provider keys, customer data, and secrets.

For projects that previously generated or referenced source maps during protected releases, keep the post-protect source-map evidence packet beside the manifest. It proves the protected artifact still matches the manifest and does not expose .map files or sourceMappingURL comments.

jso-protector --source-map-evidence dist-protected/jso-manifest.json \
  --source-map-evidence-output reports/source-map-evidence.md

The packet includes a Source Map Review Assistant for BYO AI or internal reviewers. It gives release owners questions for leak cleanup, manifest verification, secure debugging exceptions, bundler cleanup order, and clean handoff without sharing raw maps, source-map contents, original source paths, source code, protected output, customer data, or secrets.

For projects that previously depended on anti-debug, self-defending, runtime lock, console, and countermeasure behavior, generate a source-free runtime-defense packet before release approval. It turns those migration settings into monitoring target, customer-owned forwarding, countermeasure policy, domain/date lock, release metadata, compatibility scan, and protected-build smoke-test review tracks.

jso-protector --config jso.config.json --runtime-defense-review \
  --runtime-defense-review-output reports/runtime-defense-review.md

The packet includes a Runtime Defense Review Assistant for BYO AI or internal reviewers. It turns runtime behavior scope, monitoring handoff, countermeasure policy, domain/date lock smoke, source-reading compatibility scan, release metadata, and protected-build smoke into owner actions without sharing domains, dates, redirect URLs, beacon URLs, countermeasure values, source code, protected output, compatibility-scan source snippets, raw config files, API credentials, provider keys, collector tokens, customer data, or secrets.

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, client-visible challenge freshness checks, asynchronous signed RSA envelope monitoring, and beacon callback. Runtime envelope verification reports asynchronously and is not a blocking loader gate; use signed release-attestation verification before deployment for execution authorization. Self-defending, self-healing, and anti-monkey-patching wrappers use dynamic evaluation (eval and/or the Function constructor) and require CSP dynamic-evaluation permission; API evidence reports RequiresUnsafeEval=true. 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

  1. Run jso-protector --dry-run --json and confirm the file list.
  2. Exclude vendor bundles, polyfills, generated framework runtime files, and source maps.
  3. Add reservedNames for public globals, framework entry points, and names called by external code.
  4. Protect into a separate output folder first, then run browser smoke tests against that folder.
  5. Add manifest, maxOutputBytes, or maxGrowthRatio once the protected output is stable.
Next: read the npm CLI workflow and npm presets and options references for the complete command surface.

Try this in the online obfuscator

Paste your own code and see this option applied, or compare plans for larger projects and the desktop app.

Try It Free See Pricing