Skip to main content

User Apps API

The User Apps API enables you to manage the relationship between users and your games. Track installations, monitor progress, maintain game state, and analyze user engagement with comprehensive analytics for each user-app relationship.

Authentication

Most endpoints require authentication using either:

  • API Key: Include x-api-key header
  • Cognito JWT: Include Authorization: Bearer <token> header
  • Developer Auth: Special authentication for developer operations

The getUserAppById endpoint is public and supports an optional x-guest-id header for guest users.

Base URL

https://api.getjar.com/user-apps

Core Concepts

User App Relationship

A user-app represents the relationship between a user and an installed application. It tracks:

  • Installation Details: When installed, platform, version, device
  • Usage Metrics: Sessions, playtime, streaks, engagement
  • Progress Tracking: Level, XP, achievements, completion
  • Game State: Virtual currency, energy, lives, custom data
  • Analytics: Retention, engagement scores, behavioral patterns

Data Layers

The User Apps API manages three distinct data layers:

  1. Installation Data: Basic app installation info (platform, version, device)
  2. Progress Data: Game progression (level, XP, achievements, checkpoints)
  3. State Data: Current game state (currency, energy, lives, inventory)

Status Types

StatusDescription
ACTIVECurrently installed and active
UNINSTALLEDUser has uninstalled the app
BANNEDUser has been banned from the app

Install App

Register a new app installation for a user. Tracks installation details, platform, and device information.

Endpoint

POST /user-apps/:userId/apps

Parameters

ParameterTypeRequiredDescription
userIdstringYesThe unique user identifier

Request Body

{
appId: string; // Required: App to install
platform: string; // Required: WINDOWS, MAC, LINUX, IOS, ANDROID, WEB
installedVersion?: string; // Version being installed
deviceId?: string; // Unique device identifier
}

Response

{
userAppId: string;
userId: string;
appId: string;
platform: string;
installedVersion: string;
installedAt: string;
status: string; // ACTIVE
totalSessions: number; // 0
totalPlayTime: number; // 0
streak: number; // 0
createdAt: string;
}

Example

import { UserAppsApi } from "@getjar-iap/sdk";

const userAppsApi = new UserAppsApi(configuration);

const installation = await userAppsApi.installApp({
userId: "user_123",
installAppRequest: {
appId: "app_123",
platform: "IOS",
installedVersion: "1.2.3",
deviceId: "device-iphone-67890",
},
});

console.log("Installed:", installation.data.userAppId);
console.log("Platform:", installation.data.platform);
console.log("Status:", installation.data.status);

Response Codes

CodeDescription
201App installed successfully
400Invalid installation data
401Unauthorized
404User or app does not exist
409App already installed for this user

Update User App

Update general user app information such as version, platform, or device ID.

Endpoint

PUT /user-apps/:userId/apps/:appId

Parameters

ParameterTypeRequiredDescription
userIdstringYesThe unique user identifier
appIdstringYesThe unique application identifier

Request Body

{
currentVersion?: string; // Updated app version
platform?: string; // Updated platform
deviceId?: string; // Updated device identifier
rating?: number; // User rating (1-5)
hasRated?: boolean; // Whether user has rated
reviewId?: string; // Associated review ID
}

Example

const updated = await userAppsApi.updateUserApp({
userId: "user_123",
appId: "app_123",
updateUserAppRequest: {
currentVersion: "1.3.0",
rating: 4.5,
hasRated: true,
},
});

console.log("Updated version:", updated.data.currentVersion);
console.log("Rating:", updated.data.rating);

Response Codes

CodeDescription
200User app updated
400Invalid update data
401Unauthorized
404User app does not exist

Update App Progress

Update user progress tracking including level, experience, achievements, and completion percentage.

Endpoint

PUT /user-apps/:userId/apps/:appId/progress

Parameters

ParameterTypeRequiredDescription
userIdstringYesThe unique user identifier
appIdstringYesThe unique application identifier

Request Body

