Skip to main content

iOS Analytics

Attribution tracking (Adjust or AppsFlyer) is configured automatically via the Alogame backend. No local setup required in the SDK.

Adjust or AppsFlyer — never both

A game uses one attribution provider, selected by your operator in the Console (attribution_provider: "adjust" or "appsflyer"). The two are mutually exclusive per game. Everything below that says "Adjust" applies identically to AppsFlyer when it's the active provider — the SDK routes to whichever one is configured, using the same APIs, the same app-delegate callbacks, and the same event names. The sections Privacy Disclosure Requirements and SKAdNetwork (iOS) below apply specifically when AppsFlyer is the selected provider.

Event names, their provider-specific tokens (Adjust) or allow-list membership (AppsFlyer), and the provider app/dev key are managed by your game operator on the backend — you do not configure them in the app. As a developer you only call the logging APIs below with the event name agreed with your operator.

AdjustSigSdk — no manual setup needed​

Adjust SDK v5 bundles AdjustSigSdk automatically. When integrating OegSdkV2 via SPM (source URL), Xcode resolves and embeds it as part of the normal build — no extra steps required.

If you see this crash:

dyld: Library not loaded: @rpath/AdjustSigSdk.framework/AdjustSigSdk

This means OegSdkV2 was added as a pre-built XCFramework (dragged in directly) rather than via SPM. Switch to SPM source integration:

File → Add Package Dependencies → enter your OegSdkV2 gitlab URL

Xcode will then resolve AdjustSigSdk automatically via the Adjust transitive dependency.

note

Do not add adjust_signature_sdk as a separate SPM dependency — it is already managed inside ios_sdk v5 and adding it separately causes version conflicts.

Auto-Tracked Events​

The SDK automatically tracks the following lifecycle events when configured in the backend:

Event NameDescriptionTrigger
sdk_show_loginLogin screen displayedUser opens login UI
sdk_register_successRegistration completedUser successfully registers
sdk_login_successLogin completedUser successfully logs in (manual login only)
sdk_logoutUser logged outUser logs out or session expires
sdk_rechargeIn-app purchase completedIAP verification succeeds
sdk_switch_roleCharacter/server switch, same accountsetGameRole() called while a different role was already active
sdk_logout_game_roleActive role cleared, no logoutlogoutGameRole() called while a role was active

These events are tracked automatically once your operator has set them up on the backend. No game code required.

Set Game Role​

To enable role-specific tracking data (used in sdk_recharge and other events), call setGameRole() after the player enters the game:

import OegSdkV2

OegSdkCore.setGameRole(
serverId: "server_01",
serverName: "Server 1", // optional
roleId: "character_123",
roleName: "DragonSlayer", // optional
level: 50 // optional
)
#import <OegSdkV2/OegSdkV2-Swift.h>

[OegSdkCore setGameRoleWithServerId:@"server_01"
serverName:@"Server 1"
roleId:@"character_123"
roleName:@"DragonSlayer"
level:50];

This information is used to enrich tracking events with player context. Calling setGameRole() again for a different server/role fires sdk_switch_role automatically — no separate call needed for a direct switch.

For games with multiple servers where the player returns to a select screen with no role picked yet, call logoutGameRole() to clear the stale role (fires sdk_logout_game_role). The SDK also clears this data silently (no event) on logout.

OegSdkCore.logoutGameRole {
// navigate to your own switch-server screen
}
[OegSdkCore logoutGameRoleWithCallback:^{
// navigate to your own switch-server screen
}];

See also: Game Role API for detailed documentation and usage examples.

App Tracking Transparency (ATT)​

ATT permission is only needed for IDFA access (accurate install attribution). Basic event tracking works without it — both Adjust and AppsFlyer fall back to probabilistic/non-IDFA attribution if permission is denied.

