Every user who installs your app got there from somewhere: an ad, a referral link, a social media post, a QR code, or an organic search. That "somewhere" tells you what the user cares about. Deep links carry this context through the install, letting you build an onboarding experience that matches the user's intent instead of showing them a generic welcome screen.
For deferred deep linking mechanics, see Deferred Deep Linking for Personalized Onboarding. For the complete onboarding guide, see User Onboarding with Deep Links.
The Context You Can Capture
Deep links carry data through the install process. Here's what each source tells you:
| Source | Deep Link Data | What It Tells You |
|---|---|---|
| Ad campaign | Product category, promo code, ad creative | What product/feature attracted the user |
| Referral link | Referrer name/ID, reward details | Who sent them, social proof context |
| Content link | Article topic, feature page | What they were reading about |
| QR code | Physical location, event, product | Where they scanned (in-store, billboard, packaging) |
| Partner link | Partner name, integration context | B2B or partnership origin |
| Email link | Subscriber segment, email campaign | Existing relationship context |
Implementation Pattern
Step 1: Capture Context on First Launch
// On first app launch
async function initializeOnboarding() {
const deferredLink = await Tolinku.checkDeferredLink();
const context = {
source: 'organic', // default
campaign: null,
referrer: null,
product: null,
promoCode: null,
};
if (deferredLink) {
const params = deferredLink.params;
context.source = params.utm_source || 'deep_link';
context.campaign = params.utm_campaign;
context.referrer = params.ref;
context.product = params.product;
context.promoCode = params.promo;
}
onboardingStore.setContext(context);
return context;
}
Step 2: Choose the Onboarding Flow
function getOnboardingFlow(context) {
if (context.referrer) {
return 'referral'; // Acknowledge the referrer, show reward
}
if (context.product) {
return 'product_focused'; // Skip category selection, show the product
}
if (context.campaign) {
return 'campaign'; // Show the campaign-specific landing
}
return 'default'; // Standard onboarding
}
Step 3: Customize Each Step
function OnboardingScreen({ context }) {
const flow = getOnboardingFlow(context);
switch (flow) {
case 'referral':
return (
<ReferralWelcome
referrerName={context.referrerName}
reward="$10 off your first order"
/>
);
case 'product_focused':
return (
<ProductOnboarding
product={context.product}
promoCode={context.promoCode}
/>
);
case 'campaign':
return (
<CampaignLanding
campaign={context.campaign}
headline={getCampaignHeadline(context.campaign)}
/>
);
default:
return <StandardOnboarding />;
}
}
Personalization Strategies
Skip Irrelevant Steps
If the deep link tells you the user's interest, skip steps that ask about it:
| Deep Link Context | Steps to Skip |
|---|---|
product=fitness |
"What are you interested in?" category picker |
ref=friend123 |
"How did you hear about us?" survey |
partner=EMPLOYER |
Account type selection (partner defines it) |
promo=PREMIUM_TRIAL |
Pricing page (they already know the offer) |
Every skipped step reduces drop-off. If you know the answer, don't ask the question.
Show Relevant Content First
Reorder the onboarding to show the most relevant content based on context:
User from a fitness ad:
- "Welcome! Let's set up your fitness profile." (not generic welcome)
- Fitness preference selection
- Account creation
User from a referral:
- "Sarah invited you! Here's your $10 reward."
- Quick account creation
- Browse products (with reward highlighted)
User from a QR code at a retail store:
- "Welcome! Scan products to see reviews and prices."
- Location permissions (to enhance in-store experience)
- Account creation (optional, can browse first)
Pre-Fill Known Data
If the deep link includes data the user already provided (email from a newsletter signup, name from a partner integration):
function AccountCreationScreen({ context }) {
return (
<Form>
<Input
label="Email"
defaultValue={context.email || ''}
disabled={!!context.email} // Pre-filled and locked
/>
<Input label="Password" />
<Input label="Name" />
</Form>
);
}
Customize Messaging
Tailor the copy to match how the user arrived:
| Source | Welcome Message |
|---|---|
| Referral | "Sarah thinks you'll love [App]. Here's $10 to get started." |
| Fitness ad | "Ready to crush your fitness goals? Let's go." |
| Back-to-school campaign | "Everything you need for the new semester." |
| Organic (no context) | "Welcome to [App]. Let's get you set up." |
Small copy changes make the experience feel intentional, not generic.
Deferred Deep Linking Requirements
Personalized onboarding depends entirely on deferred deep linking working correctly. The user clicks a link, installs the app, and the context must survive the install process.
How Deferred Deep Links Work
- User clicks
https://go.yourapp.com/signup?product=fitness&promo=FIT20 - User is redirected to the App Store / Play Store
- User installs the app
- On first launch, the SDK contacts the server
- The server matches the device (fingerprinting) to the original click
- The deep link data (
product=fitness,promo=FIT20) is returned to the app
Match Rate
Deferred deep link match rates are typically 60-80%. Factors that affect matching:
- Time between click and install (shorter is better)
- Network changes (different Wi-Fi/cellular between click and install)
- Device privacy settings (iOS App Tracking Transparency, Android privacy features)
For the 20-40% of users where deferred matching fails, fall back to the default onboarding flow. The personalized flow is a bonus, not a requirement.
For contextual deep linking patterns, see Contextual Deep Linking: Pass Data Through the Install.
Measuring Personalized Onboarding
Key Metrics
| Metric | Personalized | Default | Expected Lift |
|---|---|---|---|
| Onboarding completion rate | 60-80% | 40-60% | +20-40% |
| Time to complete | 2-4 min | 4-8 min | -50% |
| Day 1 retention | 40-60% | 25-40% | +30-50% |
| First conversion | 20-30% | 10-15% | +50-100% |
A/B Testing
Test personalized vs. default onboarding for users from the same source:
function getOnboardingVariant(context) {
// 50/50 split for users from ad campaigns
if (context.source === 'ad' && Math.random() < 0.5) {
return 'default'; // Control group
}
return getOnboardingFlow(context); // Personalized
}
Track completion rates, retention, and conversion for each variant.
Funnel Analysis
Track each onboarding step with the context:
analytics.track('onboarding_step', {
step: 'account_creation',
flow: context.flow, // 'referral', 'product_focused', 'default'
source: context.source,
campaign: context.campaign,
stepsSkipped: context.skippedSteps.length,
});
This reveals which personalization strategies drive the biggest improvements and which sources produce the highest-quality users.
For onboarding use cases, see the onboarding documentation. For deferred deep linking details, see the deferred deep linking docs. For deep linking features, see Tolinku deep linking.
Get deep linking tips in your inbox
One email per week. No spam.