{
level?: number; // Current level
experience?: number; // Total experience points
achievements?: string[]; // Array of achievement IDs
completionPercentage?: number; // Game completion (0-100)
checkpoints?: object; // Custom checkpoint data
}

Response

{
userAppId: string;
progress: {
level: number;
experience: number;
achievements: string[];
completionPercentage: number;
checkpoints: object;
};
updatedAt: string;
}

Example

const progress = await userAppsApi.updateAppProgress({
userId: "user_123",
appId: "app_123",
updateAppProgressRequest: {
level: 42,
experience: 125000,
achievements: ["FIRST_WIN", "LEVEL_10", "SPEED_RUNNER"],
completionPercentage: 67.5,
checkpoints: {
world1: "completed",
world2: "in_progress",
world3: "locked",
bossDefeated: true,
},
},
});

console.log("Level:", progress.data.progress.level);
console.log("XP:", progress.data.progress.experience);
console.log("Completion:", progress.data.progress.completionPercentage + "%");
console.log("Achievements:", progress.data.progress.achievements.length);

Response Codes

CodeDescription
200Progress updated
400Invalid progress data
401Unauthorized
404User app does not exist

Update App State

Update user state information including virtual currency, energy, lives, and custom game data.

Endpoint

PUT /user-apps/:userId/apps/:appId/state

Parameters

ParameterTypeRequiredDescription
userIdstringYesThe unique user identifier
appIdstringYesThe unique application identifier

Request Body

{
virtualCurrency?: number; // Virtual currency balance
energy?: number; // Energy/stamina
lives?: number; // Lives/hearts
customData?: object; // Custom game-specific data
}

Response

{
userAppId: string;
userState: {
virtualCurrency: number;
energy: number;
lives: number;
customData: object;
}
updatedAt: string;
}

Example

const state = await userAppsApi.updateAppState({
userId: "user_123",
appId: "app_123",
updateAppStateDto: {
virtualCurrency: 5000,
energy: 100,
lives: 5,
customData: {
inventory: ["sword", "shield", "health_potion"],
activePowerups: ["speed_boost", "double_xp"],
questsCompleted: 15,
dailyRewardsClaimed: true,
lastSavePoint: "checkpoint_42",
},
},
});

console.log("Gold:", state.data.userState.virtualCurrency);
console.log("Energy:", state.data.userState.energy);
console.log("Lives:", state.data.userState.lives);
console.log("Inventory:", state.data.userState.customData.inventory);

Response Codes

CodeDescription
200State updated
400Invalid state data
401Unauthorized
404User app does not exist

Get User App by ID

Retrieve detailed information about a specific user-app installation including all progress, state, and usage metrics. This endpoint is public.

Endpoint

GET /user-apps/:userId/apps/:appId

Parameters

ParameterTypeRequiredDescription
userIdstringYesThe unique user identifier
appIdstringYesThe unique application identifier

Headers

HeaderTypeRequiredDescription
x-guest-idstringNoGuest identifier for unauthenticated users

Response

{
userAppId: string;
userId: string;
appId: string;
installedAt: string;
installedVersion: string;
currentVersion: string;
platform: string;
deviceId: string;
firstOpenedAt: string | null;
lastOpenedAt: string | null;
totalSessions: number;
totalPlayTime: number; // Minutes
averageSessionLength: number; // Minutes
daysActive: number;
progress: {
level: number;
experience: number;
achievements: string[];
completionPercentage: number;
checkpoints: object;
} | null;
userState: {
virtualCurrency: number;
energy: number;
lives: number;
customData: object;
} | null;
status: string; // ACTIVE, UNINSTALLED, BANNED
uninstalledAt: string | null;
bannedAt: string | null;
banReason: string | null;
hasRated: boolean;
rating: number | null;
reviewId: string | null;
streak: number;
bestStreak: number;
lastDailyChallengeAt: string | null;
metadata: object;
createdAt: string;
updatedAt: string;
}

Example

const userApp = await userAppsApi.getUserAppById({
userId: "user_123",
appId: "app_123",
});

