Sign in
Open the dashboard to protect a script.
Sign inOverview
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.
Off by default. Standard inlines eligible small helpers while keeping your preset's protections. Preview is free and does not use your build quota.
Ready when you are.
Checking usage
Normal balances protection and performance. Max applies stronger hardening.
Docs
How to build, use macros, and connect your tools.
Introduction
Build in the dashboard, send a file to the Discord bot, or connect through the API.
Your first build
- Open Obfuscate.Paste your source into the left editor.
- Choose a preset.Start with Normal, or choose Max for stronger protection.
- Build and save.When the build finishes, copy or download the output.
local message = "Hello from Voltfuscator"
print(message)Using the Discord bot
DM the bot a .lua or .txt file. Accept the terms on your first use, choose a preset, press Next, and select Lua 5.1 or Executor / Luau. The promotional status requirement is off. Each user has a 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: 12 per rolling 12 hours. Elite: 120 per rolling 12 hours, shared across website, bot, and API. Daily maximums: Basic 6, Pro 24, Elite 240 (00:00 UTC reset). |
| Source size | Basic: 350 KB. Pro and Elite: 450 KB. Limits use UTF-8 file size (1 KB = 1,024 bytes), including pasted source. |
| 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 |
VLT_JIT | MV_JIT | LPH_JIT |
VLT_JIT_MAX | MV_JIT_MAX | LPH_JIT_MAX |
VLT_NO_VIRTUALIZE | MV_NO_VIRTUALIZE | LPH_NO_VIRTUALIZE |
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 macros
VLT_JIT(function() ... end) uses a faster virtualized profile. VLT_JIT_MAX(function() ... end) uses the lightest virtualized profile. VLT_NO_VIRTUALIZE(function() ... end) emits a native function for maximum speed. Use them around hot loops and frequent callbacks such as RenderStepped or Heartbeat.
VLT_JIT(function()
for i = 1, 1000 do
-- repeated work
end
end)()
game:GetService("RunService").RenderStepped:Connect(VLT_NO_VIRTUALIZE(function()
-- frequent callback
end))VLT, MV and LPH prefixes are supported; JIT_MAX and JITMAX are aliases. Pass an inline function. Captured locals stay live, including writes and callbacks used after the script returns. Reflective environment/debug access in marked functions is unsupported. Native Lua 5.1 functions require Lua 5.1 syntax; native Luau functions can use supported Luau syntax.
These profiles trade protection for speed: native function code can be read, and JIT functions use lighter VM protection. Unmarked functions keep the selected preset. Local arithmetic benchmarks measured about 1.2–1.9× faster JIT execution; results depend on the workload and captured-variable traffic.
VLT_INLINE, VLT_OMIT, VLT_VM, VLT_NO_UPVALUES, and VLT_COMPRESS remain migration hints; they do not force inlining, remove captures or add compression.
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 350 KB for Basic or 450 KB for Pro and Elite, measured in UTF-8 bytes |
preset | string | normal or max; defaults to normal |
runtime | string | lua51, roblox, studio, or executor. Legacy luau (default) remains portable. |
runtimeRestrictions | object | Optional restrictions for the selected runtime. Unsupported fields are rejected before reserving a build. |
Runtime restrictions
Lua 5.1 accepts machineId, supplied by your host as VLT_MACHINE_ID or the VOLTFUSCATOR_MACHINE_ID environment variable. Roblox accepts studioOnly, userIds, placeIds, and gameIds. Studio always enforces Studio-only execution. UserId lists require LocalPlayer; GameId means universe ID. Executor accepts executorAllowlist, executorBlocklist, and requiredApis (function paths such as request or Drawing.new). Names are case-insensitive reported executor names. These are startup restrictions, not unforgeable client identity. Enforce valuable permissions on your server. FiveM is not supported.
curl "https://voltils.cc/v1/obfuscate" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"code":"print(1)","preset":"normal","runtime":"roblox"}'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", runtime: "roblox" })
});
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.
Source Optimization - Experimental: optional sourceOptimization is off (default), standard, or performance. Performance uses the lighter VLT_JIT_MAX profile with fewer protections. Set previewOptimized: true to receive optimizedSource without using build quota. Previews are unprotected, authenticated, rate limited, and not saved by the service.
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 goes to the compiler and is used to create the protected output. The gateway stores build details such as status, preset, size, and duration, but not your source or output. Copy or download your output before leaving the dashboard.
Build activity is kept for about 30 days. Aggregate build totals are stored separately. Cleanup runs in batches, so records may remain longer if a backlog builds up.
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.
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.