From a stock JAR to a protected one in five minutes.
No CLI, no build plugin, no Gradle config. JavaObf runs in the browser. Drop a JAR, pick a profile, ship the result. The pages below cover the workflow, the modules at a level you actually need, and the things that bite first-time users.
1. Quickstart
Three steps. Skip the rest of this page until you have actually shipped one protected build. Reading docs about a tool you have not used is the slowest path.
-
01
Sign in. Use the email you want to bind your license to. Free tier needs no card. Create an account.
-
02
New project, drop a JAR. The engine parses the descriptors (
plugin.yml,paper-plugin.yml,fabric.mod.json,mods.toml, mixins, access wideners) and builds the analysis graph. You will see the explorer fill in within a few seconds. -
03
Open the Protect tab and click Build. Default profile is
balanced. The first build typically finishes in under a minute. Download the JAR and the mapping file. Test the JAR in your dev server before shipping.
2. Your first protected build
Open a project after upload. You'll see four tabs: Overview, Call graph, CFG, and Protect.
- Overview shows the class you have selected, its methods, and the strings it embeds.
- Call graph shows who calls who. Use it to find the methods your value depends on.
- CFG shows the basic blocks of the active method. Useful when deciding what to harden.
- Protect is where you choose a profile and queue the build.
For the first build, leave the profile on balanced. The engine has
opinionated defaults that work for the vast majority of plugins. You'll add
targeting rules in later builds, not the first one.
Click Build. The build queues, runs, and produces a row in the builds list. When it turns green, the JAR and the mapping file are downloadable.
3. Reading the build output
A successful build produces four artifacts:
Test protected.jar in a real server before you ship it. The engine
locks descriptors automatically, but every plugin has its own quirks (reflection,
custom mixins, native libs). The first run in a real Paper or Velocity server is
where those surface.
Concept: profiles
A profile is a named bundle of settings. Three ship with the engine:
Identifier rename and basic string concealment. Fastest build, smallest impact, cheapest to test compatibility against.
Symbol distortion, string concealment, control-flow flattening, integrity mesh, decoy classes. The sane default for paid plugins. Used in 80% of builds.
Everything in balanced plus selective VM, anti-patch interlocks, dispatcher flattening. Heaviest profile. Use this on classes that encode actual value.
You can override any module on top of a profile. The profile sets the floor; rules and toggles raise or lower it per class.
Concept: presets
A preset is your own saved profile, scoped to a project (or a JAR by hash). Build a config you like once, save it as a preset, and apply it to the next plugin without re-tuning the same 22 modules.
Presets are useful when you ship multiple variants of the same plugin (paid versions, gift versions, demo versions). Each variant gets a different preset so a leaked demo cannot be patched into a paid copy.
Concept: locks & entrypoints
The engine locks symbols that the platform must see by their original name. Two kinds of lock:
- Hard lock. Required by the platform. The main class in
plugin.yml, the bootstrap class infabric.mod.json, registered listeners. These never get renamed. - Soft lock. Convention-based.
onEnable,onDisable, common reflection patterns. The engine warns before touching these.
You can add custom locks via the rules panel if your plugin uses an unusual convention (a custom service loader, a reflective bootstrap, a third-party plugin API). The rules are simple regex over class or method patterns.
Concept: targeting rules
Rules let you raise or lower the protection floor on specific code. Five chips show up in the right inspector when you select a class or method:
The general rule of thumb: hard-lock classes that the platform reflects on, max-harden methods that encode actual value (license verification, anti-cheat checks, custom algorithms), relax methods that need to stay debuggable in production logs.
Module guide
The 22 modules group into five families. The descriptions below are the level you actually need to make decisions. The exact transforms each module applies are not public for the same reason your locks would not be either.
Identifiers 6 modules
Symbol distortion, layout scrambling, package-layout scrambling, resource-aware rename, reflection lock tightening, class-literal concealment.
When to enable: always, except on demos you want a reverser to be able to read. The cheapest tier of protection and the one that breaks the casual decompiler.
Watch out for: reflective lookups in your own code that depend on class
or method names. Use S rules to skip rename on those, or refactor the lookup
to use a constant the engine can track.
Strings & literals 5 modules
Concealment, invokedynamic strings, class-string rewriting, broad string encryption, concat-template concealment.
When to enable: always for paid plugins. Strings are the first thing a reverser greps for. License URLs, error messages, and config keys leak the design.
Watch out for: log messages get rewritten too. If your support workflow
relies on grepping logs for a phrase, exempt the logger class with a S rule
on the strings module.
Control flow 4 modules
CFG distortion, dispatcher flattening, method splitting, arithmetic distortion.
When to enable: always for the methods your value sits in. Decompilers rely on recognizable control-flow shapes. Once those go, the cost of reading the method jumps from minutes to a serious afternoon of dynamic analysis.
Watch out for: hot inner loops can take a small performance hit when
aggressively flattened. Use R on tight game loops or per-tick handlers.
Anti-tamper 4 modules
Integrity mesh, anti-patch interlocks, decoy class generation, metadata hygiene.
When to enable: always for anything you charge for. The interlocks are where the real anti-modification cost shows up. They are what make the fifth attempted patch break the first.
Watch out for: nothing, in normal operation. If a build fails the integrity check at boot, that is the engine catching real corruption. File a support ticket with the build ID and we will look at it.
Runtime & resources 3 modules
Resource rewriting, anti-debug / anti-agent, selective VM (covered separately).
When to enable: resource rewriting is fine to leave on. Anti-debug is off by default and should stay off unless you have a specific reason. It catches aggressive reversers but may interact with profilers and analytics agents.
Selective Java VM crown jewel
The selective VM rewrites individual methods into a custom opcode set executed by a tiny embedded interpreter. The decompiler walks into a dispatcher that has no recognizable Java semantics. The encoding rotates per build.
When to enable: on the methods that matter. License verification. Anti-cheat heuristics. Pricing logic. Anything you would lose sleep over if a reverser could read it cleanly.
Watch out for: a small overhead per call. Keep VM-protected methods out
of inner loops that run thousands of times per tick. Use V on methods that
run at session start, not per frame.
Native stub lifting enterprise
For the most valuable methods, the engine compiles them into a hardened native runtime layer the Java side calls into. The Java side becomes a stub. Disassembly resistant, per-customer polymorphic, integrity-bound at load.
When to enable: when the cost of a single leak would justify the price of the plan. Native stub is heavy on the build pipeline (we cross-compile for x86-64 and ARM64) and changes the deployment shape (your JAR now ships shared libraries).
Watch out for: not all methods are stub-lifting candidates. The engine tells you which ones are eligible, and falls back to VM-protected Java where the target platform is unsupported.
Product Licensing
Pro and Enterprise plans include the licensing module. JavaObf injects a tamper resistant license client into your protected jar at build time, so you do not ship a single line of license code from your own repo. Issue keys to your customers, revoke them in minutes from your dashboard, and let the gateway enforce the rules at runtime.
The licensing client is patched into your protected build by the engine. You write zero license logic in your own source.
On first run, the license is bound to the customer's machine ID. Spoofing the machine ID fails server side, with no client side boolean to flip.
Revoke a key from your dashboard and every running copy fails its next validation cycle. The jar self corrupts shortly after.
Quickstart
-
01
Open /licensing and create a product. Or open the project you already have and use Create from this project on the Product Licensing card; that creates and links the product in one click.
-
02
Make sure the project is linked to the product. The project page shows a green chip when it is. Each linked project carries the product's cryptographic identity into every build of that project.
-
03
Queue a build with the licensing toggle on. The build form shows a checkbox Patch licensing client. On by default for linked projects.
-
04
Issue a license and hand the customer the file. The Licenses tab gives you a copy chip for the key and a Download .key button. The customer drops
license.keynext to the jar.
The license.key file
One opaque base64 line. The customer places it in the same directory as the jar (or in the working directory the jar is launched from). The patched runtime locates it automatically.
If the file is missing or invalid: the jar prints a short generic
notice (license.key not found or license.key invalid)
and refuses to start. No URLs, no marketing copy, no hints about which check
failed.
Runtime behaviour
On first launch, the patched runtime activates the license against the gateway and binds it to the machine. From then on it continuously re validates in the background. If it cannot reach the gateway for an extended window, or if you revoke the key from your dashboard, the jar stops working.
Failure mode is intentionally delayed. When the gateway rejects a session, the runtime does not crash at the check site. It silently corrupts its own internal state, so the failure surfaces minutes later inside customer code rather than pointing an attacker at the verification logic.
Watch out for: machines without internet access. The licensing module is online only by design. If your customers have offline deployments, tell us and we will discuss enterprise options.
Notifications
Each product can fan out license events to channels you configure. Three channel types are supported:
Branded rich embed, color coded by severity, deep links back to the dashboard. Paste the webhook URL and we handle the rest.
Signed JSON POST to any URL. The signing secret is shown to you once at creation time. Verify the X-JavaObf-Signature header on receipt.
Plain text alerts to a single inbox. Useful for low volume products and operator on call rotations.
Pick which event kinds each channel subscribes to. Defaults cover the things that signal piracy or abuse (machine ID mismatch, replay attempt, signature failure, ban). Heartbeat noise is off by default to keep your channel readable.
Common workflows
Shipping a paid plugin
- First build with
balanced. Confirm it boots in your target server. - Switch to
max-hardening-plus. Confirm it still boots. - Add
Vrules on the two or three methods that hold value (license, anti-cheat, custom algo). - Save as a preset. Apply to every paid build going forward.
Shipping a demo / trial variant
- Use the same preset as your paid build, but add a
Srule on the trial-gating class so its strings stay readable. - Set a different fingerprint suffix so leaked demos identify themselves separately from leaked paid copies.
- Watermark the trial-only resources so they cannot be lifted into a paid build.
Updating a plugin without breaking installed users
Polymorphic encoding means each new build is structurally different. That is the point: a crack of v1.4 does not work on v1.5. As long as your plugin's external contract (commands, config schema) stays stable, your users will not notice. The mapping file changes per build, so keep them all if you need to deobfuscate stack traces from older versions.
Troubleshooting
The protected JAR fails to load with "no main manifest attribute"
This means a custom entrypoint convention was not auto-detected. Add a hard-lock rule on your main class via the rules panel and rebuild. If your platform is unusual, paste a snippet from your descriptor to support and we will add it to the auto-lock list.
Reflection inside my plugin fails after protection
You are looking up a class or method by a name the engine renamed. Either refactor to use a stable handle (a service interface, a constant), or add a skip-rename rule on the lookup target. The build report flags every reflective access it could not resolve.
The plugin is slower after enabling selective VM
That is expected on hot paths. VM dispatch is not free. Identify the methods marked V that run inside per-tick loops and either move the V tag to a less hot caller, or replace it with the strong CFG profile, which has near-zero overhead.
A class that should be locked is being renamed anyway
Open the build report. Search for the class name. The report tells you which descriptor (or lack of one) the engine used to decide. Add an explicit lock rule for that class.
Build fails with "ecosystem could not be classified"
Your JAR has no recognizable descriptor. The engine refuses to guess. Either add a stub plugin.yml with a single line declaring the main class, or set the ecosystem manually in the project settings.
FAQ
Where do I find the engine version a build was produced with?
The build report has it as engine.version. The protected JAR also embeds it inside the integrity manifest. Useful for support tickets.
Can I export my projects?
Yes. Account → Export. You get a JSON archive of all projects, presets, builds, and rules. No source code is exported, only metadata.
Is there an API or a CLI?
The web app is the primary interface. Enterprise customers get a sealed Docker runner image with a license-bound CLI for CI integration. Get in touch if that is your shape.
Do you have a public roadmap?
Internal one, not public. Subscribe to the changelog from the dashboard. Major modules and crown-jewel features get announced in the Discord first.