console.log("📱 User App Details:");
console.log("Platform:", userApp.data.platform);
console.log("Version:", userApp.data.currentVersion);
console.log("Total Sessions:", userApp.data.totalSessions);
console.log("Playtime:", `${userApp.data.totalPlayTime} minutes`);
console.log("Level:", userApp.data.progress?.level);
console.log("Completion:", userApp.data.progress?.completionPercentage + "%");
console.log("Gold:", userApp.data.userState?.virtualCurrency);
console.log("Streak:", userApp.data.streak, "days");

Response Codes

CodeDescription
200User app retrieved
404User app does not exist

Get User Apps

Retrieve a paginated list of all apps installed by a user with optional status filters.

Endpoint

GET /user-apps/:userId/apps

Parameters

ParameterTypeRequiredDescription
userIdstringYesThe unique user identifier
pagenumberNoPage number (default: 1)
limitnumberNoItems per page (default: 20)
statusstringNoFilter by status

Response

{
items: Array<{
userAppId: string;
userId: string;
appId: string;
platform: string;
installedAt: string;
lastOpenedAt: string;
status: string;
totalSessions: number;
totalPlayTime: number;
streak: number;
progress: object;
userState: object;
}>;
pagination: {
total: number;
page: number;
limit: number;
totalPages: number;
hasNextPage: boolean;
hasPreviousPage: boolean;
}
}

Example

// Get all user apps
const apps = await userAppsApi.getUserApps({
userId: "user_123",
page: 1,
limit: 20,
});

console.log("Total apps:", apps.data.pagination.total);
console.log("\n📱 Installed Apps:");
apps.data.items.forEach((app, index) => {
console.log(`${index + 1}. ${app.appId}`);
console.log(` Platform: ${app.platform}`);
console.log(` Sessions: ${app.totalSessions}`);
console.log(` Playtime: ${app.totalPlayTime} minutes`);
console.log(` Status: ${app.status}`);
});

// Get only active apps
const activeApps = await userAppsApi.getUserApps({
userId: "user_123",
status: "ACTIVE",
page: 1,
limit: 50,
});

console.log("Active apps:", activeApps.data.pagination.total);

Response Codes

CodeDescription
200User apps retrieved
401Unauthorized
404User does not exist

Get User Apps Summary

Retrieve aggregate statistics across all user apps including totals, most played apps, and engagement metrics.

Endpoint

GET /user-apps/:userId/apps-summary

Parameters

ParameterTypeRequiredDescription
userIdstringYesThe unique user identifier

Response

{
totalApps: number;
activeApps: number;
uninstalledApps: number;
bannedApps: number;
totalPlayTime: number; // Minutes across all apps
totalSessions: number;
averageSessionLength: number; // Minutes
totalAchievements: number;
mostPlayedApps: Array<{
appId: string;
appName: string;
totalPlayTime: number;
totalSessions: number;
lastOpenedAt: string;
}>;
platformDistribution: Array<{
platform: string;
appCount: number;
}>;
recentlyPlayed: Array<{
appId: string;
appName: string;
lastOpenedAt: string;
}>;
}

Example

const summary = await userAppsApi.getUserAppsSummary({
userId: "user_123",
});

console.log("📊 User Gaming Summary:");
console.log("Total Apps:", summary.data.totalApps);
console.log("Active Apps:", summary.data.activeApps);
console.log(
"Total Playtime:",
`${summary.data.totalPlayTime} minutes (${(
summary.data.totalPlayTime / 60
).toFixed(1)} hours)`
);
console.log("Total Sessions:", summary.data.totalSessions);
console.log("Average Session:", `${summary.data.averageSessionLength} minutes`);
console.log("Total Achievements:", summary.data.totalAchievements);

console.log("\n🏆 Most Played Apps:");
summary.data.mostPlayedApps.slice(0, 5).forEach((app, index) => {
console.log(
`${index + 1}. ${app.appName}: ${app.totalPlayTime} min (${
app.totalSessions
} sessions)`
);
});

