Perkox iOS SDK: Complete Offerwall Integration Guide for Swift Developers (2026)
If you’re building an iOS app and want to monetize beyond in-app purchases and banner ads, an offerwall is one of the highest-earning formats available — and the Perkox iOS SDK makes it drop-in simple. This guide walks through everything from what an offerwall is all the way to server-side reward validation, App Store compliance, and debugging in Xcode.
Whether you’re shipping a new game or adding a rewarded monetization layer to an existing utility app, this tutorial covers the complete iOS offerwall integration workflow with real, copy-paste-ready Swift code.
Table of Contents
- 1. What the Perkox iOS SDK Does
- 2. Prerequisites
- 3. Installation via Local Swift Package
- 4. Quick Start: Swift Implementation
- 5. Event Handling: onReward and onClose
- 6. Server-Side Reward Validation
- 7. Configuration: appId, sdkKey, playerId
- 8. App Store Compliance (ATT & Privacy Manifest)
- 9. Testing and Sandbox
- 10. Common Xcode Issues
- 11. FAQ
- 12. Get Started
1. What the Perkox iOS SDK Does
The Perkox iOS SDK is a native Swift framework that embeds a fully-managed offerwall inside your iOS application. An offerwall is a rewarded advertising unit: users see a list of available offers — completing surveys, downloading and trying other apps, signing up for services, or watching videos — and earn in-app currency or rewards for each completed action.
From a developer’s perspective, the SDK handles the entire offerwall lifecycle:
- Offer fetching and display: The SDK pulls a personalized offer catalog from Perkox servers and renders it in a modally-presented web view. No UI work required on your end.
- Conversion tracking: Perkox’s backend tracks offer completions across its advertiser network. You don’t need to build any tracking infrastructure.
- Reward callbacks: The SDK exposes
onRewardandonCloseclosures so your app can react to events in real time — updating a balance display, showing a toast, or dismissing the offerwall. - Server-side postbacks: For production-grade security, Perkox sends a signed postback to your backend URL whenever a reward is confirmed, so you can credit the user’s account without trusting the client.
The SDK ships as a precompiled PerkoxOfferwall.xcframework bundled inside a local Swift Package, meaning you get native performance, no CocoaPods dependency, and full compatibility with Apple’s modern packaging workflow.
2. Prerequisites
Before you begin the swift offerwall integration, make sure your development environment meets these requirements:
| Requirement | Minimum Version |
|---|---|
| iOS Deployment Target | iOS 13.0+ |
PerkoxOfferwall.xcframework |
Swift 5.7+ |
| Xcode | Xcode 14.0+ |
| Device Architectures | arm64 device, arm64 & x86_64 simulator |
| Perkox Account | Active publisher account at pub.perkox.com |
You’ll also need:
- An app registered in the Perkox publisher dashboard — this gives you your
appIdandsdkKey. - A backend endpoint capable of receiving and validating postback requests.
- A basic understanding of Swift and Xcode project structure.
3. Installation via Local Swift Package
The Perkox iOS SDK is distributed as a downloadable zip containing a Swift Package with the Package.swift manifest and the PerkoxOfferwall.xcframework. Unlike registry-hosted packages, you add it locally — which means no network dependency resolution, faster builds, and full offline support.
Step 1: Download the SDK Zip
Log in to the Perkox publisher dashboard, navigate to SDK Downloads, and download the iOS SDK zip file (e.g., PerkoxOfferwall-iOS-1.x.x.zip).
Step 2: Extract the Archive
Extract the zip to a stable location inside or near your project directory. The extracted folder must contain a Package.swift file and the PerkoxOfferwall.xcframework binary:
PerkoxOfferwall-iOS/
├── Package.swift
├── Sources/
│ └── PerkoxOfferwall/
│ └── PerkoxOfferwall.swift
└── PerkoxOfferwall.xcframework/
├── ios-arm64/
├── ios-arm64_x86_64-simulator/
└── Info.plist
~/Projects/MyApp/Vendor/PerkoxOfferwall-iOS/ and add it to version control or a shared team storage location. Avoid placing it in /tmp or other ephemeral paths.Step 3: Add the Local Package in Xcode
Follow these exact Xcode menu paths:
- Open your project in Xcode.
- Select your app target in the project navigator.
- Go to the General tab, scroll to Frameworks, Libraries, and Embedded Content.
- In the menu bar, select File → Add Package Dependencies…
- In the dialog that appears, click Add Local… in the bottom-left corner.
- Navigate to the extracted
PerkoxOfferwall-iOSfolder (the one containingPackage.swift) and click Add Package. - Xcode resolves the package. Select the PerkoxOfferwall library and click Add Package to link it to your target.
Step 4: Verify the Framework Is Embedded
After adding the package, confirm that PerkoxOfferwall.xcframework appears under Frameworks, Libraries, and Embedded Content with the embed setting set to Embed & Sign. If it shows Do Not Embed, change the dropdown — the SDK must be embedded for the runtime to load the binary.
Step 5: Import and Build
Add the import to any Swift file where you’ll use the SDK, then build (⌘B):
import PerkoxOfferwall
If the build succeeds with no errors, the SDK is properly linked. You’re ready to write code.
4. Quick Start: Swift Implementation
With the SDK installed, implementing the offerwall takes only a few lines of Swift. The core API surface is intentionally minimal: you create an Offerwall instance, optionally attach event closures, and launch it from a view controller.
Here’s the complete quick-start implementation:
import UIKit
import PerkoxOfferwall
class OfferwallViewController: UIViewController {
private var offerwall: Offerwall?
override func viewDidLoad() {
super.viewDidLoad()
setupOfferwall()
}
private func setupOfferwall() {
// Create the offerwall instance with credentials from the Perkox dashboard
offerwall = PerkoxOfferwall.create(
appId: "YOUR_APP_ID",
sdkKey: "YOUR_SDK_KEY",
playerId: "user_12345"
)
// Register event handlers
offerwall?.onReward = { reward in
// reward is [String: Any?] with keys: amount, status, txid, player_id
DispatchQueue.main.async {
let amount = reward["amount"] as? Double ?? 0.0
let txid = reward["txid"] as? String ?? "unknown"
print("Reward earned: \(amount) (txid: \(txid))")
self.updateBalanceDisplay()
}
}
offerwall?.onClose = {
DispatchQueue.main.async {
print("Offerwall closed by user")
self.navigationItem.rightBarButtonItem?.isEnabled = true
}
}
}
@IBAction func showOfferwallTapped(_ sender: UIButton) {
// Present the offerwall modally from the current view controller
offerwall?.launch(viewController: self)
}
private func updateBalanceDisplay() {
// Refresh your in-app currency balance label
// e.g., balanceLabel.text = "\(UserWallet.currentBalance)"
}
}
Let’s break down what’s happening:
PerkoxOfferwall.create(appId:sdkKey:playerId:)initializes and returns anOfferwallobject. This is your handle to the SDK — store it as a property so it stays in memory while the offerwall is active.offerwall.launch(viewController:)presents the offerwall UI modally from whichever view controller you pass in. The SDK manages the presentation and dismissal internally.onRewardfires whenever a reward event is detected. The callback dictionary includesamount,status,txid, andplayer_id.onClosefires when the user dismisses the offerwall. Use it to re-enable buttons or refresh UI state.
5. Event Handling: onReward and onClose
Event handling is where most of your app-side logic lives. The Perkox iOS SDK exposes two closures on the Offerwall type: onReward and onClose. Understanding their threading behavior and payload structure is critical for a smooth user experience.
The onReward Closure
The onReward closure receives a dictionary of type [String: Any?] containing the following keys:
| Key | Type | Description |
|---|---|---|
amount |
Double |
Reward amount in your app’s virtual currency units |
status |
String |
Reward status (e.g., “credited”, “pending”) |
txid |
String |
Unique transaction ID for this reward event |
player_id |
String |
The player ID you passed to create() |
DispatchQueue.main.async for UI Updates
The SDK fires closures on a background thread to avoid blocking the offerwall’s web view. Any UI manipulation — updating labels, showing alerts, toggling buttons — must be dispatched to the main queue. Failing to do so will cause runtime warnings and potential crashes:
offerwall?.onReward = { reward in
// ⚠️ This runs on a background thread
let amount = reward["amount"] as? Double ?? 0.0
let status = reward["status"] as? String ?? "unknown"
let txid = reward["txid"] as? String ?? "N/A"
let playerId = reward["player_id"] as? String ?? "N/A"
DispatchQueue.main.async {
// ✅ Safe to update UI here
self.balanceLabel.text = "Balance: +\(amount)"
self.showRewardToast(amount: amount, txid: txid)
// Optional: trigger a local backend sync
self.syncWalletWithServer()
}
// Logging is fine on background
print("[Perkox] Reward: amount=\(amount) status=\(status) txid=\(txid) player=\(playerId)")
}
The onClose Closure
The onClose closure takes no arguments and fires when the user taps the close button or otherwise dismisses the offerwall. Use it to restore your app’s UI state:
offerwall?.onClose = {
DispatchQueue.main.async {
// Re-enable the offerwall button
self.offerwallButton.isEnabled = true
self.offerwallButton.alpha = 1.0
// Optionally refresh the user's balance from your backend
self.fetchUpdatedBalance()
}
}
onReward as the source of truth for crediting rewards. Client-side callbacks can be intercepted, spoofed, or missed entirely if the user closes the app. Always validate rewards server-side via postback. See Section 6 and the SDK security best practices guide.6. Server-Side Reward Validation
This is the single most important section in this guide. Client-side reward callbacks are a convenience for UI updates only — they are not a reliable or secure mechanism for crediting user accounts. Here’s why:
- Tampering: A motivated user with a jailbroken device can hook into the SDK’s runtime and fire fake
onRewardcallbacks with arbitrary amounts. - Network loss: If the user’s device loses connectivity or the app is force-quit, the callback may never fire even though the offer was genuinely completed.
- Replay attacks: Without server-side deduplication, the same reward could be credited multiple times.
- Duplicate crediting: If the user reinstalls the app or switches devices, client-side state is lost, leading to double-credits or missed credits.
The correct architecture is a server-side postback: Perkox’s servers send an HTTP request to your backend when an offer is confirmed, and your backend credits the user after verifying the request’s authenticity.
Postback URL Format
Configure a postback URL in the Perkox dashboard. Perkox will make an HTTP GET request to this URL with the following query parameters:
https://yourdomain.com/postback?offer_id={offer_id}&payout={payout}&status={status}&player_id={player_id}&reward_amount={reward_amount}
The available macro placeholders are:
| Parameter | Description |
|---|---|
{offer_id} |
Unique identifier of the completed offer |
{payout} |
The payout amount (what you earn as publisher) |
{status} |
Reward status: credited or pending |
{player_id} |
The player ID you passed to the SDK |
{reward_amount} |
The reward amount in your app’s virtual currency |
Backend Postback Handler Example
Here’s a minimal Node.js/Express handler that validates and deduplicates postbacks:
const express = require('express');
const app = express();
app.get('/postback', async (req, res) => {
const { offer_id, payout, status, player_id, reward_amount } = req.query;
// 1. Validate required parameters
if (!offer_id || !player_id || !reward_amount) {
return res.status(400).send('Missing parameters');
}
// 2. Check for duplicate transactions (idempotency)
const existing = await db.query(
'SELECT * FROM reward_transactions WHERE txid = ?',
[`perkox_${offer_id}_${player_id}`]
);
if (existing.length > 0) {
return res.status(200).send('Duplicate - already credited');
}
// 3. Only credit if status is "credited"
if (status !== 'credited') {
return res.status(200).send('Pending - not credited');
}
// 4. Credit the user's account
await db.query(
'INSERT INTO reward_transactions (txid, player_id, amount, source) VALUES (?, ?, ?, ?)',
[`perkox_${offer_id}_${player_id}`, player_id, parseFloat(reward_amount), 'perkox']
);
await db.query(
'UPDATE user_wallets SET balance = balance + ? WHERE player_id = ?',
[parseFloat(reward_amount), player_id]
);
// 5. Respond 200 OK so Perkox doesn't retry
res.status(200).send('OK');
});
app.listen(3000);
7. Configuration: appId, sdkKey, playerId
The PerkoxOfferwall.create(appId:sdkKey:playerId:) method takes three parameters. Getting these right is essential for the SDK to function correctly.
appId
Your application’s unique identifier on the Perkox platform. Find it in the publisher dashboard under Apps → Your App → Settings. It’s a string like "app_a1b2c3d4e5". Using the wrong appId will result in an empty offerwall or no offers being returned.
sdkKey
A secret key that authenticates the SDK with Perkox servers. Also found in the dashboard under your app’s settings. Treat this like a credential — do not hardcode it in client-side source code that’s pushed to a public GitHub repo. While the SDK key alone cannot credit rewards (that requires the postback), exposing it could allow unauthorized apps to display your offers.
playerId
A unique identifier for the current user in your system. This is the value Perkox will send back in the postback’s {player_id} field, so your backend can attribute the reward to the correct account. Best practices for playerId:
- Use a stable, unique identifier from your user database (not a display name).
- Avoid using email addresses or phone numbers for privacy reasons — prefer an opaque user ID or UUID.
- Set it at SDK initialization time, ideally right after login.
- If your app supports anonymous/guest users, generate a persistent UUID stored in the keychain.
// Example: playerId from your auth system
let playerId = AuthManager.shared.currentUserId ?? KeychainHelper.getOrCreateGuestId()
offerwall = PerkoxOfferwall.create(
appId: Configuration.perkoxAppId,
sdkKey: Configuration.perkoxSdkKey,
playerId: playerId
)
8. App Store Compliance (ATT & Privacy Manifest)
Apple’s App Store has strict requirements around user privacy and tracking. The Perkox iOS SDK is designed to be compliant, but you as the app developer are responsible for proper configuration.
App Tracking Transparency (ATT)
If your app — or any third-party SDK it includes — engages in tracking as defined by Apple’s App Tracking Transparency framework, you must request ATT permission using the ATTrackingManager.requestTrackingAuthorization API before the SDK fetches offers.
import AppTrackingTransparency
import AdSupport
func requestATTPermission(completion: @escaping () -> Void) {
ATTrackingManager.requestTrackingAuthorization { status in
DispatchQueue.main.async {
completion()
}
}
}
// Call before launching the offerwall:
requestATTPermission {
self.offerwall?.launch(viewController: self)
}
Add the ATT usage description to your Info.plist:
<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized offers and rewards.</string>
Privacy Manifest (PrivacyInfo.xcprivacy)
Since Spring 2024, Apple requires all apps to include a Privacy Manifest (PrivacyInfo.xcprivacy) that declares the data types collected and the tracking domains used by you and your SDKs. The Perkox SDK collects the following data categories that you should declare:
- Device ID — used for offer attribution and fraud prevention.
- Product Interaction — offer clicks and completions.
- Coarse Location — used to serve region-appropriate offers (if enabled).
Create a PrivacyInfo.xcprivacy file in your app target and declare the SDK’s data usage. Refer to Apple’s Privacy Manifest Files documentation for the exact format.
App Privacy Nutrition Label
In App Store Connect, under App Privacy, declare that your app uses third-party SDKs for advertising and that data linked to the user (such as device ID) is collected for the purpose of serving third-party ads. Offerwalls are an approved monetization format, and thousands of apps use them without App Store issues — just be transparent in your privacy disclosures.
9. Testing and Sandbox
Before shipping to production, you need to test the full offerwall flow — from presentation to reward crediting — in a controlled environment.
Sandbox Mode
The Perkox dashboard provides a sandbox mode that serves test offers instead of real advertiser campaigns. Enable it by toggling Sandbox Mode in your app’s settings in the dashboard. In sandbox mode:
- Test offers appear immediately and convert quickly (often within seconds).
- Rewards are credited in the postback with
status=credited. - No real advertiser budget is consumed.
- You can simulate both success and failure paths.
Testing the Postback
To test your postback endpoint without completing real offers, use the Postback Tester tool in the Perkox dashboard. It sends a simulated GET request to your configured postback URL with sample data, so you can verify your backend handles it correctly.
Simulator vs. Device Testing
The PerkoxOfferwall.xcframework includes slices for both arm64 devices and arm64/x86_64 simulators, so you can test the full flow on the iOS Simulator. However, some offers (particularly app-install offers) require a real device because they need the App Store and device-level attribution. For full end-to-end testing, always do a final pass on a physical device.
Checklist Before Going Live
- Sandbox mode disabled in dashboard.
- Postback URL set to your production endpoint (HTTPS, publicly accessible).
- Postback handler tested with duplicate detection and idempotency.
- ATT permission prompt shown before first offerwall launch.
- Privacy manifest file included in the app bundle.
- App Privacy Nutrition Label filled out in App Store Connect.
appIdandsdkKeypoint to the production app (not a test app).- Reward UI updates dispatched to the main queue.
10. Common Xcode Issues
Here are the most frequent issues developers encounter when integrating the Perkox iOS SDK, along with their solutions.
Issue 1: “No such module ‘PerkoxOfferwall’”
Cause: The local package wasn’t added correctly, or the build hasn’t completed since adding it.
Fix: In Xcode, go to File → Add Package Dependencies → Add Local and re-select the folder containing Package.swift. Then do a clean build (⌘Shift+K followed by ⌘B). Ensure the PerkoxOfferwall product is linked to your app target under General → Frameworks, Libraries, and Embedded Content.
Issue 2: “Unsupported Architecture” or “Building for Simulator but xcframework only contains arm64”
Cause: Older Xcode versions or missing simulator slices.
Fix: Ensure you’re using Xcode 14.0+ and have downloaded the latest SDK version. The framework includes ios-arm64_x86_64-simulator slices for full simulator support. If the issue persists, verify your EXCLUDED_ARCHS build setting is empty for the simulator configuration.
Issue 3: “Framework not embedded” runtime crash
Cause: The xcframework is set to “Do Not Embed” in the target’s Frameworks list.
Fix: Select the app target → General → Frameworks, Libraries, and Embedded Content → change the embed dropdown for PerkoxOfferwall.xcframework from “Do Not Embed” to Embed & Sign.
Issue 4: Offerwall appears blank or shows no offers
Cause: Incorrect appId or sdkKey, or sandbox mode is off but the app isn’t approved yet.
Fix: Double-check credentials from the dashboard. If your app is still in review, enable sandbox mode to see test offers. Also verify network connectivity and that no firewall blocks *.perkox.com domains.
Issue 5: UI freezes or “Main Thread Checker” warnings
Cause: UI updates made inside onReward or onClose without dispatching to the main queue.
Fix: Wrap all UI code in DispatchQueue.main.async { ... } as shown in the event handling section above.
Issue 6: Package resolution fails with “Package.swift not found”
Cause: You selected the wrong folder — perhaps a parent or nested subdirectory.
Fix: The folder you select via Add Local must directly contain the Package.swift file. Check the extracted directory structure and select the correct level.
11. FAQ
Q1: What is the Perkox iOS SDK and what does it do?
The Perkox iOS SDK is a Swift framework that lets you embed an offerwall inside any iOS app. It presents a curated list of offers (surveys, app installs, sign-ups) that users can complete to earn in-app rewards. The SDK handles offer display, tracking, and reward callbacks, while your backend validates rewards via a server-side postback URL for security. See our introduction to offerwalls for more context.
Q2: What are the minimum requirements for the Perkox iOS SDK?
The SDK requires iOS 13.0+, Swift 5.7+, and Xcode 14.0+. It supports both arm64 physical devices and arm64/x86_64 simulators via the included PerkoxOfferwall.xcframework. No CocoaPods or Carthage installation is needed — the SDK is added as a local Swift Package.
Q3: Can I rely on client-side onReward callbacks to credit users?
No. Client-side callbacks run on the user’s device and can be tampered with, spoofed, or lost if the app is closed. Always credit rewards through a server-side postback URL that your backend verifies. Use onReward only for UI feedback such as updating a balance display or showing a toast notification. Read the complete postback guide and security best practices for details.
Q4: How do I install the Perkox iOS SDK in Xcode?
Download the SDK zip from the Perkox dashboard, extract it to a local folder, then in Xcode go to File → Add Package Dependencies → Add Local, select the extracted folder containing Package.swift, and add the PerkoxOfferwall library target to your app. Set the framework to Embed & Sign. No remote SPM registry or CocoaPods is needed.
Q5: Is the Perkox iOS SDK compliant with App Store guidelines?
Yes. The SDK is designed for App Store compliance. You must request App Tracking Transparency (ATT) permission if your app tracks users, include a Privacy Manifest (PrivacyInfo.xcprivacy), and disclose data collection in your App Privacy Nutrition Label. Offerwalls are an approved monetization method under Apple’s guidelines. Also check out our guides for Android and Flutter if you’re targeting multiple platforms.
12. Get Started with Perkox
Ready to monetize your iOS app with an offerwall?
Create your free Perkox publisher account, download the iOS SDK, and start earning within minutes.
Related Guides
- What Is an Offerwall? A Beginner’s Guide
- Complete Offerwall Postback Guide
- Offerwall SDK Security Best Practices
- Perkox Android SDK: Complete Integration Guide
- Perkox Flutter SDK: Complete Integration Guide
This guide covers the Perkox iOS SDK (PerkoxOfferwall) for Swift developers. For the latest API reference and updates, always consult the official documentation.
