The Unity Offerwall SDK: Complete C# Integration Guide (2026)
Published August 22, 2026 — by the Perkox Developer Team
Unity is the engine behind a huge share of mobile games, and monetization is a core concern for every game developer. An offerwall lets your players earn in-game currency by completing real-world tasks — surveys, app downloads, free trials — which you then convert into gems, coins, or premium items. The Perkox Unity Offerwall SDK brings this capability to Unity with a clean C# API, native Android and iOS plugins, and seamless Unity Package Manager (UPM) installation.
This guide covers the complete integration: prerequisites, UPM installation, C# initialization, event handlers for rewards, Android and iOS build settings, server-side postback setup, testing, debugging, and an FAQ. Whether you are building a casual mobile game or a complex RPG, by the end of this guide your Unity project will display offers, track completions, and credit players securely.
If you are unfamiliar with how offerwalls work, start with our introduction to offerwalls. For native platform details, refer to the Android SDK guide and the iOS SDK guide. The postback guide covers server-side reward verification, and the security best practices guide is essential reading for protecting your integration.
Table of Contents
- Prerequisites
- Installation via Unity Package Manager
- C# Initialization
- Showing the Offerwall
- Event Handlers for Rewards
- Android and iOS Build Settings
- Server-Side Postback Setup
- Testing and Debugging
- FAQ
1. Prerequisites
Before installing the Perkox Unity SDK, verify your environment meets these requirements:
| Requirement | Minimum |
|---|---|
| Unity | 2021.3 LTS or later (including Unity 6) |
| Scripting Backend | Mono or IL2CPP |
| Android minSdkVersion | 23 (Android 6.0) |
| iOS Deployment Target | 14.0 |
| Xcode (for iOS builds) | 15.0+ |
| Perkox Publisher Account | Required — sign up free |
| App ID & API Key | Available in the Perkox dashboard |
You will also need your Postback Secret for server-side verification, available in the Perkox dashboard under App Settings → Postback. If you have not registered your game yet, create a publisher account here.
2. Installation via Unity Package Manager
The Perkox Unity SDK is distributed as a UPM package hosted on Perkox’s registry. You can install it through the Unity Editor or by editing your manifest.json directly.
2.1 Installing via the Unity Editor
- Open your Unity project.
- Go to Window → Package Manager.
- Click the + button in the top-left corner.
- Select Add package from git URL….
- Enter the Perkox SDK git URL:
https://github.com/perkox/unity-offerwall-sdk.git - Click Add. Unity will download and import the package.
2.2 Installing via manifest.json
Alternatively, add the package directly to your project’s Packages/manifest.json:
{
"dependencies": {
"com.perkox.offerwall": "https://github.com/perkox/unity-offerwall-sdk.git#1.2.0",
"com.unity.modules.android": "1.0.0",
"com.unity.modules.ios": "1.0.0"
}
}
Replace 1.2.0 with the latest version number. Check the Perkox documentation for the current release.
2.3 Importing Native Plugins
After installation, the package automatically places native plugins in the correct folders:
Plugins/Android/perkox-offerwall.aar— Android native libraryPlugins/iOS/PerkoxOfferwall.framework— iOS native frameworkPlugins/Perkox/PerkoxOfferwall.cs— C# binding script
Unity’s plugin importer settings are pre-configured, so you typically do not need to adjust them. Verify that the Android plugin is set to Android platform only and the iOS framework to iOS only in the Inspector.
3. C# Initialization
Initialize the SDK early in your game’s lifecycle — typically in a bootstrap scene or an initial-loading MonoBehaviour. The initialization call configures the SDK with your credentials and the current player’s ID.
using UnityEngine;
using Perkox;
public class PerkoxManager : MonoBehaviour
{
private const string APP_ID = "your-app-id";
private const string API_KEY = "your-publisher-api-key";
private async void Start()
{
var options = new PerkoxInitOptions
{
AppId = APP_ID,
ApiKey = API_KEY,
UserId = GetPlayerId(), // your internal player ID
IsTestMode = Debug.isDebugBuild,
LogLevel = PerkoxLogLevel.Info
};
bool success = await PerkoxOfferwall.InitializeAsync(options);
if (success)
{
Debug.Log("[Perkox] SDK initialized successfully");
}
else
{
Debug.LogError("[Perkox] SDK initialization failed");
}
}
private string GetPlayerId()
{
// Return your game's stable player ID
// e.g., from PlayerPrefs, a backend auth call, or PlayFab
return PlayerPrefs.GetString("player_id", "default-player");
}
}
PerkoxInitOptions Structure
namespace Perkox
{
public class PerkoxInitOptions
{
public string AppId;
public string ApiKey;
public string UserId;
public bool IsTestMode;
public PerkoxLogLevel LogLevel;
public Dictionary<string, string> CustomParams;
}
public enum PerkoxLogLevel
{
None,
Error,
Info,
Debug
}
}
Debug.isDebugBuild for IsTestMode so development builds use test offers (instant conversion) while release builds use real offers. This avoids accidentally shipping with test mode enabled.
Making the Manager Persistent
Attach the PerkoxManager script to a GameObject in your first scene and mark it with DontDestroyOnLoad so the SDK persists across scene changes:
void Awake()
{
DontDestroyOnLoad(gameObject);
}
4. Showing the Offerwall
Once initialized, showing the offerwall is a single async call. The SDK opens a native view controller (iOS) or activity (Android) over your Unity game.
using UnityEngine;
using Perkox;
using UnityEngine.UI;
public class OfferwallButton : MonoBehaviour
{
public Button earnButton;
private void Start()
{
earnButton.onClick.AddListener(OnEarnButtonClicked);
}
private async void OnEarnButtonClicked()
{
bool hasOffers = await PerkoxOfferwall.HasOffersAvailableAsync();
if (!hasOffers)
{
Debug.Log("[Perkox] No offers available for this user");
return;
}
await PerkoxOfferwall.ShowOfferwallAsync(new PerkoxShowOptions
{
Placement = "store_button",
OnClose = () =>
{
Debug.Log("[Perkox] Offerwall closed by player");
RefreshPlayerBalance();
}
});
}
private void RefreshPlayerBalance()
{
// Refresh the player's currency display
}
}
Placement Tags
Placements let you track which entry point generates the most revenue. Common placements for games:
store_button— next to the in-app purchase button in your shopgame_over— shown at the end of a level or matchrewarded_prompt— when a player tries to buy something they cannot affordmain_menu— a button on the main menu screen
5. Event Handlers for Rewards
The SDK emits C# events for reward completions, offerwall lifecycle, and errors. Subscribe to these events to update your game UI in real time. Remember: client-side events are for UX only — always verify rewards server-side via postback.
using UnityEngine;
using Perkox;
public class PerkoxEventListener : MonoBehaviour
{
private void OnEnable()
{
PerkoxEvents.OnReward += HandleReward;
PerkoxEvents.OnOfferwallOpen += HandleOfferwallOpen;
PerkoxEvents.OnOfferwallClose += HandleOfferwallClose;
PerkoxEvents.OnError += HandleError;
}
private void OnDisable()
{
PerkoxEvents.OnReward -= HandleReward;
PerkoxEvents.OnOfferwallOpen -= HandleOfferwallOpen;
PerkoxEvents.OnOfferwallClose -= HandleOfferwallClose;
PerkoxEvents.OnError -= HandleError;
}
private void HandleReward(PerkoxReward reward)
{
Debug.Log($"[Perkox] Reward earned: {reward.Payout} coins " +
$"from offer '{reward.OfferName}' " +
$"(txn: {reward.TransactionId})");
// Show reward animation / toast in-game
ShowRewardAnimation(reward.Payout, reward.OfferName);
// NOTE: Do NOT credit the player's actual balance here.
// The server-side postback is the source of truth.
}
private void HandleOfferwallOpen()
{
Debug.Log("[Perkox] Offerwall opened");
// Pause game audio / music
AudioListener.pause = true;
}
private void HandleOfferwallClose()
{
Debug.Log("[Perkox] Offerwall closed");
// Resume game audio
AudioListener.pause = false;
}
private void HandleError(PerkoxError error)
{
Debug.LogError($"[Perkox] Error {error.Code}: {error.Message}");
}
private void ShowRewardAnimation(int payout, string offerName)
{
// Trigger your game's reward UI (e.g., a particle effect + text popup)
}
}
PerkoxReward Structure
namespace Perkox
{
public struct PerkoxReward
{
public string TransactionId; // unique per completion
public string OfferId;
public string OfferName;
public int Payout; // in your virtual currency units
public int PayoutUsdCents; // in USD cents
public string UserId;
public long Timestamp; // Unix epoch ms
}
public struct PerkoxError
{
public string Code;
public string Message;
}
}
6. Android and iOS Build Settings
6.1 Android Build Settings
The SDK’s UPM package includes a Unity Plugin manifest (perkox-offerwall.androidlib) that automatically merges required permissions and activities into your AndroidManifest.xml. Verify the following in your project settings:
Player Settings → Other Settings → Identification:
| Setting | Required Value |
|---|---|
| Minimum API Level | Android 6.0 (API level 23) |
| Scripting Backend | IL2CPP (recommended) or Mono |
| Target Architectures | ARM64 (required for Google Play); ARMv7 optional |
Gradle configuration: The SDK’s AAR includes its own dependencies, which Unity’s Gradle resolver handles automatically. If you use a custom mainTemplate.gradle, ensure it includes:
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
}
ProGuard / R8: If you enable minification, add these rules to your proguard-user.txt:
-keep class com.perkox.offerwall.** { *; }
-keepclassmembers class com.perkox.offerwall.** { *; }
-dontwarn com.perkox.offerwall.**
For the complete native Android configuration, see the Android SDK guide.
6.2 iOS Build Settings
The SDK includes a PostProcessBuild script that automatically configures the Xcode project after Unity generates it. This script adds the Perkox framework to the project, sets the deployment target, and injects required Info.plist entries. Verify the following:
Player Settings → Other Settings → Configuration:
| Setting | Required Value |
|---|---|
| Target iOS Version | 14.0 or later |
| Scripting Backend | IL2CPP (required for iOS) |
| Architecture | ARM64 |
| Camera Usage Description | Required if any offer uses the camera |
Info.plist entries (auto-injected):
// The PostProcessBuild script adds these automatically:
// - LSApplicationQueriesSchemes: https
// - NSAppTransportSecurity: allows loading offerwall content over HTTPS
If your game already uses a PostProcessBuild script, ensure there are no conflicts. The Perkox script runs at priority 100 and handles only Perkox-specific modifications. For the complete native iOS configuration, see the iOS SDK guide.
6.3 Universal Windows Platform (UWP) and Other Platforms
The Perkox Unity SDK currently supports Android and iOS. If you are building for other platforms (UWP, WebGL, Standalone), the SDK’s C# layer will compile but InitializeAsync will return false and ShowOfferwallAsync will be a no-op. This lets you keep a single codebase without conditional compilation for unsupported platforms.
// Safe to call on any platform — no-op on unsupported ones
#if UNITY_ANDROID || UNITY_IOS
await PerkoxOfferwall.ShowOfferwallAsync(options);
#else
Debug.Log("[Perkox] Offerwall not supported on this platform");
#endif
7. Server-Side Postback Setup
The postback is the secure channel through which Perkox notifies your backend when a player completes an offer. This is where you actually credit the player’s balance. Configure the postback URL in the Perkox dashboard under App Settings → Postback.
Postback URL Format
https://api.yourgame.com/perkox/postback?user_id={user_id}&txn_id={txn_id}&payout={payout}&offer_id={offer_id}&signature={signature}
Perkox replaces the placeholders with actual values and appends an HMAC-SHA256 signature. Your server must verify the signature before crediting the player.
Server-Side Verification (C# / ASP.NET Core)
using Microsoft.AspNetCore.Mvc;
using System.Security.Cryptography;
using System.Text;
[ApiController]
[Route("perkox/postback")]
public class PerkoxPostbackController : ControllerBase
{
private const string PERKOX_SECRET = "your-postback-secret";
private readonly IGameService _gameService;
public PerkoxPostbackController(IGameService gameService)
{
_gameService = gameService;
}
[HttpGet]
public async Task<IActionResult> HandlePostback(
[FromQuery] string user_id,
[FromQuery] string txn_id,
[FromQuery] string payout,
[FromQuery] string offer_id,
[FromQuery] string signature)
{
// Reconstruct the signature
var data = $"{user_id}{txn_id}{payout}{offer_id}";
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(PERKOX_SECRET));
var expectedSigBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
var expectedSig = BitConverter.ToString(expectedSigBytes)
.Replace("-", "").ToLower();
if (signature != expectedSig)
{
return Unauthorized("Invalid signature");
}
// Idempotency check — prevent double-crediting
if (await _gameService.IsTransactionProcessedAsync(txn_id))
{
return Ok("OK"); // Already processed, acknowledge with 200
}
// Credit the player
var payoutAmount = int.Parse(payout);
await _gameService.CreditPlayerAsync(user_id, payoutAmount, txn_id);
return Ok("OK");
}
}
Node.js Alternative
const express = require('express');
const crypto = require('crypto');
const app = express();
const PERKOX_SECRET = 'your-postback-secret';
app.get('/perkox/postback', async (req, res) => {
const { user_id, txn_id, payout, offer_id, signature } = req.query;
const data = `${user_id}${txn_id}${payout}${offer_id}`;
const expectedSig = crypto
.createHmac('sha256', PERKOX_SECRET)
.update(data)
.digest('hex');
if (signature !== expectedSig) {
return res.status(403).send('Invalid signature');
}
if (await isDuplicateTxn(txn_id)) {
return res.status(200).send('OK');
}
await creditPlayer(user_id, parseInt(payout, 10), txn_id);
res.status(200).send('OK');
});
Player ID Consistency
The UserId you pass to InitializeAsync in Unity must match the user_id in the postback. Use a stable, server-assigned player ID — never a device-specific identifier, because players switch devices. If you use PlayFab, Firebase Auth, or a custom backend, use that service’s user ID.
8. Testing and Debugging
8.1 Test Mode
When IsTestMode is true, the SDK displays test offers that convert instantly. This lets you verify your entire flow — show offerwall, complete offer, receive C# event, receive postback — without waiting for real offer completions.
var options = new PerkoxInitOptions
{
AppId = APP_ID,
ApiKey = API_KEY,
UserId = "test-player-1",
IsTestMode = true,
LogLevel = PerkoxLogLevel.Debug
};
await PerkoxOfferwall.InitializeAsync(options);
8.2 Log Levels
| Level | Output |
|---|---|
None |
No logs |
Error |
Errors only (production default) |
Info |
Errors + lifecycle events |
Debug |
Full verbose logs including native bridge calls |
With PerkoxLogLevel.Debug, the SDK logs all native bridge calls to the Unity Console, visible in both the Editor and device logs (logcat on Android, Console.app on iOS).
8.3 Testing on Device
Test mode offers work on real devices and in the Unity Editor’s device simulation. For full end-to-end testing, build to a physical device:
// Build and run on Android
File → Build Settings → Android → Build and Run
// Build and run on iOS
File → Build Settings → iOS → Build
// Then open the generated Xcode project and run on device
8.4 Debugging Postbacks
Use the Postback Tester in the Perkox dashboard to send a test postback to your server. This verifies your endpoint, signature validation, and idempotency logic without completing a real offer. Check your server logs to confirm receipt and processing.
8.5 Common Issues
| Issue | Cause | Fix |
|---|---|---|
| SDK not found after install | UPM package not imported | Check Package Manager; verify manifest.json URL |
| iOS build fails in Xcode | Framework not linked or deployment target too low | Set iOS target to 14.0+; ensure PostProcessBuild ran |
| Android build fails (Gradle) | Missing dependencies or ProGuard stripping | Add Gradle deps and ProGuard keep rules |
| Offerwall blank in release build | IsTestMode left true | Set IsTestMode = Debug.isDebugBuild |
| Postback not received | Endpoint unreachable or not returning 200 | Test with curl; check server firewall; ensure 200 response |
| No reward event in Unity | Event handler not subscribed or GameObject destroyed | Subscribe in OnEnable; use DontDestroyOnLoad |
9. FAQ
Does the Perkox Unity SDK work with both Android and iOS builds?
Yes. The SDK includes native plugins for both Android (Kotlin/Java via AAR) and iOS (Swift via framework). A single C# API handles both platforms through platform-specific compilation. You do not need to write separate code for each platform.
Can I use the SDK with Unity’s IL2CPP backend?
Yes. The SDK is fully compatible with IL2CPP, which is required for iOS builds and recommended for Android 64-bit builds. The native plugins are invoked through P/Invoke and Unity’s platform-specific compilation directives.
Do I need to modify the AndroidManifest.xml or Info.plist?
The SDK’s UPM package includes a Unity Plugin manifest that automatically merges required permissions and activities into your AndroidManifest.xml. For iOS, required Info.plist entries are injected via the PostProcessBuild script. You typically do not need to edit these files manually.
How do I handle rewards safely in a Unity game?
Use client-side C# events for immediate UI feedback (showing a reward animation), but credit the player’s actual balance via the server-side postback. The postback sends an HTTP request to your backend with an HMAC signature. Verify the signature on your server before crediting.
What Unity versions are supported?
The SDK supports Unity 2021.3 LTS and later, including Unity 6 (2024+). Both the Mono and IL2CPP scripting backends are supported. The minimum API level for Android is 23 (Android 6.0), and the minimum iOS deployment target is 14.0.
Conclusion
The Perkox Unity Offerwall SDK gives game developers a clean C# API to integrate offerwall monetization with native performance on both Android and iOS. With UPM installation, automatic native plugin configuration, event-driven reward handling, and a secure server-side postback system, you can go from package import to first reward in a single development session.
Unity games are particularly well-suited to offerwall monetization because players already expect virtual currencies and in-game economies. By placing the offerwall button next to your in-app purchase button, at the game-over screen, or when a player cannot afford an item, you give free-to-play users a way to earn currency without spending real money — while you still earn revenue from each completed offer.
Always pair the SDK with a properly configured server-side postback and follow the security best practices to protect your game’s economy from abuse.
Ready to monetize your Unity game?
Create your free Perkox publisher account and get your API keys in minutes.
Related guides: What is an Offerwall? · Android SDK Guide · iOS SDK Guide · Postback Guide · Security Best Practices