OegSdkCore requests ATT itself, automatically, 2 seconds after launch on iOS 14+ (ATTrackingManager.requestTrackingAuthorization, deferred so the prompt doesn't fight app-launch rendering). This is the only ATT prompt the SDK shows — your game does not need to (and should not) call requestTrackingAuthorization itself; Apple only shows the system prompt once per install regardless of who calls it, so a second call from game code would not re-prompt, it would just return the already-resolved status immediately. All your game needs to do is ship the required Info.plist key below.

Required — add to your game's Info.plist:

<key>NSUserTrackingUsageDescription</key>
<string>Cho phép theo dõi để cải thiện trải nghiệm trong game.</string>

Without this key, requestTrackingAuthorization throws and iOS treats the app as if tracking is denied.

AppsFlyer's session start waits on this prompt — read this if you're integrating AppsFlyer

This is a subtle point that's easy to get wrong, so it's spelled out explicitly here. AppsFlyer's iOS SDK (pinned 7.x) does not manage ATT timing itself: its registerSessionReadyListener fires independent of ATT status — AppsFlyer's own SDK header states plainly "ATT is not a readiness condition." (An older API, waitForATTUserAuthorizationWithTimeoutInterval:, used to handle this inside AppsFlyer's SDK; it is deprecated in the pinned version, which is why this coordination had to move into OegSdkCore.) Left uncoordinated, AppsFlyer would start — and report the install — before the ATT prompt above has resolved, permanently losing IDFA attribution for that install even if the user later grants permission.

To prevent that, OegSdkCore owns the ordering internally: it calls AppsFlyer's session-start method only from inside the completion handler of the automatic ATT request described above — never before. This is entirely internal to the SDK; the Host_App does not add any code for this. Below iOS 14, where there is no ATT prompt to wait for, AppsFlyer starts immediately.

Uninstall Tracking​

Uninstall tracking is automatic — no game code required. When APNs registers the device, the SDK forwards the raw APNs token (Data) directly to whichever attribution provider is active (Adjust or AppsFlyer). That provider then periodically sends a silent push; if delivery fails, the device is counted as an uninstall.

Requirements:

  • Push Notifications capability enabled in Xcode (see Push Notifications)
  • OEGManager.handleDidRegisterForRemoteNotifications(deviceToken:) wired in AppDelegate — this is the same callback for Adjust and AppsFlyer; there is nothing additional to wire for AppsFlyer
  • Provider app token / dev key configured by your operator
note

Both Adjust and AppsFlyer require the raw APNs Data token, not the FCM string token. The SDK handles this automatically — do not pass a hex string or FCM token to either provider manually.

Deep link reattribution is automatic. The SDK processes all incoming URLs through:

  • OEGManager.handleOpenURL(_:options:) — URL scheme callbacks
  • OEGManager.handleContinueUserActivity(_:) — Universal Links

If these are already wired in your AppDelegate (required by the Installation guide), no additional code is needed — for either provider. Install attribution (first open) works regardless — this is only needed to credit campaigns that bring back existing users. The SDK receives and logs AppsFlyer's conversion/deep-link callback internally; it does not navigate anywhere in your game — routing a link to in-game content is your game's responsibility.

Log an event​

The SDK can log any event — there is no fixed list. An event is just a name plus optional string parameters. Which events exist, and how each name is routed to the active provider — an Adjust event token, or membership in the AppsFlyer allow-list — is defined by your game operator (in Adjust/AppsFlyer + the Alogame backend); the SDK resolves the routing at runtime. You only need the event name agreed with your operator.

An event that isn't configured for the active provider (no Adjust token mapped; not in the AppsFlyer allow-list) is silently skipped (no tracking, no error).

Swift​

// Simple event, no parameters
OEGAnalytics.shared.logEvent("tutorial_complete")

// Event with custom parameters (all values are strings)
OEGAnalytics.shared.logEvent("level_up", parameters: [
"level": "10",
"score": "15000"
])

Objective-C​

// Simple event, no parameters
[[OEGManager sharedManager] logEvent:@"tutorial_complete" withValues:nil];

// Event with custom parameters
[[OEGManager sharedManager] logEvent:@"level_up" withValues:@{
@"level": @"10",
@"score": @"15000"
}];

Log a revenue event​

Events that carry money — Recharge (web_store / WebPay top-ups), first_recharge, or any custom revenue event — must set the real revenue with logRevenue. Sending the amount only as a plain parameter (e.g. charged_value) is not counted by either provider — the dashboard would show 0.

Native IAP is automatic

The native StoreKit IAP flow fires sdk_recharge with revenue already set — no game code needed. Use logRevenue only for events the game pushes itself (web_store / WebPay recharges and custom revenue events).

For Adjust, the revenue is attached to the event's own token, so that event must be set up as a revenue event by your game operator. For AppsFlyer, sdk_recharge additionally and automatically derives AppsFlyer's predefined purchase event from the same call — no separate setup step. orderId deduplicates against double-counting for both providers.

Swift​

OEGAnalytics.shared.logRevenue(
"Recharge", // event name set up as a revenue event by your operator
revenue: 99000, // real amount paid (must be > 0)
currency: "VND", // ISO 4217
orderId: "order_12345", // dedup id
parameters: ["payment_channel": "web_store", "product_id": "vip_pack_1"]
)

Objective-C​

[[OEGManager sharedManager] logEvent:@"Recharge"
withValues:@{ @"payment_channel": @"web_store", @"product_id": @"vip_pack_1" }
revenue:99000
currency:@"VND"
orderId:@"order_12345"];

A recharge is a revenue event — always send it via logRevenue (Swift) / logEvent:withValues:revenue:currency:orderId: (Objective-C), not the plain logEvent, otherwise the active provider records no revenue.

Enable / disable tracking​

setTrackingEnabled(false) stops tracking with whichever provider is active (Adjust's or AppsFlyer's own opt-out mechanism); true resumes it. This does not itself ask the user anything — pair it with your own consent UI if you offer an in-app opt-out separate from ATT.

Swift​

OEGAnalytics.shared.setTrackingEnabled(false)
OEGAnalytics.shared.setTrackingEnabled(true)

Objective-C​

[[OEGAnalytics shared] setTrackingEnabled:NO];
[[OEGAnalytics shared] setTrackingEnabled:YES];

Privacy Disclosure Requirements​

This section applies only when AppsFlyer is the selected attribution provider for your game. If your game uses Adjust, nothing here changes what you already declare.

Adding AppsFlyer to your app is a data-collection change, not just a code change — it changes what you owe Apple in your App Store Privacy ("nutrition label") disclosure, and it changes what your game's own privacy policy needs to say. This is on your game's App Store Connect listing; the SDK cannot fill it in for you.

Identifiers AppsFlyer collects, consistent with what the SDK already sends to Adjust today (no new category of data is introduced — same class of identifiers, different vendor):

  • Advertising / device identifiers used for attribution — IDFA when ATT is granted (see App Tracking Transparency above); AppsFlyer's own SDK-generated install identifier when it is not.
  • Your app's own user id, when you have one — the SDK sets AppsFlyer's customer user id from the same account_id your game already sends to Adjust and to the Alogame backend. No new identifier is introduced; it is the same value routed to one more place.
  • Push token — the raw APNs Data token, forwarded for uninstall measurement (see Uninstall Tracking above), the same token already sent to Adjust today for the same purpose.
  • Standard network/request metadata (IP address, device model, OS version) inherent to any SDK that makes HTTP calls — the same category Adjust already collects.

The SDK never sends email, phone number, or other direct PII to AppsFlyer — nothing beyond what it already sends to your existing providers (Requirement 8.2 of the AppsFlyer integration spec).

Verify against AppsFlyer's current official guidance before submitting

The exact checkbox-level categories Apple's Privacy Nutrition Label form and Google Play's Data Safety form expect are AppsFlyer's to define and can change as Apple/Google's own taxonomies evolve. Do not fill in your app's forms from this page alone — cross-check against AppsFlyer's own current guidance:

Whoever owns your App Store Connect listing (not necessarily the SDK integrator) should complete this before the release that adds AppsFlyer ships — Apple rejects submissions with an inaccurate privacy label, and it is reviewed against runtime behavior, not just declared intent.

SKAdNetwork (iOS)​

If your game's first release with AppsFlyer selected does not ship an SKAdNetworkItems array in Info.plist, SKAdNetwork cannot start collecting conversion data for that release at all — adding the array later requires shipping a new App Store release before SKAdNetwork takes effect. This is a now-or-much-later decision, not something you can turn on from the Console after the fact.

What SKAdNetwork will actually do with each conversion (the 64-value conversion-value schema, timing windows, etc.) is a separate, marketing-owned decision that is intentionally out of scope for this SDK — no SDK code depends on it. The Info.plist array itself is the only piece that must ship now, because it is what App Store Connect physically bundles into the binary at submission time.

Add to your game's Info.plist:

<key>SKAdNetworkItems</key>
<array>
<dict>
<key>SKAdNetworkIdentifier</key>
<string>YOUR_AD_NETWORK_ID.skadnetwork</string>
</dict>
<!-- one <dict> entry per ad network id -->
</array>
Get the current ID list from AppsFlyer directly — do not copy a snapshot

AppsFlyer maintains the current list of ad-network SKAdNetwork IDs to include, and that list grows over time as new ad networks integrate. A copy pasted into this doc (or into a game's repo) would go stale the next time AppsFlyer adds a network. Pull the current list from AppsFlyer's own page at Info.plist-authoring time:

The conversion-value schema itself (what each of the 64 values means) is deferred — do not block shipping the ID array on that decision being made.