Macros

Macros are compile-time constructs that allow you to write conditional code paths and optimize performance in your obfuscated scripts.

Quick Reference

MacroTypePurpose
WYNF_OBFUSCATEDbooleanDetect if script is obfuscated
WYNF_NO_VIRTUALIZEfunction wrapperMark function for native execution (unprotected)
WYNF_CRASHfunction callSecurely crash and corrupt the VM (destructive)
WYNF_IS_CALLER_WYNFUSCATEfunction callDetect external callers (security)
WYNF_ENC_STRINGstring wrapperExtra encryption for sensitive strings (security)
WYNF_ENC_NUMnumber wrapperExtra encryption for sensitive numbers (security)
WYNF_LINEfunction callGet source line number at compile time (debug)
WYNF_NO_UPVALUESfunction wrapperCompatibility wrapper for callbacks (compatibility)
WYNF_SECURE_CALLfunction wrapperRestrict function to VM-only callers (security)
WYNF_SECURE_CALLBACKfunction wrapperSecure wrapper for event callbacks (security)
WYNF_ENC_FUNCfunction wrapperRuntime-decrypted function with key server support (security)

WYNF_OBFUSCATED

boolean

A compile-time constant that evaluates to true in obfuscated builds. In plain Lua (non-obfuscated), it behaves like a normal global (typically nil/false).

Dead Code Pruning

When used as an if condition, the compiler removes unreachable branches from the output entirely. This means dev-only stubs and fallback code gated by WYNF_OBFUSCATED are not present in the obfuscated bytecode at all — not just skipped at runtime.

Basic Example

Loading...

Stripping Dev Code from Output

This pattern ensures dev fallback code is never shipped in the obfuscated file:

Loading...

Development Stubs

Define stubs for macros so your code runs in development without errors. These stubs are completely removed from obfuscated output:

Loading...
Do
  • Use to strip dev-only stubs from output
  • Use to gate debug/profiling code
  • Use for feature flags between dev/prod
  • Use for verbose logging in dev only
Avoid
  • Assuming it prevents debugging/tampering
  • Relying on it as sole protection for secrets
  • Using for license enforcement alone

WYNF_NO_VIRTUALIZE

performance

WARNING: Code Exposure

Code wrapped with WYNF_NO_VIRTUALIZE is NOT protected through virtualization. Your code will be minified (local names, upvalue names, comments, and line information are stripped), but raw strings and logic will still be exposed.

Only use this for performance-critical code that does not contain sensitive logic, API keys, URLs, or any code you need to keep private.

Marks a function to run as native Lua instead of inside the VM. This bypasses VM overhead for performance-critical code like hot loops or heavy math/table/string operations.

Correct Usage

Use for performance-critical code that contains no sensitive information:

Loading...

Incorrect Usage

Never use for code containing sensitive information - it will be exposed:

Loading...

Upvalues

Functions can capture variables from the parent scope (upvalues). While upvalue names are stripped, the values themselves are not secure. Avoid referencing upvalues that contain sensitive information.

Loading...

Development Stub

To run un-obfuscated scripts without errors, add this stub at the top of your file:

Loading...

This stub is automatically ignored when the script is obfuscated.

Do
  • Use for hot loops or heavy computations
  • Use for math/table/string operations
  • Use only for non-sensitive code
  • Keep function body self-contained
  • Test in both obfuscated and plain runs
Avoid
  • Sensitive strings (API keys, URLs)
  • License/auth validation logic
  • Proprietary algorithms
  • Recursive functions
  • Nesting inside another no-virt function

Limitations

  • Self-recursion: Not supported - the function cannot call itself
  • Nesting: Cannot use WYNF_NO_VIRTUALIZE inside another no-virt function
  • Mutual recursion: Two no-virt functions cannot call each other

WYNF_CRASH

security

Immediately and securely crashes the VM, corrupting the VM context to prevent recovery or analysis. Use this as a last-resort defense when tampering or unauthorized access is detected.

Correct Usage

Loading...

Incorrect Usage

Loading...

Important: Direct Calls Only

WYNF_CRASH() must be called directly - it cannot be stored in a variable, passed as a callback, or referenced indirectly. The macro is detected at compile time and replaced with a secure crash sequence.

Behavior

When executed, the VM is immediately corrupted and enters an unrecoverable state. No code after WYNF_CRASH() will execute. This makes it ideal for anti-tamper checks where you want to ensure the script cannot be analyzed or recovered after a violation is detected.

Development Stub

To run un-obfuscated scripts without errors, add this stub at the top of your file:

Loading...

This stub is automatically ignored when the script is obfuscated. In development, it throws a standard Lua error to simulate the crash behavior.

