Mobile game onboarding is the tutorial, but it's also more than the tutorial. It's the first 5-10 minutes that decide whether a player spends 100 hours with your game or never opens it again. Day 1 retention in mobile gaming averages 25-35%, meaning most players leave after one session. Deep links add a dimension that most games overlook: bringing players in with context (a friend's invite, a reward code, a specific game mode) and tailoring the experience accordingly.
For personalization with deep links, see Personalized Onboarding Flows with Deep Link Data. For incrementality testing, see Incrementality Testing for Mobile Marketing.
Photo by RDNE Stock project on Pexels
Tutorial Design Principles
Show, Don't Tell
The worst gaming tutorials are walls of text explaining controls. The best ones let the player discover mechanics through guided gameplay:
const tutorialStages = [
{
id: 'movement',
mechanic: 'swipe_to_move',
instruction: null, // No text, just a subtle arrow animation
environment: 'safe_corridor', // No enemies
successCondition: 'reach_checkpoint_1',
failSafe: { showHintAfter: 5000, hint: 'Swipe to move your character' },
},
{
id: 'combat_basic',
mechanic: 'tap_to_attack',
instruction: null,
environment: 'weak_enemy', // One easy enemy
successCondition: 'defeat_enemy',
failSafe: { showHintAfter: 8000, hint: 'Tap the enemy to attack' },
},
{
id: 'collect',
mechanic: 'tap_to_collect',
instruction: null,
environment: 'reward_room', // Shiny collectibles
successCondition: 'collect_3_items',
failSafe: { showHintAfter: 5000, hint: 'Tap items to collect them' },
},
];
Each stage introduces one mechanic. The player learns by doing, not by reading. The failsafe hint only appears if the player is stuck.
Difficulty Ramp
The first 10 minutes should follow a carefully designed difficulty curve:
| Minute | Challenge | Purpose |
|---|---|---|
| 0-1 | No challenge (safe exploration) | Learn basic controls |
| 1-2 | Trivially easy enemy | Learn combat/core mechanic |
| 2-3 | Easy enemy + collectible | Learn reward system |
| 3-5 | Moderate challenge | Experience the game loop |
| 5-7 | First real challenge | Feel accomplishment |
| 7-10 | Story hook or competitive element | Create motivation to return |
Skip Option for Experienced Players
Always offer a way to skip the tutorial:
function TutorialScreen({ stage, onSkip }) {
return (
<View>
<GameView stage={stage} />
{stage.id === 'movement' && (
<SkipButton onPress={onSkip}>
Skip Tutorial
</SkipButton>
)}
</View>
);
}
function handleTutorialSkip(player) {
// Grant tutorial completion rewards so they aren't penalized
grantTutorialRewards(player);
// Set all tutorial flags as completed
markAllTutorialComplete(player);
// Navigate to the main game
navigation.navigate('MainGame');
}
Players who skip tutorials are often experienced gamers or returning from a reinstall. Don't punish them.
Deep Links for Gaming Onboarding
Friend Invite Deep Links
When a player sends an invite:
async function createGameInviteLink(player) {
const link = await Tolinku.createLink({
path: `/invite/${player.id}`,
params: {
ref: player.id,
player_name: player.displayName,
player_level: player.level,
reward_type: 'starter_pack',
},
ogTitle: `${player.displayName} challenges you to play [Game]`,
ogDescription: 'Join and get an exclusive starter pack!',
ogImage: player.customInviteImage || defaultInviteImage,
});
return link.url;
}
Handling Game Invite Deep Links
async function handleGameInviteDeepLink(deferred) {
if (deferred === null) return startStandardOnboarding();
const params = deferred.params;
if (params.ref) {
// Player was invited by a friend
return {
tutorial: 'abbreviated', // Shorter tutorial for social players
reward: {
type: params.reward_type || 'starter_pack',
source: 'friend_invite',
},
socialContext: {
friendId: params.ref,
friendName: params.player_name,
friendLevel: parseInt(params.player_level),
},
firstScreen: 'InviteWelcome',
};
}
if (params.mode) {
// Deep link to a specific game mode
return {
tutorial: 'mode_specific',
targetMode: params.mode,
firstScreen: 'ModeIntro',
};
}
return startStandardOnboarding();
}
Reward Deep Links
Marketing campaigns with in-game rewards:
async function handleRewardDeepLink(params) {
if (params.reward_code) {
const reward = await validateRewardCode(params.reward_code);
if (reward && reward.isValid) {
// Grant the reward after tutorial completion
pendingRewards.add({
type: reward.type,
items: reward.items,
source: 'deep_link',
grantAfter: 'tutorial_complete',
});
return {
tutorial: 'standard',
showRewardPreview: true,
rewardPreview: reward,
};
}
}
}
Social Onboarding
Friend-Invited Player Experience
Players who arrive via a friend's invite have higher retention potential. Use the social context:
function InviteWelcomeScreen({ socialContext, reward }) {
return (
<Screen>
<PlayerAvatar playerId={socialContext.friendId} />
<Heading>
{socialContext.friendName} (Level {socialContext.friendLevel}) invited you!
</Heading>
<RewardPreview reward={reward}>
<Text>Complete the tutorial to claim your {reward.name}.</Text>
</RewardPreview>
<Button onPress={startTutorial}>Play Now</Button>
</Screen>
);
}
Friend Connection After Tutorial
After the tutorial, connect the player to their friend:
async function postTutorialSocialSetup(player, socialContext) {
// Auto-add the inviting friend
await addFriend(player.id, socialContext.friendId);
// Show the friend's activity
navigation.navigate('FriendActivity', {
friendId: socialContext.friendId,
message: `You and ${socialContext.friendName} are now friends!`,
});
// Grant invite rewards to both
await grantInviteReward(player.id, 'invited_player');
await grantInviteReward(socialContext.friendId, 'inviter');
}
Monetization in Onboarding
When to Show IAP
Never show in-app purchase prompts during the tutorial. The player hasn't experienced value yet. Timing:
| Approach | Timing | Conversion Rate |
|---|---|---|
| During tutorial | Too early | < 0.5% |
| Immediately after tutorial | Still early | 1-2% |
| After first real challenge (session 1-2) | Good timing | 3-5% |
| After first failure/retry (session 2-3) | Best timing | 5-8% |
| After reaching a natural paywall | Organic timing | 4-7% |
Starter Pack Offer
The best first purchase offer comes after the player understands the game:
function StarterPackOffer({ player, trigger }) {
// Only show after:
// 1. Tutorial is complete
// 2. Player has played at least 2 sessions
// 3. Player has experienced a challenge
if (player.sessionCount < 2) return null;
if (player.hasCompletedTutorial === false) return null;
return (
<Modal>
<Heading>Starter Pack</Heading>
<Text>Everything you need to level up faster.</Text>
<ItemGrid items={starterPackItems} />
<PriceTag original="$9.99" discounted="$1.99" />
<Text style={styles.limited}>One-time offer. 80% off.</Text>
<Button primary onPress={() => purchaseStarterPack()}>
Get Starter Pack
</Button>
<LinkButton onPress={dismiss}>No Thanks</LinkButton>
</Modal>
);
}
Measuring Gaming Onboarding
Key Metrics
| Metric | Definition | Benchmark |
|---|---|---|
| Tutorial completion rate | Finished tutorial / Started game | 70-85% |
| Tutorial skip rate | Skipped / Started | 5-15% |
| D1 retention | Returned on day 1 | 25-40% |
| D7 retention | Returned on day 7 | 10-20% |
| Time to first IAP | Sessions before first purchase | 3-7 sessions |
| Social invite acceptance | Installs from invites / Invites sent | 5-15% |
Tutorial Funnel
async function tutorialFunnel(dateRange) {
const stages = tutorialStages.map(s => s.id);
for (let i = 0; i < stages.length; i++) {
const completed = await countEvent('tutorial_stage_completed', {
stage: stages[i],
dateRange,
});
const previous = i > 0
? await countEvent('tutorial_stage_completed', { stage: stages[i - 1], dateRange })
: await countEvent('tutorial_started', { dateRange });
console.log(stages[i], {
completed,
dropOff: ((previous - completed) / previous * 100).toFixed(1) + '%',
});
}
}
If a specific tutorial stage has high drop-off, the mechanic introduction might be confusing, too difficult, or too slow.
Deep Link Attribution
analytics.track('tutorial_completed', {
source: player.acquisitionSource, // 'organic', 'ad', 'friend_invite'
hasReward: player.pendingRewards.length > 0,
tutorialType: player.tutorialType, // 'standard', 'abbreviated', 'skipped'
timeToComplete: player.tutorialDuration,
friendInvited: player.socialContext ? true : false,
});
Compare retention and monetization across sources. Friend-invited players typically have 30-50% higher D7 retention than organic or ad-acquired players.
For deep linking features, see Tolinku deep linking. For onboarding use cases, see the onboarding documentation.
Get deep linking tips in your inbox
One email per week. No spam.