Skip to content

Obfuscation ​

Protect the code you ship. SunLicense obfuscates it on our servers, so it is far harder to read or reuse:

  • Java — upload a built .jar and we run ProGuard, yGuard or Skidfuscator over it (pick the engine per profile): it renames your classes, fields and methods, and can shrink, repackage or — with Skidfuscator — add control-flow obfuscation and string encryption. You get the obfuscated jar, a mapping file (so you can de-obfuscate your own stack traces) and a report.
  • JavaScript and TypeScript — upload a .js, .mjs, .cjs or .ts file, or a project .zip, and we run javascript-obfuscator over it. You get the obfuscated file (or a zip of your project) and a report. (See below.)
  • Python — upload a .py file or a project .zip, and we run python-minifier over every .py in it. The output is plain Python 3 that still runs on your buyers' machines; protection is lighter than Java's. (See below.)
  • Lua / FiveM — upload a .lua file or a zipped FiveM resource, and we run Prometheus over your client, server and shared scripts while leaving fxmanifest.lua, html/, stream/ and data files alone. (See below.)

Obfuscation is on the Lite and Standard plans, with a monthly limit shared across languages. It runs as a task, so you can close the page and come back — the result waits for you, and files are kept for 7 days.

Java ​

Upload a built Java .jar and SunLicense runs ProGuard over it: it renames your classes, fields and methods, and can shrink unused code and repackage everything. You get back the obfuscated jar, the ProGuard mapping file (so you can de-obfuscate your own stack traces) and a short report.

Obfuscate a jar ​

  1. Open Obfuscation in the sidebar.
  2. Pick your language (Java) and an obfuscator — ProGuard is the recommended, safe default.
  3. Drop in your built .jar (or a .zip of several jars). SunLicense looks at it and tells you what it found — a Paper plugin, a Fabric mod, a library — names the run for you and applies safe settings, so there's usually nothing else to do.
  4. Optional: open Advanced options to change the settings (below), start from a saved profile, or add library jars you compile against (the Paper, Velocity or JDA API) — only needed if the obfuscator reports missing classes. Without them it runs with warnings ignored, and the report says so.
  5. Choose Obfuscate and watch the live log. When it finishes, download the obfuscated jar, the mapping file and the report.

Your past runs are on the page's History tab — open one any time to download its results again (links last a few minutes).

Your plugin still loads ​

SunLicense detects your jar's entry points and keeps their names, so you never have to write keep rules by hand:

  • the manifest Main-Class;
  • plugin.yml, paper-plugin.yml and bungee.yml main, and velocity-plugin.json;
  • Fabric fabric.mod.json entrypoints and mixin classes, and Forge/NeoForge @Mod classes;
  • META-INF/services providers, event handlers (@EventHandler, @Subscribe), enums and serialisable types.

The SunLicense SDK's license check is renamed along with the rest of your code — there is no fixed name for an attacker to find — but it still runs, and the per-buyer download placeholders (product downloads) are kept intact. Classes that hold a placeholder are never string-encrypted, so per-buyer key injection keeps working; a run that would lose a placeholder is refused.

Engines ​

Pick the engine in your profile — one engine runs per job. They trade strength against compatibility:

EngineLicenceWhat it doesGood for
ProGuardGPL-2.0 w/ classpath exceptionRenames, and can shrink and optimise bytecode. Mature and widely compatible.The default; plugins, mods, bots and libraries.
yGuardMITRenames classes, fields and methods only (no string encryption), configured with its own XML.A lightweight, highly compatible rename, or if you already have a yGuard config.
SkidfuscatorMITAdds control-flow obfuscation and string encryption on top — much harder to read, at some cost in size and compatibility.The strongest protection, when you can test the result loads.

TIP

Stronger obfuscation is more likely to break reflection-heavy plugins. Try Skidfuscator with just string encryption first, test that your plugin still loads, then add control-flow obfuscation.

Settings ​

