Game Role API
The Game Role API tells the SDK which server, character, and level the player is currently on — used to enrich analytics and IAP tracking with player context.
The One Rule
There is exactly one call to make: setGameRole(), any time the player's server, character, or level changes. It's cheap and safe to call often — there's no separate API for "on level up" or "on character switch," it's always the same call, wired to whatever hook in your game already notices player state changing.
Call it from every one of these trigger points:
- Right after login, once you know the player's starting server/character
- After creating a new character
- Whenever the player switches character or server — this fires
af_sdk_switch_roleautomatically, no extra step needed - Whenever the player levels up — easy to forget since it's not a "switch," but skipping it means level silently drifts stale in analytics with no error to flag it
// Call this from wherever your game already tracks these values changing —
// login, character creation, server switch, level up all funnel through here.
fun reportGameRole(player: Player) {
OEGAuthCore.setGameRole(
serverId = player.serverId,
serverName = player.serverName,
roleId = player.characterId,
roleName = player.characterName,
level = player.level
)
}
public void reportGameRole(Player player) {
OEGAuthCore.INSTANCE.setGameRole(
player.getServerId(), player.getServerName(),
player.getCharacterId(), player.getCharacterName(), player.getLevel()
);
}
When the player instead leaves to a character/server-select screen with no role picked yet — a real gap, not a direct switch — call logoutGameRole() first so no stale role backs analytics/purchases in the meantime (see below).
API Reference
setGameRole()
import vn.oeg.sdk.v2.core.auth.OEGAuthCore
OEGAuthCore.setGameRole(
serverId: String,
serverName: String? = null,
roleId: String,
roleName: String? = null,
level: Int = 0
)
import vn.oeg.sdk.v2.core.auth.OEGAuthCore;
// All parameters required from Java — use null for optional String, 0 for default level
OEGAuthCore.INSTANCE.setGameRole(serverId, serverName, roleId, roleName, level);
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
serverId | String | ✅ Yes | Game server identifier (e.g., "server_01", "asia_1") |
serverName | String? | ❌ No | Human-readable server name (e.g., "Asia Server 1") |
roleId | String | ✅ Yes | Character/role unique identifier |
roleName | String? | ❌ No | Character/role display name (e.g., "DragonSlayer") |
level | Int | ❌ No | Character level (default: 0) |
Returns: Nothing (void)
Storage: In-memory only (cleared on logout)
Analytics: If a role was already active and serverId/roleId actually change, fires af_sdk_switch_role (old + new server/role). The very first call after login is treated as an initial pick, not a switch, and does not fire it.
logoutGameRole()
Clears the active character/server context without logging the account out — call when the player returns to a server/character-select screen, before the next setGameRole() call for the newly chosen one. Optional: calling setGameRole() again directly for the new role is enough for a plain switch: use logoutGameRole() when there's a real gap (e.g. player is back at the character-select screen with no role picked yet).
The SDK only clears its own state and fires the analytics event — it does not navigate anywhere. callback fires once that's done; use it to move the game to its own switch-server screen.
import vn.oeg.sdk.v2.core.auth.OEGAuthCore
OEGAuthCore.logoutGameRole {
// Game role cleared — navigate to your own switch-server screen here
navigateToServerSelect()
}
import vn.oeg.sdk.v2.core.auth.OEGAuthCore;
OEGAuthCore.INSTANCE.logoutGameRole(() -> {
// Game role cleared — navigate to your own switch-server screen here
navigateToServerSelect();
});
Returns: Nothing (void) — reports completion via callback
Analytics: Fires af_sdk_logout_game_role (with the role that was just cleared) — but only when a role was actually active. Calling it when no role is set is a safe no-op and does not fire the event.
How It's Used
The SDK uses game role data in the following ways:
1. Analytics Events
Role information is automatically included in analytics events:
af_sdk_recharge(IAP events): Includesrole_id,role_name,server_idaf_logout: Includesserver_idaf_sdk_switch_role: Fired bysetGameRole()when it replaces an already-active role with a different server/role. Includesold_server_id,old_role_id,server_id(new),role_id(new)af_sdk_logout_game_role: Fired bylogoutGameRole()when it clears an active role. Includesserver_id,role_id(the role that was cleared)- Custom events: Available for game-specific tracking
These af_-prefixed names are what AppsFlyer receives. Adjust receives a different, per-game opaque event token configured in the CMS for the same logical event — not these literal strings.
2. IAP Tracking
When a player makes an in-app purchase, the SDK automatically includes role context:
// Game calls IAP
OEGPayment.purchaseAndVerify(productId, gameData) { result ->
// SDK automatically tracks af_sdk_recharge event with:
// - role_id from gameData (primary); falls back to setGameRole() if gameData field is empty
// - role_name from gameData (primary); falls back to setGameRole() if empty
// - server_id from gameData (primary); falls back to setGameRole() if empty
}
OEGPayment.INSTANCE.purchaseAndVerify(productId, gameData, (purchaseResult, result) -> {
// SDK automatically tracks af_sdk_recharge event with role data from gameData (primary)
});
3. Priority and Fallback Behavior
For IAP analytics, the SDK uses GameData as the primary source (it is always present at purchase time). setGameRole() data is used as a fallback when a GameData field is empty.
| Field | Primary | Fallback |
|---|---|---|
role_id | gameData.characterId | gameRole.roleId |
role_name | gameData.characterName | gameRole.roleName |
server_id | gameData.serverId | gameRole.serverId |
For non-IAP events (e.g. af_logout), the SDK uses setGameRole() data directly.
Best practice: Always populate GameData fields when calling purchaseAndVerify() for accurate IAP tracking.
Data Lifecycle
Storage
- Location: In-memory only (not persisted to disk)
- Scope: Current session only
- Access: Internal to SDK (not exposed to game)
Clearing
Call logoutGameRole() explicitly when the player returns to a server/character-select screen (fires af_sdk_logout_game_role). Game role data is also automatically cleared — silently, no event — in these scenarios:
- User logs out:
OEGAuth.logout() // Clears game role automatically
OEGAuth.INSTANCE.logout(); // Clears game role automatically
-
Session expires:
- SDK receives 401 from backend
- Game role cleared during session cleanup
-
Force logout (maintenance):
- SDK force logs out user
- Game role cleared
Persistence
Game role data is NOT persisted across app restarts. You must call setGameRole() again after:
- App restart
- User logs in again
- Session restoration
Reading Game Role (Internal)
The game role data is stored internally and used by the SDK. Games typically don't need to read it back, but if needed:
val gameRole = OEGAuthCore.gameRole
if (gameRole != null) {
val serverId = gameRole.serverId
val serverName = gameRole.serverName
val roleId = gameRole.roleId
val roleName = gameRole.roleName
val level = gameRole.level
}
OEGGameRole gameRole = OEGAuthCore.INSTANCE.getGameRole();
if (gameRole != null) {
String serverId = gameRole.getServerId();
String serverName = gameRole.getServerName();
String roleId = gameRole.getRoleId();
String roleName = gameRole.getRoleName();
int level = gameRole.getLevel();
}
Note: This is read-only. Use setGameRole() to update.
Best Practices
✅ Do
- Wire
setGameRole()into whichever single place your game already tracks server/character/level — don't treat login, character switch, and level-up as separate integrations - Include level every time, not just at login — it's the field most likely to go stale if treated as optional
- Use meaningful IDs (e.g., "server_01", not "1")
- Include optional fields when available (improves analytics)
❌ Don't
- Don't call before login completes
- Don't use sensitive data in role names
- Don't skip re-calling it on level-up because it "isn't a switch" — same call, just a changed value
- Don't rely on persistence across sessions
Troubleshooting
Role data not appearing in analytics
Problem: IAP events show empty role fields
Solutions:
- Verify
setGameRole()is called after login - Check that it's called before IAP purchase
- Ensure parameters are non-empty strings
- Check logs for any SDK errors
Role data cleared unexpectedly
Problem: Role data disappears during session
Cause: User logged out or session expired
Solution: Re-call setGameRole() after re-login
Multiple characters per account
Problem: Game supports multiple characters, which one to track?
Solution: Call setGameRole() for the currently active character. Update when player switches characters.
Backend behavior: every server tracks each character separately — a
second roleId on the same serverId does not replace the first, both
persist. Whichever one setGameRole() was called for most recently is what
Console's player roster marks as that server's current character. If your
game only calls setGameRole() when the player enters a server (not on every
character switch within it), Console's "current" marker goes stale — it
still shows whichever character was picked at login, not the one actually
being played. Analytics are unaffected either way: af_sdk_switch_role /
sdk_switch_role only fires from an explicit setGameRole() call.
Related Documentation
- Analytics Tracking - Auto-tracked events that use role data
- In-App Purchases - IAP flow that includes role tracking
- Authentication - Login flow and session management