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-keyheader - 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:
- Installation Data: Basic app installation info (platform, version, device)
- Progress Data: Game progression (level, XP, achievements, checkpoints)
- State Data: Current game state (currency, energy, lives, inventory)
Status Types
| Status | Description |
|---|---|
| ACTIVE | Currently installed and active |
| UNINSTALLED | User has uninstalled the app |
| BANNED | User 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The 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
| Code | Description |
|---|---|
| 201 | App installed successfully |
| 400 | Invalid installation data |
| 401 | Unauthorized |
| 404 | User or app does not exist |
| 409 | App 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The unique user identifier |
| appId | string | Yes | The 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
| Code | Description |
|---|---|
| 200 | User app updated |
| 400 | Invalid update data |
| 401 | Unauthorized |
| 404 | User 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The unique user identifier |
| appId | string | Yes | The 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
| Code | Description |
|---|---|
| 200 | Progress updated |
| 400 | Invalid progress data |
| 401 | Unauthorized |
| 404 | User 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The unique user identifier |
| appId | string | Yes | The 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
| Code | Description |
|---|---|
| 200 | State updated |
| 400 | Invalid state data |
| 401 | Unauthorized |
| 404 | User 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The unique user identifier |
| appId | string | Yes | The unique application identifier |
Headers
| Header | Type | Required | Description |
|---|---|---|---|
| x-guest-id | string | No | Guest 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
| Code | Description |
|---|---|
| 200 | User app retrieved |
| 404 | User 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The unique user identifier |
| page | number | No | Page number (default: 1) |
| limit | number | No | Items per page (default: 20) |
| status | string | No | Filter 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
| Code | Description |
|---|---|
| 200 | User apps retrieved |
| 401 | Unauthorized |
| 404 | User 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The 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
| Code | Description |
|---|---|
| 200 | Summary retrieved |
| 401 | Unauthorized |
| 404 | User 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| userId | string | Yes | The unique user identifier |
| appId | string | Yes | The 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
| Code | Description |
|---|---|
| 200 | Analytics retrieved |
| 401 | Unauthorized |
| 404 | User 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| appId | string | Yes | The application identifier |
| page | number | No | Page number (default: 1) |
| limit | number | No | Items per page (default: 20) |
| status | string | No | Filter 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
| Code | Description |
|---|---|
| 200 | App users retrieved |
| 401 | Unauthorized |
| 404 | App 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
-
Track Installations Immediately: Create user-app on first launch
await installApp({
userId,
installAppRequest: {
appId,
platform: detectPlatform(),
installedVersion: getAppVersion(),
deviceId: getDeviceId(),
},
}); -
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({...});
} -
Track Device Changes: Update deviceId when user switches devices
await updateUserApp({
userId,
appId,
updateUserAppRequest: {
deviceId: newDeviceId,
platform: newPlatform,
},
});
Progress Management
-
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"],
},
}); -
Checkpoint System: Use checkpoints for save points
checkpoints: {
tutorial: 'completed',
world1: 'completed',
world2: 'level_5',
boss1: 'defeated',
secretArea: 'discovered'
} -
Achievement Tracking: Maintain complete achievement list
const newAchievements = [...current.achievements, "NEW_ACHIEVEMENT_ID"];
await updateAppProgress({
achievements: Array.from(new Set(newAchievements)),
});
State Management
-
Atomic Updates: Update state atomically
// Good: Single update
await updateAppState({
virtualCurrency: newBalance,
energy: newEnergy,
lives: newLives,
});
// Avoid: Multiple separate updates -
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'
}
} -
Validate Before Updating: Check state validity
if (newCurrency < 0) {
throw new Error("Insufficient currency");
}
await updateAppState({
virtualCurrency: newCurrency,
});
Analytics Usage
-
Monitor Engagement: Track engagement scores
const analytics = await getUserAppAnalytics({ userId, appId });
if (analytics.data.engagementScore < 30) {
// User is disengaging - send re-engagement notification
} -
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); -
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:
- Documentation: https://docs.getjar.com
- API Reference: https://api.getjar.com/docs
- Support: support@getjar.com