Do
  • Use for anti-tamper responses
  • Call directly in conditionals
  • Use as last line of defense
  • Combine with WYNF_OBFUSCATED checks
Avoid
  • Storing in variables
  • Passing as function arguments
  • Using in table values
  • Indirect references of any kind

WYNF_IS_CALLER_WYNFUSCATE

security

Returns true if the current function was called from within your obfuscated code, and false if it was called from an external source like an exploit script. This protects your functions from being hijacked or invoked by malicious code, even when exploiters have access to function references.

Basic Example

Loading...

Protecting RemoteEvent Handlers

Loading...

Protecting Module Functions

Loading...

Correct Usage

Check once at the entry point, then proceed with your logic:

Loading...

Incorrect Usage

Loading...

Development Stub

To run un-obfuscated scripts without errors, add this stub at the top of your file:

Loading...

The stub always returns true, bypassing protection during development. The real protection activates when you obfuscate.

CLI/Development Environments

In CLI or development environments, this macro always returns true. This is expected - use Studio or production environments to test external caller detection.

Do
  • Use at the beginning of sensitive functions
  • Protect functions exposed via RemoteEvents
  • Combine with other validation layers
  • Test logic works when macro returns true
Avoid
  • Using as your only security measure
  • Calling in tight loops (expensive)
  • Assuming it catches all attack vectors
  • Expecting it to work in CLI environments

WYNF_ENC_STRING

security

Applies additional encryption layers to a string literal, providing extra protection for highly sensitive values like API keys, passwords, and encryption keys.

Basic Example

Loading...

When to Use

  • API Keys — External service credentials
  • Encryption Keys — Keys used to encrypt/decrypt game data
  • License Validation — Strings used in license checking logic
  • Admin Passwords — Hardcoded fallback credentials
  • Secret URLs — Hidden API endpoints

When NOT to Use

  • Frequently accessed strings — Each access has overhead
  • Strings in tight loops — Performance impact multiplies
  • Non-sensitive UI text — Regular encryption is sufficient
  • Large strings — Encryption overhead increases with size

Performance Consideration

WYNF_ENC_STRING adds additional encryption layers which has a performance cost on each access. For strings accessed once or twice per session, this is negligible. For strings accessed frequently, consider using regular string encryption instead.

Example: Protecting an API Client

Loading...

Syntax Rules

Loading...

Development Stub

To run your script without obfuscation during development, add this stub at the top:

Loading...

This allows your code to run normally in Studio or CLI while developing. When obfuscated, the real macro takes over and provides the additional encryption.

Do
  • Use for your most sensitive secrets
  • Place at module scope or function entry
  • Combine with other security measures
  • Test code works before obfuscating
Avoid
  • Using in tight loops
  • Using for every string
  • Assuming strings are impossible to extract
  • Using with variables or expressions

WYNF_ENC_NUM

security

Protects a numeric literal by encoding it in an encrypted form, preventing magic numbers from being trivially found via memory scanning or static analysis.

Basic Example

Loading...

When to Use

  • Product IDs — Asset or game pass identifiers
  • Feature Flags — Numeric flags for premium features
  • Salts — Values used in hashing or validation
  • Thresholds — Limits you do not want easily modified
  • Magic Numbers — Any constant you want hidden

Correct Usage

Loading...

Incorrect Usage

Loading...

Performance Consideration

WYNF_ENC_NUM has overhead on each access. For best performance, assign once to a local variable and reuse that local throughout your code.

Development Stub

To run your script without obfuscation during development, add this stub at the top:

Loading...

This allows your code to run normally in Studio or CLI while developing. When obfuscated, the real macro takes over and provides the additional encryption.

Do
  • Use for sensitive magic numbers
  • Assign to a local once, reuse it
  • Use numeric literals only
  • Combine with other security measures
Avoid
  • Using variables as arguments
  • Using expressions
  • Calling repeatedly in tight loops
  • Assuming numbers are impossible to extract

WYNF_LINE

debug

Expands to the current source line number at compile time. This provides a stable line marker for logs and error messages without relying on VM debug info, which is stripped during obfuscation.

Basic Example

Loading...

When to Use

  • Error Messages — Include line numbers in error reports
  • Debug Logging — Track execution flow with stable markers
  • Support Tickets — Help users report issues with line references
  • Assertions — Add context to assertion failures

Correct Usage

Loading...

Incorrect Usage

Loading...

Development Stub

To run your script without obfuscation during development, add this stub at the top:

Loading...

This uses the Lua debug library to get the actual line number during development. When obfuscated, the macro is replaced with the compile-time line number.

Do
  • Use for error and debug messages
  • Call directly as a global function
  • Use to help with support tickets
  • Combine with other context info