console.log("\n📱 Platform Distribution:");
summary.data.platformDistribution.forEach((platform) => {
console.log(`${platform.platform}: ${platform.appCount} apps`);
});

console.log("\n⏰ Recently Played:");
summary.data.recentlyPlayed.slice(0, 3).forEach((app) => {
console.log(
`${app.appName} - ${new Date(app.lastOpenedAt).toLocaleString()}`
);
});

Response Codes

CodeDescription
200Summary retrieved
401Unauthorized
404User does not exist

Get User App Analytics

Retrieve comprehensive analytics for a specific user-app relationship including engagement, progress, and behavioral metrics.

Endpoint

GET /user-apps/:userId/apps/:appId/analytics

Parameters

ParameterTypeRequiredDescription
userIdstringYesThe unique user identifier
appIdstringYesThe unique application identifier

Response

{
userId: string;
appId: string;
totalSessions: number;
totalPlayTime: number; // Minutes
averageSessionLength: number; // Minutes
daysActive: number;
daysSinceInstall: number;
daysSinceLastPlayed: number;
streak: number;
bestStreak: number;
retentionRate: number; // Percentage
engagementScore: number; // 0-100
progress: {
level: number;
experience: number;
achievements: string[];
completionPercentage: number;
};
state: {
virtualCurrency: number;
energy: number;
lives: number;
};
rating: number | null;
installedAt: string;
lastOpenedAt: string;
sessionsOverTime: Array<{
date: string;
sessionCount: number;
playTime: number;
}>;
}

Example

const analytics = await userAppsApi.getUserAppAnalytics({
userId: "user_123",
appId: "app_123",
});

console.log("📈 User App Analytics:");
console.log("Engagement Score:", analytics.data.engagementScore + "/100");
console.log("Total Sessions:", analytics.data.totalSessions);
console.log("Total Playtime:", `${analytics.data.totalPlayTime} minutes`);
console.log(
"Average Session:",
`${analytics.data.averageSessionLength} minutes`
);
console.log("Days Active:", analytics.data.daysActive);
console.log("Days Since Install:", analytics.data.daysSinceInstall);
console.log("Current Streak:", analytics.data.streak, "days");
console.log("Best Streak:", analytics.data.bestStreak, "days");
console.log("Retention Rate:", analytics.data.retentionRate + "%");

console.log("\n🎮 Progress:");
console.log("Level:", analytics.data.progress.level);
console.log("XP:", analytics.data.progress.experience);
console.log("Completion:", analytics.data.progress.completionPercentage + "%");
console.log("Achievements:", analytics.data.progress.achievements.length);

console.log("\n💎 Current State:");
console.log("Gold:", analytics.data.state.virtualCurrency);
console.log("Energy:", analytics.data.state.energy);
console.log("Lives:", analytics.data.state.lives);

Response Codes

CodeDescription
200Analytics retrieved
401Unauthorized
404User app does not exist

Get App Users

Retrieve a paginated list of all users who have installed a specific app with engagement metrics.

Endpoint

GET /user-apps/apps/:appId/users

Parameters

ParameterTypeRequiredDescription
appIdstringYesThe application identifier
pagenumberNoPage number (default: 1)
limitnumberNoItems per page (default: 20)
statusstringNoFilter by status

Response

{
items: Array<{
userAppId: string;
userId: string;
platform: string;
installedAt: string;
lastOpenedAt: string;
status: string;
totalSessions: number;
totalPlayTime: number;
streak: number;
rating: number | null;
}>;
pagination: {
total: number;
page: number;
limit: number;
totalPages: number;
hasNextPage: boolean;
hasPreviousPage: boolean;
}
}

Example

const appUsers = await userAppsApi.getAppUsers({
appId: "app_123",
page: 1,
limit: 100,
});

console.log("📊 App User Statistics:");
console.log("Total Users:", appUsers.data.pagination.total);