The options depend on the engine (the form is generated from each engine's own schema). For ProGuard:

OptionDefaultWhat it does
Rename symbolsonRename classes, fields and methods.
Remove unused codeoffDrop unused classes and members. Off by default, because plugins and mods are loaded by reflection.
OptimiseoffRun ProGuard's optimisation passes.
Keep line numbersonKeep line-number tables so your stack traces still map to your source.
Keep public APIoffKeep public and protected members unrenamed — for libraries other code compiles against.
Repackage classesoffMove all renamed classes into a single package.
Keep unrenamed—Extra packages, classes or members to leave untouched, such as com.acme.api.**.

yGuard offers Keep public API, Keep line numbers and Keep unrenamed. Skidfuscator offers Encrypt strings and Obfuscate control flow (both off by default) and Leave untouched.

Advanced ​

Choose Advanced to edit the engine's configuration directly, starting from the one your options generate. SunLicense manages the input, output and library jars for you, so anything that names a file is refused with a clear message: ProGuard directives (-injars, -libraryjars, -printmapping <file>, @file, dictionaries…), yGuard XML that adds inoutpair/externalclasses/logfile or a DTD/DOCTYPE, and Skidfuscator libs/renaming keys, HOCON include or file paths.

JavaScript and TypeScript ​

Upload a single .js, .mjs, .cjs or .ts file, or a .zip of your project. For a project, SunLicense obfuscates every .js, .mjs, .cjs and .ts file outside node_modules and your build folders (build/, dist/, …); everything else, node_modules included, is copied into the result unchanged. TypeScript is transpiled to JavaScript first (a plain transpile — no type checking — so the output is .js).

Your node_modules doesn't need to be in the zip (your buyers run npm ci); if it is, keep it under 150 MB or the run is refused.

Your SunLicense SDK calls and the per-buyer download placeholders (product downloads) are always kept readable, and your import/require statements are left intact, so licensing and injection keep working.

OptionDefaultWhat it does
StrengthmediumHow hard the transforms you turn on push: low, medium or high.
Runs onnodenode for bots, servers and CLIs; browser for front-end bundles.
Encode stringsoffEncode the extracted string literals (base64, or RC4 on high).
Flatten control flowoffRewrite control flow so it's hard to follow. Can slow hot code down.
Inject dead codeoffAdd believable unreachable code. Grows the file.
Self-defendingoffBreak the output if it's reformatted or beautified — don't post-process the file.
Keep exported namesonLeave top-level (exported) names so other code can still import them.
Skip files—In a project zip, paths to leave untouched, such as src/vendor/**.

Every obfuscated file is checked with node --check before you download it, so a broken transform never ships.

Choose Advanced to edit the javascript-obfuscator options directly as JSON, starting from the one your options generate. SunLicense manages the input, output and source maps, so options that name files (inputFileName, sourceMap…, and so on) are refused.

Python ​

Upload a single .py file or a .zip of your whole project (a Discord bot, a tool) and SunLicense runs python-minifier over every .py file in it: it shortens the names used inside your functions and removes docstrings, so the code is harder to read. The output is plain Python 3 — no compiled binaries, no C extensions — so it still runs on your buyers' Windows, macOS and Linux machines on any Python 3 they have.

In a project .zip, SunLicense obfuscates only your .py files. Anything inside a virtualenv, site-packages, __pycache__ or a package's metadata folder is copied untouched, and so are your non-Python files (requirements.txt, assets, data). You get back a .zip with the same layout, plus a short report.

Python protection is lighter than Java's

Python ships as source, so obfuscation can only go so far: names are shortened and docstrings removed, but the program's structure stays. It raises the effort to read or copy your code; it does not make it unrecoverable. If you need stronger protection, Java (compiled bytecode + ProGuard) is the better target.

Settings ​

OptionDefaultWhat it does
Rename local namesonRename arguments and variables used inside a function. This is the main protection.
Rename module-level namesoffAlso rename classes, functions and variables at module level. Off by default: it breaks imports between your own modules, and names your framework looks up by string (discord.py cogs, Flask routes). Turn it on only for a single self-contained file.
Remove docstringsonDrop docstrings and other bare literal text.
Remove type annotationsoffStrip type hints. Off by default: discord.py commands and libraries like pydantic read annotations at runtime, so removing them can break your bot.
Keep names—Names to never rename, one per line (for example setup, or a command your framework finds by name).

Because module-level names and annotations are kept by default, a typical discord.py bot obfuscates and still imports and runs unchanged.

Advanced ​

Choose Advanced to edit the engine options directly as a JSON object of python-minifier keyword arguments, starting from the one your options generate (for example {"rename_locals": true, "rename_globals": false}). python-minifier reads and writes no files, so there is nothing to point at the filesystem; any option that isn't a known python-minifier flag is refused with a clear message.

Lua and FiveM resources ​

Choose the Prometheus (Lua / FiveM) engine to obfuscate Lua. Upload either a single .lua file or a zipped FiveM resource (up to 50 MB).

For a resource zip, SunLicense reads your fxmanifest.lua (or the legacy __resource.lua) and obfuscates only the scripts it lists under client_scripts, server_scripts and shared_scripts — globs like server/*.lua are expanded. Everything else is passed through untouched:

  • the manifest itself, and files/ui_page/data_file entries;
  • html/, stream/ and other assets, and any non-Lua file;
  • scripts that belong to another resource (@other-resource/lib.lua).

Because Prometheus keeps string literals, your exports, event names and NUI callbacks keep working — nothing that other resources call by name changes. A single .lua upload is obfuscated as-is.

Settings (Lua) ​

OptionWhat it does
Protection presetMinify, Weak, Medium (recommended) or Strong — Prometheus' built-in presets. Stronger presets grow and slow the output.
Lua versionLua 5.1 (FiveM and most Lua) or LuaU (Roblox; experimental upstream).
ExclusionsResource-relative files to leave alone, e.g. config.lua or locales/*.lua.

FiveM and Lua 5.4

FiveM's CfxLua is based on Lua 5.4, but Prometheus parses and emits Lua 5.1 (or LuaU). Most resources are written in 5.1-compatible syntax and work fine. Scripts that use 5.4-only syntax — integer division //, bitwise operators & | ~ >> <<, or <close>/<const> attributes — won't parse; list those files under Exclusions so they're shipped unchanged.

Each output file is syntax-checked (compiled without being run) before you get it back, so a broken obfuscation never ships silently.

Advanced (Lua) ​

A Prometheus configuration is itself a Lua table — i.e. code — so, for safety, the Advanced editor takes a JSON form of it, not Lua. You can set the preset, luaVersion, prettyPrint, exclusions and an explicit steps list (each an allow-listed step name with primitive settings); SunLicense builds the Lua config from your JSON and never runs any Lua you write. Steps or settings outside the allow-list are refused with a clear message.

Obfuscation for Lua is powered by Prometheus — Based on Prometheus by Elias Oelschner, https://github.com/prometheus-lua/Prometheus, used under the Prometheus License.

Profiles ​

Save a configuration as a profile to reuse it on later runs. A profile can be linked to a product, and starting a run copies its settings into the task, so editing the profile later never changes a past result.

TIP

Keep the mapping file from each release. If a customer sends you an obfuscated stack trace, ProGuard's retrace tool turns it back into your original class and method names using that file.

Beyond the dashboard ​

Obfuscation always runs on SunLicense's servers — never on your machine — so you can reach it the same way everywhere.

Publish an obfuscated build to Downloads ​

When you upload a release file under product downloads, turn on Obfuscate before publishing and (optionally) pick a profile — the default is the product's linked profile. SunLicense obfuscates the upload before it goes live: the release stays processing until it succeeds, then the obfuscated file is published with each buyer's license written in, and your original is removed. Buyers only ever get the obfuscated file. If a run fails, the release shows the task log and stays unpublished.

From the CLI (and CI) ​

Use the sunlicense obfuscate command to obfuscate a build and download the result, with a non-zero exit code on failure so it fits a release step:

bash
sunlicense obfuscate build/libs/app.jar --profile release -o dist/

The language is detected from the file; pass --engine or --profile to be explicit, --config <file> for a raw engine config, and --json for scripts. sunlicense obfuscate profiles lists your saved profiles.

From an AI coding agent (MCP) ​

The CLI's MCP server exposes obfuscation_profiles_list, obfuscate_file (it uploads a local file — the file is never shown to the model) and obfuscation_status. Connected apps and SunLicense AI get the read-only tools only.

From the API ​

A run uses the standard tasks API: create it with POST /api/v1/obfuscation/runs (with a profileId, or engine + options/rawConfig), upload the input with the task's presigned URL, submit it, follow the live log over the task's SSE stream, and download the outputs. GET /api/v1/obfuscation/engines lists the languages, engines and their options; GET /api/v1/obfuscation/profiles lists your profiles.

Send feedback

Found something broken, or have an idea? It goes straight to our board.

The first line becomes the title.
Images (optional, up to 5: paste, drop or capture)
Check each image before sending, and remove any that show something private.

We also receive this page's address and your browser version.

Ctrl Enter to send