{"id":1740,"date":"2026-07-13T17:00:00","date_gmt":"2026-07-13T22:00:00","guid":{"rendered":"https:\/\/tolinku.com\/blog\/?p=1740"},"modified":"2026-03-07T03:50:06","modified_gmt":"2026-03-07T08:50:06","slug":"re-engagement-attribution","status":"publish","type":"post","link":"https:\/\/tolinku.com\/blog\/re-engagement-attribution\/","title":{"rendered":"Re-Engagement Attribution for Mobile Apps"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Re-engagement attribution measures whether a campaign brought back a lapsed user. Unlike install attribution (which tracks new users), re-engagement attribution tracks returning users who were inactive and then resumed using the app after exposure to a retargeting ad, push notification, or email campaign.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide covers how re-engagement attribution works. For attribution models, see <a href=\"https:\/\/tolinku.com\/blog\/last-click-vs-multi-touch-attribution\/\">last-click vs multi-touch attribution<\/a>. For deep link analytics, see <a href=\"https:\/\/tolinku.com\/blog\/deep-link-analytics-measuring-what-matters\/\">deep link analytics: measuring what matters<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What Counts as Re-Engagement<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A re-engagement event occurs when:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>An existing user has been inactive for a defined period (the inactivity window).<\/li>\n<li>The user is exposed to a re-engagement campaign (ad, push notification, email, SMS).<\/li>\n<li>The user returns to the app.<\/li>\n<li>The return is attributed to the campaign.<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Defining &quot;Inactive&quot;<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The inactivity window varies by app category:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>App Category<\/th>\n<th>Typical Inactivity Window<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Social media<\/td>\n<td>7 days<\/td>\n<\/tr>\n<tr>\n<td>E-commerce<\/td>\n<td>14 days<\/td>\n<\/tr>\n<tr>\n<td>Gaming<\/td>\n<td>7 days<\/td>\n<\/tr>\n<tr>\n<td>Fintech\/Banking<\/td>\n<td>30 days<\/td>\n<\/tr>\n<tr>\n<td>News\/Media<\/td>\n<td>14 days<\/td>\n<\/tr>\n<tr>\n<td>Health\/Fitness<\/td>\n<td>7 days<\/td>\n<\/tr>\n<tr>\n<td>Travel<\/td>\n<td>30 days<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">A fintech app might define a user as &quot;lapsed&quot; after 30 days of no app opens. A gaming app might use 7 days. Choose a window that reflects normal usage patterns for your app.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Re-Engagement Attribution Models<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Click-Through Re-Engagement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The user taps a retargeting ad or deep link, which opens the app:<\/p>\n\n\n\n<pre><code>1. User is inactive for 30 days\n2. User sees retargeting ad on Facebook\n3. User taps the ad \u2192 deep link opens the app\n4. Re-engagement attributed to Facebook retargeting campaign\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is the strongest signal because the user took a deliberate action.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">View-Through Re-Engagement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The user sees a retargeting ad but does not tap it. Later, they open the app on their own:<\/p>\n\n\n\n<pre><code>1. User is inactive for 14 days\n2. User sees retargeting display ad (does not tap)\n3. 6 hours later, user opens the app from the home screen\n4. Re-engagement attributed to display retargeting (view-through)\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This is a weaker signal. The user may have returned independently.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Push Notification Re-Engagement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The user taps a push notification that deep links to the app:<\/p>\n\n\n\n<pre><code>1. User is inactive for 7 days\n2. App sends push notification: &quot;New items added to your wishlist&quot;\n3. User taps notification \u2192 deep link opens wishlist screen\n4. Re-engagement attributed to push notification campaign\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Email Re-Engagement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The user taps a link in a re-engagement email:<\/p>\n\n\n\n<pre><code>1. User is inactive for 21 days\n2. User receives email: &quot;We miss you! Here&#39;s 20% off&quot;\n3. User taps email link \u2192 deep link opens the app\n4. Re-engagement attributed to email campaign\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Re-Engagement Windows<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The re-engagement attribution window defines how long after a campaign interaction the return is attributed to that campaign:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Channel<\/th>\n<th>Typical Click Window<\/th>\n<th>Typical View Window<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Retargeting ads<\/td>\n<td>7 days<\/td>\n<td>24 hours<\/td>\n<\/tr>\n<tr>\n<td>Push notifications<\/td>\n<td>24 hours<\/td>\n<td>N\/A<\/td>\n<\/tr>\n<tr>\n<td>Email<\/td>\n<td>7 days<\/td>\n<td>N\/A<\/td>\n<\/tr>\n<tr>\n<td>SMS<\/td>\n<td>48 hours<\/td>\n<td>N\/A<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">If a user taps a retargeting ad today and opens the app in 3 days, the re-engagement is attributed to the ad (within the 7-day window). If they open the app in 10 days, it is counted as organic return.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Implementation<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Tracking Re-Engagement Events<\/h3>\n\n\n\n<pre><code class=\"language-swift\">func trackAppOpen() {\n    let lastActive = UserDefaults.standard.object(forKey: &quot;last_active&quot;) as? Date\n    let now = Date()\n\n    \/\/ Update last active\n    UserDefaults.standard.set(now, forKey: &quot;last_active&quot;)\n\n    guard let lastActive = lastActive else {\n        \/\/ First open ever, this is an install not a re-engagement\n        analytics.track(&quot;install&quot;)\n        return\n    }\n\n    let inactiveDays = Calendar.current.dateComponents([.day], from: lastActive, to: now).day ?? 0\n\n    if inactiveDays &gt;= 7 {\n        \/\/ User was inactive, this is a re-engagement\n        let source = determineReEngagementSource()\n        analytics.track(&quot;re_engagement&quot;, properties: [\n            &quot;inactive_days&quot;: inactiveDays,\n            &quot;source&quot;: source.channel,\n            &quot;campaign&quot;: source.campaignId ?? &quot;unknown&quot;,\n            &quot;deep_link&quot;: source.deepLink ?? &quot;none&quot;\n        ])\n    } else {\n        \/\/ Regular app open\n        analytics.track(&quot;app_open&quot;)\n    }\n}\n\nfunc determineReEngagementSource() -&gt; ReEngagementSource {\n    \/\/ Check if the app was opened via a deep link\n    if let pendingDeepLink = deepLinkManager.pendingDeepLink {\n        let params = URLComponents(url: pendingDeepLink, resolvingAgainstBaseURL: false)?.queryItems\n        let campaign = params?.first(where: { $0.name == &quot;utm_campaign&quot; })?.value\n        let source = params?.first(where: { $0.name == &quot;utm_source&quot; })?.value\n\n        return ReEngagementSource(\n            channel: source ?? &quot;deep_link&quot;,\n            campaignId: campaign,\n            deepLink: pendingDeepLink.absoluteString\n        )\n    }\n\n    \/\/ Check if opened from a push notification\n    if let notificationData = notificationManager.lastTappedNotification {\n        return ReEngagementSource(\n            channel: &quot;push&quot;,\n            campaignId: notificationData[&quot;campaign_id&quot;] as? String,\n            deepLink: notificationData[&quot;deep_link&quot;] as? String\n        )\n    }\n\n    \/\/ Organic return\n    return ReEngagementSource(channel: &quot;organic&quot;, campaignId: nil, deepLink: nil)\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Deep Link Attribution for Re-Engagement<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When a re-engagement deep link is clicked, capture attribution data:<\/p>\n\n\n\n<pre><code class=\"language-swift\">func handleReEngagementDeepLink(_ url: URL) {\n    let params = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems\n\n    let attributionData = ReEngagementAttribution(\n        channel: params?.first(where: { $0.name == &quot;utm_source&quot; })?.value ?? &quot;unknown&quot;,\n        campaign: params?.first(where: { $0.name == &quot;utm_campaign&quot; })?.value,\n        medium: params?.first(where: { $0.name == &quot;utm_medium&quot; })?.value,\n        content: params?.first(where: { $0.name == &quot;utm_content&quot; })?.value,\n        deepLink: url.absoluteString,\n        timestamp: Date()\n    )\n\n    \/\/ Store for server-side processing\n    analytics.trackReEngagement(attributionData)\n\n    \/\/ Route to the deep linked screen\n    routeDeepLink(url)\n}\n<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Measuring Re-Engagement Effectiveness<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Key Metrics<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Metric<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>Re-engagement rate<\/td>\n<td>Lapsed users who returned \/ total lapsed users targeted<\/td>\n<\/tr>\n<tr>\n<td>Cost per re-engagement (CPRE)<\/td>\n<td>Campaign spend \/ re-engaged users<\/td>\n<\/tr>\n<tr>\n<td>Retention after re-engagement<\/td>\n<td>% of re-engaged users still active after 7\/30 days<\/td>\n<\/tr>\n<tr>\n<td>Revenue per re-engaged user<\/td>\n<td>Revenue from re-engaged users in the 30 days after return<\/td>\n<\/tr>\n<tr>\n<td>Incremental re-engagement<\/td>\n<td>Re-engagements attributable to the campaign vs. organic returns<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Incrementality<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Not all re-engaged users would have stayed inactive without the campaign. Some would have returned on their own. To measure incremental re-engagement:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Split lapsed users into a test group (receives campaign) and a control group (does not).<\/li>\n<li>Measure return rates for both groups.<\/li>\n<li>The difference is the incremental lift.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Test group return rate: 12%<\/li>\n<li>Control group return rate: 5%<\/li>\n<li>Incremental lift: 7 percentage points<\/li>\n<li>True incremental re-engagement rate: 7%<\/li>\n<li>Of the 12% who returned in the test group, only 58% (7\/12) were truly influenced by the campaign.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Common Pitfalls<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Over-Attributing to Push Notifications<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Push notifications have high tap rates, so they appear to be the most effective re-engagement channel. But many users would have opened the app anyway; the push notification just happened to be the trigger. Use holdout groups to measure true incrementality.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Ignoring Organic Returns<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If your re-engagement campaign reaches 100,000 lapsed users and 8,000 return, it is tempting to credit all 8,000 to the campaign. But if 3,000 would have returned organically, the campaign only drove 5,000 incremental re-engagements.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Short Attribution Windows<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Using a 1-hour re-engagement window for email campaigns misses users who open the email, decide to return, but do not do so until the next day. Match the attribution window to the channel&#39;s natural response time.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tolinku for Re-Engagement<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/tolinku.com\/features\/analytics\">Tolinku&#39;s analytics<\/a> track deep link clicks and attribute re-engagement events. When a lapsed user taps a Tolinku deep link in a re-engagement email or ad, the click and subsequent app open are tracked and attributed. Configure re-engagement tracking in the <a href=\"https:\/\/tolinku.com\/docs\/user-guide\/analytics\/\">Tolinku dashboard<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For mobile attribution, see <a href=\"https:\/\/tolinku.com\/blog\/mobile-attribution-developers-guide\/\">mobile attribution: a developer&#39;s guide<\/a>. For attribution models, see <a href=\"https:\/\/tolinku.com\/blog\/last-click-vs-multi-touch-attribution\/\">last-click vs multi-touch attribution<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Track and attribute re-engagement campaigns accurately. Measure the impact of retargeting, push notifications, and email on returning users.<\/p>\n","protected":false},"author":2,"featured_media":1739,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Re-Engagement Attribution for Mobile Apps","rank_math_description":"Track and attribute re-engagement campaigns accurately. Measure the impact of retargeting, push notifications, and email on returning users.","rank_math_focus_keyword":"re-engagement attribution","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-re-engagement-attribution.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-re-engagement-attribution.png","footnotes":""},"categories":[14],"tags":[37,28,520,20,69,120,514,47],"class_list":["post-1740","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-analytics","tag-attribution","tag-campaign-measurement","tag-deep-linking","tag-mobile-development","tag-re-engagement","tag-retargeting","tag-retention"],"_links":{"self":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1740","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=1740"}],"version-history":[{"count":3,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1740\/revisions"}],"predecessor-version":[{"id":2693,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/1740\/revisions\/2693"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media\/1739"}],"wp:attachment":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media?parent=1740"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/categories?post=1740"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/tags?post=1740"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}