// Calculate engagement metrics
const totalPlaytime = appUsers.data.items.reduce(
(sum, user) => sum + user.totalPlayTime,
0
);
const avgPlaytime = totalPlaytime / appUsers.data.items.length;

console.log("Average Playtime:", `${avgPlaytime.toFixed(0)} minutes`);

// Platform distribution
const platforms = appUsers.data.items.reduce((acc, user) => {
acc[user.platform] = (acc[user.platform] || 0) + 1;
return acc;
}, {} as Record<string, number>);

console.log("\n📱 Platform Distribution:");
Object.entries(platforms).forEach(([platform, count]) => {
console.log(`${platform}: ${count} users`);
});

// Top users by playtime
const topUsers = appUsers.data.items
.sort((a, b) => b.totalPlayTime - a.totalPlayTime)
.slice(0, 10);

console.log("\n🏆 Top 10 Users by Playtime:");
topUsers.forEach((user, index) => {
console.log(
`${index + 1}. ${user.userId}: ${user.totalPlayTime} min (${
user.totalSessions
} sessions)`
);
});

Response Codes

CodeDescription
200App users retrieved
401Unauthorized
404App does not exist

Complete Example

Here's a complete workflow for managing user-app relationships:

import { Configuration, UserAppsApi } from "@getjar-iap/sdk";

const configuration = new Configuration({
basePath: "https://api.getjar.com",
apiKey: "your-api-key",
});

const userAppsApi = new UserAppsApi(configuration);

async function completeUserAppWorkflow() {
const userId = "user_123";
const appId = "app_123";

console.log("🎮 User App Workflow\n");

// 1. Install app for user
const installation = await userAppsApi.installApp({
userId,
installAppRequest: {
appId,
platform: "IOS",
installedVersion: "1.2.3",
deviceId: "device-iphone-67890",
},
});

console.log("✓ App installed");
console.log("User App ID:", installation.data.userAppId);

// 2. User plays the game - update progress
const progress = await userAppsApi.updateAppProgress({
userId,
appId,
updateAppProgressRequest: {
level: 5,
experience: 2500,
achievements: ["TUTORIAL_COMPLETE", "FIRST_WIN"],
completionPercentage: 10.0,
checkpoints: {
tutorial: "completed",
world1Level1: "completed",
world1Level2: "in_progress",
},
},
});

console.log("\n✓ Progress updated");
console.log("Level:", progress.data.progress.level);
console.log("XP:", progress.data.progress.experience);

// 3. Update game state
const state = await userAppsApi.updateAppState({
userId,
appId,
updateAppStateDto: {
virtualCurrency: 500,
energy: 80,
lives: 3,
customData: {
inventory: ["sword", "shield"],
currentQuest: "defeat_the_boss",
tutorialCompleted: true,
},
},
});

console.log("\n✓ State updated");
console.log("Gold:", state.data.userState.virtualCurrency);
console.log("Energy:", state.data.userState.energy);

// 4. Get detailed user app info
const userApp = await userAppsApi.getUserAppById({
userId,
appId,
});

console.log("\n📱 Current Status:");
console.log("Sessions:", userApp.data.totalSessions);
console.log("Playtime:", `${userApp.data.totalPlayTime} minutes`);
console.log("Streak:", userApp.data.streak, "days");
console.log("Status:", userApp.data.status);

// 5. Get analytics
const analytics = await userAppsApi.getUserAppAnalytics({
userId,
appId,
});

console.log("\n📊 Analytics:");
console.log("Engagement Score:", analytics.data.engagementScore + "/100");
console.log("Retention Rate:", analytics.data.retentionRate + "%");
console.log("Days Active:", analytics.data.daysActive);

// 6. Get user summary across all apps
const summary = await userAppsApi.getUserAppsSummary({
userId,
});

console.log("\n🎮 User Gaming Profile:");
console.log("Total Apps:", summary.data.totalApps);
console.log("Total Playtime:", `${summary.data.totalPlayTime} minutes`);
console.log("Total Achievements:", summary.data.totalAchievements);

return { installation, progress, state, analytics, summary };
}

