Your scripts. Your workspace.
Publish protected Lua scripts, manage licenses, and control access from one place.
Continue with DiscordAnyone with Discord can get started.
Welcome back.
Everything you need to protect and distribute your scripts.
From source to script
Your publishing workflow, in three steps.
Protection starts here.
Use the standalone Lua / Luau obfuscator, or publish protected builds straight from your script manager.
One account. One shared build allowance.Recent deliveries
Successful protected script responses.
Projects
Organize scripts by product, community, or release.
Scripts
Write, protect, and publish through a stable loader URL.
Script editor
Draft
Set getgenv().script_key to a license before running a keyed loader.
Hosted output: up to 1.5 MB. Publishing uses your shared build allowance. The standalone Obfuscator supports larger sources.
License keys
Issue expiring access, revoke licenses, and reset device bindings.
Save your license key
This secret is shown once. Copy it before closing.
| License / script | Status | Expires | Device | Actions |
|---|
Delivery logs
Protected payloads delivered by your loaders. A delivery does not confirm successful execution.
| Script | Event | Time |
|---|
Overview
Usage and recent builds across your account.
Recent activity
Your website, bot, and API builds.
| Build | Source | Preset | Status | Time |
|---|
Obfuscate
Lua or Luau in. Protected code out.
Ready when you are.
Checking usage
Normal balances protection and performance. Max applies stronger hardening.
Docs
Guides and reference for your workspace.
Publish your first script
Create a project in Workspace, add a script, and save your source. Choose Normal or Max, then click Obfuscate & publish. Publishing consumes one shared build allowance and gives you a stable /loader/ URL.
Keyed scripts require a license from License keys. Set getgenv().script_key = "YOUR_LICENSE_KEY" before running the loader. Licenses bind to the first device identifier reported by the executor. Reset a binding when a customer changes devices; revoke a license to block future deliveries.
Hosted source is limited to 300 KB and protected output to 1.5 MB. The latest ten builds are retained for rollback. Restoring an older build preserves your draft and loader URL. Delivery logs record payload responses, not successful execution.
Introduction
Protect Lua and Luau scripts from the browser, Discord, or your own integration.
Your first build
- Open Obfuscate.Paste your source into the left editor.
- Choose a preset.Normal is a good starting point. Use Max for stronger hardening.
- Build and save.Watch the build status, then copy or download your protected output.
local message = "Hello from Voltfuscator"
print(message)Using the Discord bot
DM the bot with a .lua or .txt file. Accept the terms when asked, set dsc.gg/obfuscating in your visible Discord status, and use the panel to choose your preset. The bot keeps its ten-minute cooldown.
Limits & presets
Know what a build can accept and what counts toward your usage.
| Limit | Allowance |
|---|---|
| Successful builds | Basic: 3 per rolling 12 hours. Pro: 32 per rolling 12 hours. Elite: 64 per rolling 12 hours, shared across website, bot, and API. |
| Source size | Basic: 256,000 characters. Pro: 5,000,000. Elite: 10,000,000. Unicode characters are counted as code points. |
| Compiler time | 60 seconds per build |
| Simultaneous builds | One compiler slot |
| Active API keys | Up to 3 per account |
| Key inactivity | Expires after 30 days without API use |
Normal
Balances protection, output size, and execution performance. Start here when testing a script.
Max
Applies stronger hardening and can take longer to compile. Large sources may reach the time limit.
When the compiler is busy
Wait for the current job to finish before retrying. Check Overview for your job status after a connection interruption. All tiers regain each slot 12 hours after its successful build.
VLT Macros
Use Voltfuscator's VLT macros to mark protected builds, check values, and annotate functions.
Start with VLT
Macros are handled by the compiler. You do not need to import a library in your protected script. Function directives are comments, so the same source can run during development.
if not VLT_OBFUSCATED then
print("Running the source preview")
end
--!vlt:vm
local function nextScore(score)
return score + 10
end
assert(nextScore(20) == 30)
local originalLine = VLT_LINE or 0Build markers
| VLT macro | Behavior |
|---|---|
VLT_OBFUSCATED | Becomes true in a protected build. Without a development shim, it is nil in raw source. |
VLT_LINE | Becomes the original source line number at that expression, including lines inside comments and strings. |
Values and functions
VLT_ENC_STR(value), VLT_ENC_NUM(value), and VLT_ENC_FUNC(fn) return their first value. The normal compiler protects these values and functions as part of the VM payload. These markers do not select a separate encryption algorithm.
local label = VLT_ENC_STR("Voltfuscator")
local target = VLT_ENC_NUM(24)
local double = VLT_ENC_FUNC(function(value)
return value * 2
end)
VLT_ASSERT(double(12) == target, "Unexpected result")
print(label)A three-argument form accepts value, buildKey, runtimeKey. It returns the value only when the two keys match, otherwise it raises an error. This is a runtime equality check inside the protected script, not a key for decrypting the entire script.
local runtimeKey = "release-1"
local label = VLT_ENC_STR("Ready", "release-1", runtimeKey)Function annotations
VLT_VM(function) returns a function protected by the current VM preset. The entire script is already virtualized; this marker does not choose another VM.
VLT_CFF(function) adds opaque guards to branches and loops inside an inline function, then the function runs in the VM. It preserves closures and return values. It does not emit MoonVeil's separate native state-machine implementation.
Place --!vlt:vm or --!vlt:cff immediately above a function declaration. --!mv: and --!lph: accept the same two directives. Extra VM selectors and CFF options are not supported.
--!vlt:cff
local function tier(points)
if points >= 50 then
return "gold"
end
return "silver"
end
local add = VLT_VM(function(a, b)
return a + b
end)
assert(tier(add(25, 30)) == "gold")Checks and arithmetic
VLT_PRECHECK(fn, ...expected) executes a function and compares its returned values with the expected values. Types, return counts, and table contents must match. A mismatch raises an error. The check runs where you place it; it does not run before the VM decrypts or bind the loader's encryption key.
VLT_ASSERT(condition, message?) raises an error for false or nil and otherwise returns the condition. VLT_CRASH() deliberately raises a runtime error.
VLT_REWRITE(expression, preset?) evaluates a signed 32-bit integer expression once and adds a reversible arithmetic mask. Presets fast, strong, and extreme are accepted as compatibility names and currently use the same transformation. Floating-point values and competitor option tables are rejected.
VLT_PRECHECK(function()
return "ready", 24
end, "ready", 24)
local score = VLT_REWRITE(7 * 6, "strong")
VLT_ASSERT(score == 42, "Score check failed")Migrating from MoonVeil or Luraph?
Voltfuscator recognizes supported MV_* and LPH_* names as aliases of its VLT_* macros. You can keep familiar names while moving your scripts over. Use the mappings below and check the behavior notes before relying on a protection or performance feature.
| Voltfuscator | MoonVeil alias | Luraph alias |
|---|---|---|
VLT_OBFUSCATED | MV_OBFUSCATED | LPH_OBFUSCATED |
VLT_LINE | MV_LINE | LPH_LINE |
VLT_ENC_STR | MV_ENC_STR | LPH_ENCSTR, LPH_STRENC |
VLT_ENC_NUM | MV_ENC_NUM | LPH_ENCNUM, LPH_NUMENC |
VLT_ENC_FUNC | MV_ENC_FUNC | LPH_ENCFUNC |
VLT_VM, VLT_CFF | MV_VM, MV_CFF | LPH_VM, LPH_CFF |
VLT_PRECHECK, VLT_REWRITE | MV_PRECHECK, MV_REWRITE | LPH_PRECHECK, LPH_REWRITE |
VLT_CRASH | MV_CRASH | LPH_CRASH |
Some names in the alias families are provided by Voltfuscator for consistency and may not exist in the other product. Luraph's newer attributes, stack allocation, buffer macros, numeric runtime-key tables, and MoonVeil's index rewriting are not implemented.
Performance compatibility
VLT_INLINE, VLT_OMIT, VLT_NO_VIRTUALIZE, VLT_JIT, VLT_JIT_MAX, and VLT_NO_UPVALUES accept one function and return it. The MV and LPH equivalents are recognized too. These are migration hints: they do not bypass virtualization, force inlining, remove captures, or guarantee a speedup. The selected preset still controls optimization.
VLT_COMPRESS(value) and its MV/LPH aliases return one value without adding a compression pass. Unsupported macros and unsupported arguments produce a compile error rather than silently promising a protection feature.
Development
Call-style macros are compiler features. For raw-source testing, supply your own local debug shims or use the comment-style starter example. Macro names in strings, table fields, and local bindings are preserved.
References: MoonVeil macros and Luraph macros. Voltfuscator's implementation and behavior are described above.
API
Obfuscate scripts from your server or build tools.
Endpoint
https://voltils.cc/v1/obfuscateAuthenticate with Authorization: Bearer YOUR_API_KEY and send JSON with Content-Type: application/json.
Request body
| Field | Type | Description |
|---|---|---|
code | string | Required Lua or Luau source, up to 256,000 characters for Basic, 5,000,000 for Pro, or 10,000,000 for Elite |
preset | string | normal or max; defaults to normal |
curl "https://voltils.cc/v1/obfuscate" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code":"print(1)","preset":"normal"}'const response = await fetch("https://voltils.cc/v1/obfuscate", {
method: "POST",
headers: {
"Authorization": "Bearer " + process.env.VOLTFUSCATOR_API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({ code: "print(1)", preset: "normal" })
});
const result = await response.json();
if (!response.ok) throw new Error(result.error);
console.log(result.obfuscated);Successful response
{
"success": true,
"obfuscated": "...protected Lua..."
}Error responses
| Status | Meaning |
|---|---|
| 400 | Invalid code, preset, or request |
| 401 | Invalid, expired, or revoked key |
| 413 | Source exceeds the size limit |
| 429 | Quota, attempt limit, or compiler busy |
| 5xx | Compiler, connection, or confirmation unavailable |
Failures include an error message. Follow the response’s retry guidance and avoid sending repeated requests while a job is processing.
Key lifecycle
Keys expire after 30 days without accepted API use. Viewing a key or using the website does not extend its activity window. API Keys shows the masked value by default and reveals the full value only when you ask.
Privacy
What your account stores and how your scripts are handled.
Account data
Signing in requests Discord’s identify scope. Your Discord ID, display name, and avatar associate builds and API access with your account. Browser sessions use secure, HttpOnly cookies.
Scripts and build activity
Your source is sent to the compiler to produce protected output. The gateway database stores job metadata such as status, preset, size, and duration. It does not store your source or protected output. Copy or download output before leaving the workspace.
Activity targets a 30-day retention period. Aggregate protected-script totals remain available separately. Cleanup runs in bounded batches.
API keys
Authentication uses a key hash. A separate encrypted copy allows owners to reveal their active keys after signing in. Full keys are excluded from routine account listings, activity, and logs.
Abuse prevention
Short-lived rate-limit records use hashed identifiers. Account quotas are shared across the website, bot, and API. Tier change audit records target 90 days of retention.
Hosted scripts and licenses
Voltils hosted projects store private source drafts, published protected output, and up to ten protected versions per script until deleted by the creator. License records store key hashes, expiry, revocation, and hashed device identifiers. Delivery logs contain script names and delivery timestamps and are retained for approximately 30 days, with bounded cleanup. Deleting a hosted script removes its licenses, versions, and delivery logs. This hosted storage is separate from temporary standalone obfuscation processing.
Contact
Contact @justflaxo through the support Discord for account or privacy questions.
API Keys
Manage access for your integrations.
Up to three active keys. Inactive keys expire after 30 days without API use.
API key
Keep this key private. You can view it again while it is active.