{"id":826,"date":"2026-04-16T17:00:00","date_gmt":"2026-04-16T22:00:00","guid":{"rendered":"https:\/\/tolinku.com\/blog\/?p=826"},"modified":"2026-03-07T03:33:50","modified_gmt":"2026-03-07T08:33:50","slug":"custom-event-tracking-deep-links","status":"publish","type":"post","link":"https:\/\/tolinku.com\/blog\/custom-event-tracking-deep-links\/","title":{"rendered":"Custom Event Tracking for Deep Link Campaigns"},"content":{"rendered":"\n<p>Clicks and installs tell you how many people engaged with your link. Custom events tell you what those people did after they arrived. Without event tracking, you can&#39;t distinguish between a link that drove 1,000 clicks and zero revenue and one that drove 100 clicks and $5,000 in purchases.<\/p>\n\n\n\n<p>This guide covers how to set up custom event tracking for deep link campaigns so you can measure actual business outcomes, not just traffic.<\/p>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/tolinku.com\/blog\/wp-content\/uploads\/2026\/03\/screenshot-analytics-1772819420927.png\" alt=\"Tolinku analytics dashboard showing click metrics and conversion funnel\">\n<em>The analytics dashboard with date range selector, filters, charts, and breakdowns.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why Custom Events Matter<\/h2>\n\n\n\n<p>Default deep link analytics give you:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Click count<\/li>\n<li>Platform breakdown (iOS, Android, web)<\/li>\n<li>Geographic distribution<\/li>\n<li>Device type<\/li>\n<\/ul>\n\n\n\n<p>These are useful but insufficient. They don&#39;t tell you:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Did the user sign up after clicking?<\/li>\n<li>Did they make a purchase?<\/li>\n<li>What was the purchase value?<\/li>\n<li>Did they complete the onboarding flow?<\/li>\n<li>Did they return the next day?<\/li>\n<\/ul>\n\n\n\n<p>Custom events bridge this gap by tracking specific actions that happen after the click, all attributed back to the original link.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Event Taxonomy<\/h2>\n\n\n\n<p>Before writing any tracking code, define your event taxonomy: the list of events you&#39;ll track, their names, and their properties.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Standard Event Categories<\/h3>\n\n\n\n<p><strong>Acquisition events<\/strong> (user enters your product):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>registration_complete<\/code>: User created an account<\/li>\n<li><code>app_install<\/code>: First app open after install<\/li>\n<li><code>onboarding_complete<\/code>: User finished the onboarding flow<\/li>\n<\/ul>\n\n\n\n<p><strong>Activation events<\/strong> (user finds value):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>first_purchase<\/code>: User made their first purchase<\/li>\n<li><code>first_content_created<\/code>: User created their first piece of content<\/li>\n<li><code>feature_activated<\/code>: User tried a specific feature for the first time<\/li>\n<\/ul>\n\n\n\n<p><strong>Engagement events<\/strong> (user uses the product):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>content_viewed<\/code>: User viewed a specific piece of content<\/li>\n<li><code>search_performed<\/code>: User searched for something<\/li>\n<li><code>item_added_to_cart<\/code>: User added an item to their cart<\/li>\n<li><code>share_initiated<\/code>: User shared content from the app<\/li>\n<\/ul>\n\n\n\n<p><strong>Revenue events<\/strong> (user generates revenue):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>purchase_complete<\/code>: Transaction completed<\/li>\n<li><code>subscription_started<\/code>: User began a subscription<\/li>\n<li><code>in_app_purchase<\/code>: User bought a virtual good or upgrade<\/li>\n<\/ul>\n\n\n\n<p><strong>Retention events<\/strong> (user returns):<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>session_start<\/code>: User opened the app (with session number)<\/li>\n<li><code>streak_continued<\/code>: User maintained a daily\/weekly streak<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Event Properties<\/h3>\n\n\n\n<p>Every event should include properties that provide context:<\/p>\n\n\n\n<pre><code class=\"language-json\">{\n  &quot;event&quot;: &quot;purchase_complete&quot;,\n  &quot;properties&quot;: {\n    &quot;value&quot;: 29.99,\n    &quot;currency&quot;: &quot;USD&quot;,\n    &quot;product_id&quot;: &quot;premium_annual&quot;,\n    &quot;product_name&quot;: &quot;Premium Annual Plan&quot;,\n    &quot;source_link_id&quot;: &quot;summer-sale-2026&quot;,\n    &quot;campaign&quot;: &quot;summer_promo&quot;,\n    &quot;channel&quot;: &quot;email&quot;,\n    &quot;is_first_purchase&quot;: true\n  }\n}\n<\/code><\/pre>\n\n\n\n<p>The <code>source_link_id<\/code> and <code>campaign<\/code> properties tie the event back to the deep link that brought the user in. This is how you attribute revenue to specific links and campaigns.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Connecting Events to Deep Links<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Preserving Link Context<\/h3>\n\n\n\n<p>When a user clicks a deep link and arrives in your app, the link&#39;s metadata (route ID, campaign parameters, UTM tags) needs to persist so that subsequent events can be attributed to that link.<\/p>\n\n\n\n<p><strong>For existing users<\/strong> (app already installed):\nThe deep link handler receives the full URL with all parameters. Store the link context in the user&#39;s session.<\/p>\n\n\n\n<p><strong>For new users<\/strong> (deferred deep linking):\nThe link context is preserved through the install process by your deep linking platform. On first app open, retrieve the deferred link data and store it in the user&#39;s session.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Attribution Window<\/h3>\n\n\n\n<p>Decide how long after a click you&#39;ll attribute events to that link:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Session attribution<\/strong>: Only events within the same session as the click<\/li>\n<li><strong>7-day window<\/strong>: Events within 7 days of the click<\/li>\n<li><strong>30-day window<\/strong>: Events within 30 days of the click (common for purchases)<\/li>\n<\/ul>\n\n\n\n<p>The right window depends on your product&#39;s typical conversion timeline. If users usually purchase within 2 days of clicking, a 7-day window captures most conversions without over-attributing.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Multi-Touch Attribution<\/h3>\n\n\n\n<p>Users often interact with multiple links before converting. A user might click a social media link, then an email link, then finally purchase. Which link gets credit?<\/p>\n\n\n\n<p>Common models:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Last-click<\/strong>: The last link clicked before conversion gets full credit (simplest, most common)<\/li>\n<li><strong>First-click<\/strong>: The first link gets full credit (values discovery)<\/li>\n<li><strong>Linear<\/strong>: Each link gets equal credit<\/li>\n<li><strong>Time-decay<\/strong>: More recent links get more credit<\/li>\n<\/ul>\n\n\n\n<p>For most apps, last-click attribution is a reasonable starting point. It&#39;s simple to implement and aligns with the most immediate driver of conversion.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Implementation Approaches<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">SDK-Based Tracking<\/h3>\n\n\n\n<p>If you use Tolinku&#39;s SDKs, the deep link context is automatically available when the app opens. You can pass this context along with custom events to your <a href=\"https:\/\/tolinku.com\/features\/analytics\">analytics<\/a> backend.<\/p>\n\n\n\n<p><strong>iOS (Swift)<\/strong>:<\/p>\n\n\n\n<pre><code class=\"language-swift\">\/\/ When handling a deep link\nfunc handleDeepLink(url: URL, parameters: [String: String]) {\n    \/\/ Store link context for attribution\n    AnalyticsManager.setAttributionSource(\n        linkId: parameters[&quot;link_id&quot;],\n        campaign: parameters[&quot;campaign&quot;],\n        channel: parameters[&quot;channel&quot;]\n    )\n}\n\n\/\/ When tracking a custom event\nAnalyticsManager.track(&quot;purchase_complete&quot;, properties: [\n    &quot;value&quot;: 29.99,\n    &quot;product_id&quot;: &quot;premium_annual&quot;,\n    \/\/ Attribution context is automatically attached\n])\n<\/code><\/pre>\n\n\n\n<p><strong>Android (Kotlin)<\/strong>:<\/p>\n\n\n\n<pre><code class=\"language-kotlin\">\/\/ When handling a deep link\nfun handleDeepLink(uri: Uri, parameters: Map&lt;String, String&gt;) {\n    AnalyticsManager.setAttributionSource(\n        linkId = parameters[&quot;link_id&quot;],\n        campaign = parameters[&quot;campaign&quot;],\n        channel = parameters[&quot;channel&quot;]\n    )\n}\n\n\/\/ When tracking a custom event\nAnalyticsManager.track(&quot;purchase_complete&quot;, mapOf(\n    &quot;value&quot; to 29.99,\n    &quot;product_id&quot; to &quot;premium_annual&quot;\n))\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Server-Side Tracking<\/h3>\n\n\n\n<p>For events that happen on your server (subscription renewals, backend-triggered actions), send events via your analytics API:<\/p>\n\n\n\n<pre><code class=\"language-bash\">POST \/v1\/analytics\/events\n{\n  &quot;user_id&quot;: &quot;user_123&quot;,\n  &quot;event&quot;: &quot;subscription_renewed&quot;,\n  &quot;properties&quot;: {\n    &quot;plan&quot;: &quot;premium&quot;,\n    &quot;value&quot;: 9.99,\n    &quot;period&quot;: &quot;monthly&quot;\n  },\n  &quot;attribution&quot;: {\n    &quot;link_id&quot;: &quot;onboarding-promo&quot;,\n    &quot;campaign&quot;: &quot;new_user_trial&quot;,\n    &quot;original_click_at&quot;: &quot;2026-04-10T14:30:00Z&quot;\n  }\n}\n<\/code><\/pre>\n\n\n\n<p>Server-side tracking is more reliable than client-side because it&#39;s not affected by app crashes, SDK initialization timing, or network issues.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Hybrid Approach<\/h3>\n\n\n\n<p>Most apps use both:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Client-side<\/strong> for user interaction events (screen views, button taps, content engagement)<\/li>\n<li><strong>Server-side<\/strong> for business-critical events (purchases, subscription changes, account actions)<\/li>\n<\/ul>\n\n\n\n<p>The server-side events serve as the source of truth for revenue attribution.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">UTM Parameters and Campaign Tracking<\/h2>\n\n\n\n<p><a href=\"https:\/\/tolinku.com\/blog\/utm-parameters-short-links\/\">UTM parameters<\/a> provide campaign-level attribution for your deep links:<\/p>\n\n\n\n<pre><code>https:\/\/go.yourapp.com\/summer-sale?utm_source=email&amp;utm_medium=newsletter&amp;utm_campaign=summer_promo_2026&amp;utm_content=hero_banner\n<\/code><\/pre>\n\n\n\n<p>When the user clicks this link, the UTM values are captured and passed to your analytics. All subsequent events from this user (within the attribution window) carry these UTM values, letting you analyze performance by source, medium, campaign, and content.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Naming Conventions<\/h3>\n\n\n\n<p>Consistent naming is critical. Without it, &quot;email&quot; and &quot;Email&quot; and &quot;EMAIL&quot; become three separate sources in your reports.<\/p>\n\n\n\n<p>Establish and document naming conventions:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>utm_source<\/strong>: Lowercase, no spaces (email, facebook, twitter, google)<\/li>\n<li><strong>utm_medium<\/strong>: Lowercase (cpc, social, email, referral, push)<\/li>\n<li><strong>utm_campaign<\/strong>: Lowercase with underscores (summer_sale_2026, new_user_promo)<\/li>\n<li><strong>utm_content<\/strong>: Lowercase with underscores (hero_banner, sidebar_link, cta_button)<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Analyzing Event Data<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Funnel Analysis<\/h3>\n\n\n\n<p>Build funnels that show the path from click to conversion:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Link Click (100%)<\/li>\n<li>App Open (72%)<\/li>\n<li>Product Viewed (45%)<\/li>\n<li>Added to Cart (18%)<\/li>\n<li>Purchase Complete (8%)<\/li>\n<\/ol>\n\n\n\n<p>Each drop-off point reveals where to focus optimization. See <a href=\"https:\/\/tolinku.com\/blog\/conversion-funnel-analysis-deep-links\/\">Conversion Funnel Analysis for Deep Links<\/a> for a detailed guide.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Cohort Analysis<\/h3>\n\n\n\n<p>Group users by the campaign or link that brought them in and track their behavior over time:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Users from the &quot;summer_sale&quot; campaign: 12% purchase rate, $35 average order value<\/li>\n<li>Users from the &quot;referral_program&quot; campaign: 18% purchase rate, $42 average order value<\/li>\n<li>Users from the &quot;social_organic&quot; campaign: 6% purchase rate, $28 average order value<\/li>\n<\/ul>\n\n\n\n<p>This tells you which campaigns attract the most valuable users, not just the most clicks.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Revenue Attribution<\/h3>\n\n\n\n<p>The ultimate question: how much revenue did each link or campaign generate?<\/p>\n\n\n\n<p>Sum the revenue from all purchase events attributed to each link:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>Link\/Campaign<\/th>\n<th>Clicks<\/th>\n<th>Purchases<\/th>\n<th>Revenue<\/th>\n<th>Revenue per Click<\/th>\n<\/tr>\n<\/thead>\n<tbody><tr>\n<td>summer-sale-email<\/td>\n<td>5,200<\/td>\n<td>312<\/td>\n<td>$8,736<\/td>\n<td>$1.68<\/td>\n<\/tr>\n<tr>\n<td>summer-sale-social<\/td>\n<td>12,400<\/td>\n<td>248<\/td>\n<td>$5,952<\/td>\n<td>$0.48<\/td>\n<\/tr>\n<tr>\n<td>referral-invite<\/td>\n<td>800<\/td>\n<td>144<\/td>\n<td>$5,040<\/td>\n<td>$6.30<\/td>\n<\/tr>\n<\/tbody><\/table><\/figure>\n\n\n\n<p>Revenue per click is the key efficiency metric. The referral link drove the fewest clicks but the highest revenue per click.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Common Mistakes<\/h2>\n\n\n\n<p><strong>Tracking too many events<\/strong>: Start with 5-10 core events, not 50. Each event should be tied to a decision you need to make. If you wouldn&#39;t change anything based on the event data, don&#39;t track it.<\/p>\n\n\n\n<p><strong>Inconsistent event naming<\/strong>: &quot;PurchaseComplete,&quot; &quot;purchase_complete,&quot; and &quot;Purchase Complete&quot; are three different events in your analytics. Standardize on one format.<\/p>\n\n\n\n<p><strong>Missing attribution context<\/strong>: Events without link\/campaign attribution are useless for campaign analysis. Always attach the source link context to events.<\/p>\n\n\n\n<p><strong>No server-side validation<\/strong>: Client-side purchase events can be duplicated, missed, or fraudulent. Validate revenue events on the server.<\/p>\n\n\n\n<p><strong>Ignoring event properties<\/strong>: An event like &quot;purchase_complete&quot; without the purchase value, product ID, or user segment is almost useless. Always include relevant properties.<\/p>\n\n\n\n<p>For a broader view of 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","protected":false},"excerpt":{"rendered":"<p>Track custom events triggered by deep links. Set up event tracking for purchases, sign-ups, and in-app actions attributed to specific links.<\/p>\n","protected":false},"author":2,"featured_media":825,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"rank_math_title":"Custom Event Tracking for Deep Link Campaigns","rank_math_description":"Track custom events triggered by deep links. Set up event tracking for purchases, sign-ups, and in-app actions attributed to specific links.","rank_math_focus_keyword":"custom event tracking","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-custom-event-tracking-deep-links.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-custom-event-tracking-deep-links.png","footnotes":""},"categories":[14],"tags":[37,28,38,39,20,29],"class_list":["post-826","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-analytics","tag-analytics","tag-attribution","tag-campaign-tracking","tag-conversion","tag-deep-linking","tag-mobile-marketing"],"_links":{"self":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/826","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=826"}],"version-history":[{"count":2,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/826\/revisions"}],"predecessor-version":[{"id":2162,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/posts\/826\/revisions\/2162"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media\/825"}],"wp:attachment":[{"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/media?parent=826"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/categories?post=826"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tolinku.com\/blog\/wp-json\/wp\/v2\/tags?post=826"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}