// Run the workflow
completeUserAppWorkflow()
.then(() => console.log("\n✅ Workflow complete!"))
.catch((error) => console.error("❌ Error:", error));

Gaming Session Tracker

Track a complete gaming session with all updates:

async function trackGamingSession(
userId: string,
appId: string,
sessionData: {
duration: number;
levelsGained: number;
xpGained: number;
currencyEarned: number;
currencySpent: number;
achievementsUnlocked: string[];
}
) {
// Get current state
const current = await userAppsApi.getUserAppById({ userId, appId });

const currentLevel = current.data.progress?.level || 1;
const currentXP = current.data.progress?.experience || 0;
const currentCurrency = current.data.userState?.virtualCurrency || 0;
const currentAchievements = current.data.progress?.achievements || [];

// Calculate new values
const newLevel = currentLevel + sessionData.levelsGained;
const newXP = currentXP + sessionData.xpGained;
const newCurrency =
currentCurrency + sessionData.currencyEarned - sessionData.currencySpent;
const newAchievements = [
...new Set([...currentAchievements, ...sessionData.achievementsUnlocked]),
];

// Update progress
await userAppsApi.updateAppProgress({
userId,
appId,
updateAppProgressRequest: {
level: newLevel,
experience: newXP,
achievements: newAchievements,
},
});

// Update state
await userAppsApi.updateAppState({
userId,
appId,
updateAppStateDto: {
virtualCurrency: newCurrency,
},
});

console.log("📊 Session Complete:");
console.log(
`Level: ${currentLevel}${newLevel} (+${sessionData.levelsGained})`
);
console.log(`XP: ${currentXP}${newXP} (+${sessionData.xpGained})`);
console.log(
`Gold: ${currentCurrency}${newCurrency} (+${
sessionData.currencyEarned - sessionData.currencySpent
})`
);
console.log(`New Achievements: ${sessionData.achievementsUnlocked.length}`);

return { newLevel, newXP, newCurrency, newAchievements };
}

// Example usage
await trackGamingSession("user_123", "app_123", {
duration: 45,
levelsGained: 3,
xpGained: 1500,
currencyEarned: 300,
currencySpent: 150,
achievementsUnlocked: ["LEVEL_10", "SPEED_RUNNER"],
});

User Engagement Dashboard

Build a comprehensive engagement dashboard:

async function buildEngagementDashboard(userId: string) {
// Get all user apps
const apps = await userAppsApi.getUserApps({
userId,
page: 1,
limit: 100,
});

// Get summary
const summary = await userAppsApi.getUserAppsSummary({ userId });

// Calculate engagement metrics
const totalHours = summary.data.totalPlayTime / 60;
const avgSessionMinutes = summary.data.averageSessionLength;

// Analyze activity patterns
const activeApps = apps.data.items.filter((app) => app.status === "ACTIVE");
const recentlyActive = apps.data.items.filter((app) => {
const daysSinceActive =
(Date.now() - new Date(app.lastOpenedAt).getTime()) /
(1000 * 60 * 60 * 24);
return daysSinceActive <= 7;
});

// Get detailed analytics for top apps
const topAppsAnalytics = await Promise.all(
summary.data.mostPlayedApps.slice(0, 3).map((app) =>
userAppsApi.getUserAppAnalytics({
userId,
appId: app.appId,
})
)
);

const dashboard = {
overview: {
totalApps: summary.data.totalApps,
activeApps: activeApps.length,
recentlyActive: recentlyActive.length,
totalHours: totalHours.toFixed(1),
totalSessions: summary.data.totalSessions,
avgSessionMinutes: avgSessionMinutes.toFixed(0),
totalAchievements: summary.data.totalAchievements,
},
topApps: summary.data.mostPlayedApps.slice(0, 5).map((app) => ({
name: app.appName,
playtime: `${app.totalPlayTime} min`,
sessions: app.totalSessions,
})),
engagement: topAppsAnalytics.map((analytics) => ({
appId: analytics.data.appId,
engagementScore: analytics.data.engagementScore,
streak: analytics.data.streak,
retentionRate: analytics.data.retentionRate,
})),
platforms: summary.data.platformDistribution,
};

console.log("📊 User Engagement Dashboard\n");
console.log("Overview:");
console.log(JSON.stringify(dashboard.overview, null, 2));
console.log("\n🏆 Top Apps:");
console.log(JSON.stringify(dashboard.topApps, null, 2));
console.log("\n💪 Engagement:");
console.log(JSON.stringify(dashboard.engagement, null, 2));
console.log("\n📱 Platforms:");
console.log(JSON.stringify(dashboard.platforms, null, 2));

return dashboard;
}