Avoid
  • Shadowing with a local variable
  • Storing the function reference
  • Expecting runtime line tracking
  • Using for security purposes

WYNF_NO_UPVALUES

compatibility

Creates a lightweight wrapper around your function for compatibility with certain environments or APIs that have issues with virtualized functions used as callbacks. Your function remains fully protected — only the wrapper is simplified for compatibility.

Basic Example

Loading...

When to Use

  • Signal Callbacks — Functions connected to events or signals
  • Hook APIs — Functions passed to hooking or interception APIs
  • Third-Party Libraries — Callbacks passed to external libraries
  • Environment Compatibility — When you encounter errors with virtualized callbacks

Correct Usage

Loading...

Compatibility, Not Security

This macro is for compatibility purposes only. Your function body remains virtualized and protected, but the wrapper itself is simplified. Only use this when you encounter compatibility issues with callbacks — for normal functions, standard virtualization provides stronger protection.

Development Stub

To run your script without obfuscation during development, add this stub at the top:

Loading...

This simply returns the function as-is during development. When obfuscated, the macro creates the compatibility wrapper while keeping your code protected.

Do
  • Use for callbacks and signal handlers
  • Use when you hit compatibility issues
  • Wrap function literals directly
  • Test in your target environment
Avoid
  • Using for all functions (unnecessary)
  • Using when standard virtualization works
  • Expecting extra security benefits
  • Using for non-callback functions

WYNF_SECURE_CALL

security

Marks a function as VM-only callable. Calls to this function will only succeed when they originate from inside your obfuscated code. If an external script obtains a reference to this function and tries to call it directly, the call will be rejected.

Basic Example

Loading...

When to Use

  • Internal Helpers — Functions that should never be invoked from outside
  • Decoders — Functions that decode or decrypt sensitive data
  • Guard Logic — Internal security checks and validation functions
  • Sensitive Operations — Functions that would be dangerous if called out of band

When NOT to Use

  • Roblox Events — RemoteEvents, Signals, and UI callbacks are invoked by the engine, not the VM
  • Engine Callbacks — Any function passed to Roblox APIs that will call it externally

For callbacks and event handlers, use WYNF_SECURE_CALLBACK instead.

Fail-Closed Behavior

When an external caller attempts to invoke a WYNF_SECURE_CALL function, the call is rejected immediately (fail-closed). This is intentional — use this for functions that should never be called from outside under any circumstances.

Development Stub

To run your script without obfuscation during development, add this stub at the top:

Loading...

The stub returns the function as-is during development. When obfuscated, the real caller validation takes effect.

Do
  • Use for internal-only functions
  • Use for decoders and sensitive helpers
  • Use for functions that must never be called externally
  • Combine with other security measures
Avoid
  • Using for event handlers or callbacks
  • Using for functions called by Roblox APIs
  • Using when you need soft rejection
  • Using as your only security measure

WYNF_SECURE_CALLBACK

security

Returns a wrapped callback that performs a caller gate before invoking your function. Intended for event handlers and callbacks that are called by external systems like Roblox signals, RemoteEvents, and UI events.

Basic Example

Loading...

Roblox Examples

Loading...

Fail-Quiet Behavior

Unlike WYNF_SECURE_CALL, this macro uses fail-quiet behavior. If the caller is external, the callback simply returns nil instead of crashing. This is appropriate for callbacks where you want silent rejection rather than hard failure.

When to Use

  • RemoteEvent Handlers — OnServerEvent, OnClientEvent callbacks
  • BindableEvent Handlers — Internal signal callbacks
  • UI Callbacks — Button clicks, input handlers
  • RunService Connections — Heartbeat, RenderStepped callbacks
  • Any Engine Callback — Functions passed to Roblox APIs that will invoke them

Development Stub

To run your script without obfuscation during development, add this stub at the top:

Loading...

The stub returns the function as-is during development. When obfuscated, the wrapper provides caller validation while maintaining compatibility with engine callbacks.

Do
  • Use for event handlers and callbacks
  • Use for functions passed to Roblox APIs
  • Use when you need soft rejection
  • Wrap directly before passing to Connect()
Avoid
  • Using for internal-only functions (use WYNF_SECURE_CALL)
  • Using when you need fail-closed behavior
  • Using as your only security measure
  • Expecting it to prevent all callback attacks

WYNF_ENC_FUNC

security

Encrypts a function body at build time and returns a callable wrapper that decrypts and executes the function at runtime using a key provided by your server. This is designed for whitelist/key-server workflows where the correct decryption key is only available at runtime from a trusted source.

