{"id":996,"date":"2026-05-05T13:00:00","date_gmt":"2026-05-05T18:00:00","guid":{"rendered":"https:\/\/tolinku.com\/blog\/?p=996"},"modified":"2026-03-07T04:45:43","modified_gmt":"2026-03-07T09:45:43","slug":"contextual-onboarding","status":"publish","type":"post","link":"https:\/\/tolinku.com\/blog\/contextual-onboarding\/","title":{"rendered":"Contextual Onboarding: Adapting to User Intent"},"content":{"rendered":"\n<p>Every user who installs your app has an intent. Someone who tapped an ad for running shoes wants to see running shoes. Someone who followed a friend&#39;s referral wants to know what their friend uses the app for. Someone who scanned a QR code at a restaurant wants to see the menu. Contextual onboarding reads this intent from the deep link data and adapts accordingly.<\/p>\n\n\n\n<p>For personalization strategies, see <a href=\"https:\/\/tolinku.com\/blog\/personalized-onboarding-flows\/\">Personalized Onboarding Flows with Deep Link Data<\/a>. For invite-specific flows, see <a href=\"https:\/\/tolinku.com\/blog\/invite-link-onboarding\/\">Invite Link Onboarding: From Invitation to Active User<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Intent Signals in Deep Links<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">What Deep Links Tell You<\/h3>\n\n\n\n<p>Every deep link carries intent signals, even if they&#39;re implicit. For a comprehensive look at how contextual deep linking works under the hood, see the <a href=\"https:\/\/tolinku.com\/blog\/contextual-deep-linking-guide\/\">Contextual Deep Linking Guide<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Signal<\/th>\n<th>Example Parameter<\/th>\n<th>Implied Intent<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Product category<\/td>\n<td><code>category=running<\/code><\/td>\n<td>Wants running products<\/td>\n<\/tr>\n<tr>\n<td>Specific item<\/td>\n<td><code>product_id=abc123<\/code><\/td>\n<td>Wants to see this product<\/td>\n<\/tr>\n<tr>\n<td>Referrer<\/td>\n<td><code>ref=sarah_123<\/code><\/td>\n<td>Trusts the referrer<\/td>\n<\/tr>\n<tr>\n<td>Campaign<\/td>\n<td><code>utm_campaign=summer_sale<\/code><\/td>\n<td>Interested in deals<\/td>\n<\/tr>\n<tr>\n<td>Feature<\/td>\n<td><code>feature=workout_tracker<\/code><\/td>\n<td>Wants this specific capability<\/td>\n<\/tr>\n<tr>\n<td>Location context<\/td>\n<td><code>store=downtown_branch<\/code><\/td>\n<td>In-store shopper<\/td>\n<\/tr>\n<tr>\n<td>Content type<\/td>\n<td><code>content=recipe_collection<\/code><\/td>\n<td>Interested in recipes<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Capturing Intent<\/h3>\n\n\n\n<pre><code class=\"language-javascript\">async function captureUserIntent() {\n  const deferred = await Tolinku.checkDeferredLink();\n\n  if (deferred === null) {\n    return { type: &#39;organic&#39;, confidence: &#39;low&#39; };\n  }\n\n  const params = deferred.params;\n  const path = deferred.path;\n\n  \/\/ Determine intent type and confidence\n  if (params.product_id) {\n    return {\n      type: &#39;product_specific&#39;,\n      confidence: &#39;high&#39;,\n      product: params.product_id,\n      source: params.utm_source,\n    };\n  }\n\n  if (params.category) {\n    return {\n      type: &#39;category_interest&#39;,\n      confidence: &#39;medium&#39;,\n      category: params.category,\n      source: params.utm_source,\n    };\n  }\n\n  if (params.ref) {\n    return {\n      type: &#39;referral&#39;,\n      confidence: &#39;high&#39;,\n      referrer: params.ref,\n      referrerName: params.referrer_name,\n    };\n  }\n\n  if (params.utm_campaign) {\n    return {\n      type: &#39;campaign&#39;,\n      confidence: &#39;medium&#39;,\n      campaign: params.utm_campaign,\n      source: params.utm_source,\n    };\n  }\n\n  return {\n    type: &#39;deep_link_generic&#39;,\n    confidence: &#39;low&#39;,\n    path: path,\n  };\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Adapting the Flow<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Intent-Based Routing<\/h3>\n\n\n\n<pre><code class=\"language-javascript\">function OnboardingRouter({ intent }) {\n  switch (intent.type) {\n    case &#39;product_specific&#39;:\n      return &lt;ProductFocusedOnboarding intent={intent} \/&gt;;\n\n    case &#39;category_interest&#39;:\n      return &lt;CategoryOnboarding intent={intent} \/&gt;;\n\n    case &#39;referral&#39;:\n      return &lt;ReferralOnboarding intent={intent} \/&gt;;\n\n    case &#39;campaign&#39;:\n      return &lt;CampaignOnboarding intent={intent} \/&gt;;\n\n    case &#39;organic&#39;:\n    default:\n      return &lt;StandardOnboarding \/&gt;;\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Product-Specific Intent<\/h3>\n\n\n\n<p>The user clicked a link to a specific product. Show it immediately, then onboard around it:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">function ProductFocusedOnboarding({ intent }) {\n  const [phase, setPhase] = useState(&#39;product_view&#39;);\n\n  return (\n    &lt;View&gt;\n      {phase === &#39;product_view&#39; &amp;&amp; (\n        &lt;ProductPreview\n          productId={intent.product}\n          onContinue={() =&gt; setPhase(&#39;signup&#39;)}\n          ctaText=&quot;Sign up to purchase&quot;\n        \/&gt;\n      )}\n\n      {phase === &#39;signup&#39; &amp;&amp; (\n        &lt;QuickSignup\n          context={`Sign up to buy ${intent.productName}`}\n          onComplete={() =&gt; setPhase(&#39;purchase&#39;)}\n        \/&gt;\n      )}\n\n      {phase === &#39;purchase&#39; &amp;&amp; (\n        &lt;ProductPage\n          productId={intent.product}\n          showPromoBanner={intent.promoCode ? true : false}\n        \/&gt;\n      )}\n    &lt;\/View&gt;\n  );\n}\n<\/code><\/pre>\n\n\n\n<p>This flow is: show value, then ask for commitment. The product view gives the user a reason to sign up.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Category Interest<\/h3>\n\n\n\n<p>The user came from an ad or content about a specific category. Pre-select their interest:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">function CategoryOnboarding({ intent }) {\n  return (\n    &lt;View&gt;\n      &lt;WelcomeScreen\n        headline={getCategoryWelcome(intent.category)}\n        subtext=&quot;Let&#39;s set up your experience.&quot;\n      \/&gt;\n\n      &lt;AccountCreation \/&gt;\n\n      {\/* Skip &quot;What are you interested in?&quot; \u2014 we already know *\/}\n      &lt;CategoryFeed\n        category={intent.category}\n        preSelected={true}\n      \/&gt;\n    &lt;\/View&gt;\n  );\n}\n\nfunction getCategoryWelcome(category) {\n  const welcomes = {\n    running: &#39;Ready to find your perfect running gear?&#39;,\n    cooking: &#39;Let us help you discover new recipes.&#39;,\n    fitness: &#39;Your fitness journey starts here.&#39;,\n    travel: &#39;Where are you headed next?&#39;,\n  };\n\n  return welcomes[category] || `Welcome! Let&#39;s get you started.`;\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Campaign Context<\/h3>\n\n\n\n<p>Users from marketing campaigns expect to see what was advertised:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">function CampaignOnboarding({ intent }) {\n  const campaign = getCampaignConfig(intent.campaign);\n\n  return (\n    &lt;View&gt;\n      &lt;CampaignLanding\n        headline={campaign.headline}\n        heroImage={campaign.image}\n        ctaText={campaign.cta}\n      \/&gt;\n\n      &lt;AccountCreation promoCode={campaign.promoCode} \/&gt;\n\n      {\/* Navigate to the campaign-specific content *\/}\n      &lt;Redirect to={campaign.destinationScreen} \/&gt;\n    &lt;\/View&gt;\n  );\n}\n\nfunction getCampaignConfig(campaignId) {\n  const campaigns = {\n    summer_sale: {\n      headline: &#39;Summer Sale: Up to 50% Off&#39;,\n      image: &#39;summer-sale-hero.jpg&#39;,\n      cta: &#39;Shop the Sale&#39;,\n      promoCode: &#39;SUMMER50&#39;,\n      destinationScreen: &#39;\/sale\/summer&#39;,\n    },\n    new_feature: {\n      headline: &#39;Introducing Workout Tracking&#39;,\n      image: &#39;workout-tracking-hero.jpg&#39;,\n      cta: &#39;Try It Free&#39;,\n      promoCode: null,\n      destinationScreen: &#39;\/feature\/workout-tracking&#39;,\n    },\n  };\n\n  return campaigns[campaignId] || { headline: &#39;Welcome&#39;, cta: &#39;Get Started&#39; };\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Context Confidence Levels<\/h2>\n\n\n\n<p>Not all context is equally reliable. Handle uncertainty:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">High Confidence (Act on It)<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Specific product ID in the URL<\/li>\n<li>Referrer ID with valid account<\/li>\n<li>Known campaign with active config<\/li>\n<\/ul>\n\n\n\n<p>These are safe to use for onboarding customization. Show the product, acknowledge the referrer, display the campaign offer.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Medium Confidence (Suggest, Don&#39;t Assume)<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Category from UTM parameters<\/li>\n<li>Feature interest from content link<\/li>\n<li>Location from QR code<\/li>\n<\/ul>\n\n\n\n<p>Use these to pre-select options or reorder content, but let the user change. For a reference on which parameters to include in your links, see <a href=\"https:\/\/tolinku.com\/blog\/onboarding-deep-link-parameters\/\">Onboarding Deep Link Parameters<\/a>.<\/p>\n\n\n\n<pre><code class=\"language-javascript\">function InterestPicker({ suggestedCategory }) {\n  const [selected, setSelected] = useState(suggestedCategory);\n\n  return (\n    &lt;View&gt;\n      {suggestedCategory &amp;&amp; (\n        &lt;Text&gt;Based on how you found us, we think you&#39;re interested in:&lt;\/Text&gt;\n      )}\n\n      &lt;CategoryGrid\n        categories={allCategories}\n        selected={selected}\n        onSelect={setSelected}\n        highlighted={suggestedCategory}\n      \/&gt;\n    &lt;\/View&gt;\n  );\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Low Confidence (Fall Back to Default)<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>No deep link data (organic install)<\/li>\n<li>Deep link with only UTM source (no specific content)<\/li>\n<li>Expired or invalid deep link<\/li>\n<\/ul>\n\n\n\n<p>Use the standard onboarding flow.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Contextual Permission Requests<\/h2>\n\n\n\n<p>Tie permission requests to the user&#39;s intent:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">function getPermissionContext(intent) {\n  switch (intent.type) {\n    case &#39;product_specific&#39;:\n      return {\n        push: &#39;Get notified when this item goes on sale or ships.&#39;,\n        location: &#39;Find stores near you that carry this item.&#39;,\n      };\n\n    case &#39;category_interest&#39;:\n      return {\n        push: `Get alerts for new ${intent.category} arrivals and deals.`,\n        location: null, \/\/ Not relevant\n      };\n\n    case &#39;referral&#39;:\n      return {\n        push: `Get notified when ${intent.referrerName} shares something new.`,\n        location: null,\n      };\n\n    default:\n      return {\n        push: &#39;Get notified about updates and personalized recommendations.&#39;,\n        location: &#39;Find relevant content near you.&#39;,\n      };\n  }\n}\n<\/code><\/pre>\n\n\n\n<p>Contextual permission explanations have higher grant rates because the user understands the specific benefit.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Handling Context Across Sessions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Persisting Context<\/h3>\n\n\n\n<p>Store the intent data so it can influence the experience beyond the first session:<\/p>\n\n\n\n<pre><code class=\"language-javascript\">async function persistIntent(userId, intent) {\n  await userPreferences.set(userId, {\n    initialIntent: intent,\n    primaryCategory: intent.category,\n    acquisitionSource: intent.source,\n    referrer: intent.referrer,\n    capturedAt: Date.now(),\n  });\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Using Context After Onboarding<\/h3>\n\n\n\n<p>The deep link context is valuable beyond onboarding:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Home feed<\/strong>: Prioritize content from the user&#39;s initial category<\/li>\n<li><strong>Recommendations<\/strong>: Weight suggestions toward the initial interest<\/li>\n<li><strong>Notifications<\/strong>: Reference the initial context (&quot;More items like the one you first looked at&quot;)<\/li>\n<li><strong>Re-engagement<\/strong>: If the user churns, remind them of their original interest<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Measuring Contextual Onboarding<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Compare Against Standard<\/h3>\n\n\n\n<pre><code class=\"language-javascript\">async function contextualOnboardingReport(dateRange) {\n  const segments = [\n    { name: &#39;Organic (no context)&#39;, filter: { intentType: &#39;organic&#39; } },\n    { name: &#39;Product-specific&#39;, filter: { intentType: &#39;product_specific&#39; } },\n    { name: &#39;Category interest&#39;, filter: { intentType: &#39;category_interest&#39; } },\n    { name: &#39;Referral&#39;, filter: { intentType: &#39;referral&#39; } },\n    { name: &#39;Campaign&#39;, filter: { intentType: &#39;campaign&#39; } },\n  ];\n\n  for (const seg of segments) {\n    const completion = await getCompletionRate(dateRange, seg.filter);\n    const activation = await getActivationRate(dateRange, seg.filter);\n    const retention = await getDay7Retention(dateRange, seg.filter);\n\n    console.log(seg.name, {\n      completion: completion.toFixed(1) + &#39;%&#39;,\n      activation: activation.toFixed(1) + &#39;%&#39;,\n      day7Retention: retention.toFixed(1) + &#39;%&#39;,\n    });\n  }\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Expected Results<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Segment<\/th>\n<th>Completion<\/th>\n<th>Activation<\/th>\n<th>Day 7 Retention<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Organic<\/td>\n<td>42%<\/td>\n<td>18%<\/td>\n<td>12%<\/td>\n<\/tr>\n<tr>\n<td>Product-specific<\/td>\n<td>58%<\/td>\n<td>35%<\/td>\n<td>22%<\/td>\n<\/tr>\n<tr>\n<td>Category interest<\/td>\n<td>52%<\/td>\n<td>28%<\/td>\n<td>18%<\/td>\n<\/tr>\n<tr>\n<td>Referral<\/td>\n<td>68%<\/td>\n<td>42%<\/td>\n<td>30%<\/td>\n<\/tr>\n<tr>\n<td>Campaign<\/td>\n<td>48%<\/td>\n<td>22%<\/td>\n<td>14%<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<p>Product-specific and referral contexts produce the highest-quality users because the intent is clearest.<\/p>\n\n\n\n<p>For deferred deep linking, see the <a href=\"https:\/\/tolinku.com\/docs\/concepts\/deferred-deep-linking\/\">deferred deep linking docs<\/a>. For deep linking features, see <a href=\"https:\/\/tolinku.com\/features\/deep-linking\">Tolinku deep linking<\/a>. For onboarding use cases, see the <a href=\"https:\/\/tolinku.com\/docs\/use-cases\/onboarding\/\">onboarding documentation<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Adapt your onboarding flow based on how users arrive. Use deep link context, referral data, and campaign parameters to match onboarding to user intent.<\/p>\n","protected":false},"author":2,"featured_media":995,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Contextual Onboarding: Adapting to User Intent","rank_math_description":"Adapt your onboarding flow based on how users arrive. Use deep link context, referral data, and campaign parameters to match onboarding to user intent.","rank_math_focus_keyword":"contextual onboarding","rank_math_canonical_url":"","rank_math_facebook_title":"","rank_math_facebook_description":"","rank_math_facebook_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-contextual-onboarding.png","rank_math_facebook_image_id":"","rank_math_twitter_title":"","rank_math_twitter_description":"","rank_math_twitter_image":"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/og-contextual-onboarding.png","footnotes":""},"categories":[18],"tags":[228,191,20,21,69,27,43,33],"class_list":["post-996","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-use-cases","tag-contextual-deep-linking","tag-conversions","tag-deep-linking","tag-deferred-deep-linking","tag-mobile-development","tag-onboarding","tag-personalization","tag-user-experience"],"_links":{"self":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/996","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/comments?post=996"}],"version-history":[{"count":4,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/996\/revisions"}],"predecessor-version":[{"id":2811,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/996\/revisions\/2811"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media\/995"}],"wp:attachment":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media?parent=996"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/categories?post=996"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/tags?post=996"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}