Best Practices

Installation Tracking

  1. Track Installations Immediately: Create user-app on first launch

    await installApp({
    userId,
    installAppRequest: {
    appId,
    platform: detectPlatform(),
    installedVersion: getAppVersion(),
    deviceId: getDeviceId(),
    },
    });
  2. Handle Reinstalls: Check if already installed before creating

    try {
    const existing = await getUserAppById({ userId, appId });
    if (existing.data.status === 'UNINSTALLED') {
    // Update status instead of creating new
    await updateUserApp({ userId, appId, status: 'ACTIVE' });
    }
    } catch (error) {
    // Doesn't exist, install normally
    await installApp({...});
    }
  3. Track Device Changes: Update deviceId when user switches devices

    await updateUserApp({
    userId,
    appId,
    updateUserAppRequest: {
    deviceId: newDeviceId,
    platform: newPlatform,
    },
    });

Progress Management

  1. Incremental Updates: Update progress as it happens

    // User completes level
    await updateAppProgress({
    userId,
    appId,
    updateAppProgressRequest: {
    level: currentLevel + 1,
    experience: currentXP + levelXP,
    achievements: [...achievements, "LEVEL_COMPLETE"],
    },
    });
  2. Checkpoint System: Use checkpoints for save points

    checkpoints: {
    tutorial: 'completed',
    world1: 'completed',
    world2: 'level_5',
    boss1: 'defeated',
    secretArea: 'discovered'
    }
  3. Achievement Tracking: Maintain complete achievement list

    const newAchievements = [...current.achievements, "NEW_ACHIEVEMENT_ID"];
    await updateAppProgress({
    achievements: Array.from(new Set(newAchievements)),
    });

State Management

  1. Atomic Updates: Update state atomically

    // Good: Single update
    await updateAppState({
    virtualCurrency: newBalance,
    energy: newEnergy,
    lives: newLives,
    });

    // Avoid: Multiple separate updates
  2. Custom Data Structure: Organize custom data logically

    customData: {
    inventory: {
    weapons: ['sword', 'bow'],
    armor: ['helmet', 'chestplate'],
    consumables: ['potion', 'scroll']
    },
    quests: {
    active: ['main_quest_1', 'side_quest_3'],
    completed: ['tutorial', 'intro_quest']
    },
    settings: {
    soundEnabled: true,
    difficulty: 'normal'
    }
    }
  3. Validate Before Updating: Check state validity

    if (newCurrency < 0) {
    throw new Error("Insufficient currency");
    }

    await updateAppState({
    virtualCurrency: newCurrency,
    });

Analytics Usage

  1. Monitor Engagement: Track engagement scores

    const analytics = await getUserAppAnalytics({ userId, appId });

    if (analytics.data.engagementScore < 30) {
    // User is disengaging - send re-engagement notification
    }
  2. Retention Tracking: Monitor retention rates

    const analytics = await getUserAppAnalytics({ userId, appId });

    console.log("Retention:", analytics.data.retentionRate);
    console.log("Days since last played:", analytics.data.daysSinceLastPlayed);
  3. Streak Management: Reward consistent play

    const analytics = await getUserAppAnalytics({ userId, appId });

    if (analytics.data.streak >= 7) {
    // Award weekly streak bonus
    }

    if (analytics.data.streak > analytics.data.bestStreak) {
    // New personal record!
    }