How It Works

  • Build time: The function is extracted, encrypted with your key, and stored as a separate payload
  • Runtime: On first call, the wrapper decrypts the function using the runtime key, patches the VM, and executes
  • Security: The encryption key never appears in the obfuscated output — it must come from your server

Signature

Loading...

Generating a Key

You need a secure 64-character hex string to use as your encryption/decryption key. We provide a built-in generator in the dashboard:

  1. Go to Dashboard → Settings
  2. Scroll down to the Developer Tools section
  3. Click Generate to create a cryptographically secure 64-character hex key
  4. Copy the key and store it securely on your server
  5. Use this same key for both encKeyHex64 in your script and as the runtime decKey returned by your server

Correct Usage

Loading...

Incorrect Usage

Loading...

Key Model

The runtime decKey must be the same 64-character hex string as the build-time encKeyHex64. Your server stores this key and returns it to authorized clients at runtime. If the server returns a different key (or the key is tampered with in transit), the decrypt/decode will fail and the wrapper will trap.

Key Security

The encryption key (encKeyHex64) is a compile-time input only — it is never emitted in the obfuscated output. The decryption key must come from your server at runtime, not hardcoded in your script. If you hardcode the decryption key, you defeat the entire purpose of this macro.

Fail-Closed on Wrong Key

If the decryption key is wrong or the payload is tampered with, the function will fail closed — crash or poison the VM, not return garbage. This ensures attackers cannot probe for partial decryption or use incorrect keys.

Current Limitations

  • The protected function must be a constant function literal (not a variable)
  • The protected function must not capture upvalues from outer scopes
  • The protected function must not contain nested function literals

Performance Notes

  • First call: Incurs decrypt + load overhead (cold path)
  • Subsequent calls: The dispatcher is cached for fast execution
  • No persistent cache: Decrypted proto is not stored in a globally dumpable structure

Development Stub

To run your script without obfuscation during development, add this stub at the top:

Loading...

This ignores the encryption key arguments and returns the function as-is during development. When obfuscated, the real macro encrypts the function and requires the correct runtime key.

Do
  • Fetch decryption key from your server
  • Use for whitelist/license workflows
  • Use constant function literals only
  • Keep protected functions self-contained
  • Handle key fetch failures gracefully
Avoid
  • Hardcoding the decryption key
  • Using variables for the function argument
  • Capturing upvalues in protected function
  • Nesting functions inside protected function
  • Using variables for the encryption key

When to Use What

WYNF_OBFUSCATED

Use to strip dev-only code from obfuscated output. Unreachable branches are completely removed at compile time — not just skipped at runtime. Good for dev stubs, debug logging, and environment-specific code paths.

WYNF_NO_VIRTUALIZE

Use only for performance-critical code that runs frequently and contains no sensitive information. The function runs as native Lua (minified only), bypassing VM protection entirely. Code inside is exposed - use for math, loops, and non-secret operations only.

WYNF_CRASH

Use as a last-resort defense when tampering or unauthorized access is detected. Immediately and securely crashes the VM, making recovery impossible. Must be called directly - cannot be stored or passed indirectly.

WYNF_IS_CALLER_WYNFUSCATE

Use to protect sensitive functions from being called by external code (exploits). Returns true if called from your obfuscated code, false otherwise. Check once at entry point - avoid using in loops due to stack walking overhead.

WYNF_ENC_STRING

Use for highly sensitive strings like API keys, passwords, and encryption keys. Adds additional encryption layers for extra protection. Avoid using in tight loops or for frequently accessed strings due to performance overhead.

WYNF_ENC_NUM

Use for sensitive magic numbers like product IDs, feature flags, salts, and thresholds. Prevents numbers from being trivially found via scanning. Assign once to a local and reuse for best performance.

WYNF_LINE

Use for debugging and error reporting. Returns the source line number at compile time, providing stable line markers for logs and error messages even after obfuscation.

WYNF_NO_UPVALUES

Use for callback compatibility when virtualized functions cause issues with certain APIs or environments. Creates a compatible wrapper while keeping your code protected.

WYNF_SECURE_CALL

Use for internal-only functions that should never be called from outside your obfuscated code. External calls are rejected (fail-closed). For callbacks passed to Roblox APIs, use WYNF_SECURE_CALLBACK instead.

WYNF_SECURE_CALLBACK

Use for event handlers and callbacks passed to Roblox APIs (RemoteEvents, signals, UI events). Unlike WYNF_SECURE_CALL, uses fail-quiet behavior (returns nil) for compatibility with engine-invoked callbacks.

WYNF_ENC_FUNC

Use for whitelist/key-server workflows where critical functions should only work with a valid runtime key from your server. The function is encrypted at build time and decrypted at runtime using a key that must be fetched from your backend — never hardcoded.