Common Patterns

Daily Login Reward

async function processDailyLogin(userId: string, appId: string) {
const analytics = await userAppsApi.getUserAppAnalytics({ userId, appId });
const userApp = await userAppsApi.getUserAppById({ userId, appId });

const lastLogin = new Date(analytics.data.lastOpenedAt);
const now = new Date();
const hoursSinceLogin =
(now.getTime() - lastLogin.getTime()) / (1000 * 60 * 60);

// Check if eligible for daily reward (24 hours)
if (hoursSinceLogin >= 24) {
const currentCurrency = userApp.data.userState?.virtualCurrency || 0;
const streakBonus = Math.min(analytics.data.streak * 10, 100);
const dailyReward = 50 + streakBonus;

await userAppsApi.updateAppState({
userId,
appId,
updateAppStateDto: {
virtualCurrency: currentCurrency + dailyReward,
customData: {
...userApp.data.userState?.customData,
lastDailyReward: now.toISOString(),
dailyRewardStreak: analytics.data.streak,
},
},
});

return {
claimed: true,
reward: dailyReward,
streak: analytics.data.streak,
message: `Claimed ${dailyReward} gold! (Streak: ${analytics.data.streak} days)`,
};
}

return {
claimed: false,
nextAvailable: new Date(lastLogin.getTime() + 24 * 60 * 60 * 1000),
};
}

Save Game System

async function saveGame(
userId: string,
appId: string,
saveData: {
progress: any;
state: any;
checkpoint: string;
}
) {
// Save progress
await userAppsApi.updateAppProgress({
userId,
appId,
updateAppProgressRequest: {
...saveData.progress,
checkpoints: {
...saveData.progress.checkpoints,
lastSave: saveData.checkpoint,
savedAt: new Date().toISOString(),
},
},
});

// Save state
await userAppsApi.updateAppState({
userId,
appId,
updateAppStateDto: {
...saveData.state,
customData: {
...saveData.state.customData,
lastCheckpoint: saveData.checkpoint,
autoSave: true,
},
},
});

console.log("✓ Game saved at checkpoint:", saveData.checkpoint);
}

async function loadGame(userId: string, appId: string) {
const userApp = await userAppsApi.getUserAppById({ userId, appId });

return {
progress: userApp.data.progress,
state: userApp.data.userState,
checkpoint: userApp.data.progress?.checkpoints?.lastSave,
};
}

User Segmentation

async function segmentUsers(appId: string) {
const users = await userAppsApi.getAppUsers({
appId,
page: 1,
limit: 1000,
});

const segments = {
whales: [], // High engagement, high playtime
engaged: [], // Regular players
atrisk: [], // Declining engagement
churned: [], // Inactive
};

for (const user of users.data.items) {
const analytics = await userAppsApi.getUserAppAnalytics({
userId: user.userId,
appId,
});

if (
analytics.data.totalPlayTime > 10000 &&
analytics.data.engagementScore > 70
) {
segments.whales.push(user.userId);
} else if (analytics.data.engagementScore > 50) {
segments.engaged.push(user.userId);
} else if (analytics.data.daysSinceLastPlayed <= 7) {
segments.atrisk.push(user.userId);
} else {
segments.churned.push(user.userId);
}
}

return segments;
}

Error Handling

async function safeUserAppOperation() {
try {
const userApp = await userAppsApi.installApp({
userId: "user_123",
installAppRequest: {
/* ... */
},
});

return {
success: true,
data: userApp.data,
};
} catch (error) {
if (error.response) {
switch (error.response.status) {
case 400:
console.error("Invalid installation data");
break;
case 401:
console.error("Authentication required");
break;
case 404:
console.error("User or app not found");
break;
case 409:
console.error("App already installed");
// Handle reinstall scenario
break;
default:
console.error("Unexpected error:", error.response.status);
}
}

return {
success: false,
error: error.message,
};
}
}

Support

For additional help or questions: