Home Guides Analytics Integration Guide

Analytics Integration Guide

Last updated on Apr 04, 2026

LinkMe resolves deep links and passes attribution data (UTM parameters) directly to your app. To view this data in your analytics dashboard (Firebase, PostHog, Mixpanel, etc.), you must manually log the campaign event when a link is received.

[!IMPORTANT] Why is manual logging required? While some analytics SDKs attempt to automatically scrape "direct" deep links from the OS, they cannot detect Deferred Deep Links (links that survive the app install process).

LinkMe fetches deferred data via an API call after your app launches. To attribute these installs correctly, you must take the payload from LinkMe and hand it to your analytics provider.

Prefer server-side streaming?

If you want LinkMe to push events directly to your backend (instead of only SDK-side logging), use the dedicated Webhooks Guide. It covers event subscriptions, delivery history, retries/backoff, and optional request signing.

When to Log

You should log the campaign event in two places to cover all scenarios:

  1. Cold Start / Install: Inside the getInitialLink callback.
  2. Warm Start: Inside the addListener (or onLink) callback.

Link analytics dashboard showing click totals, UTM properties, and payload details

The portal logs mirror what your downstream analytics stack should store—UTM keys, link IDs, and the computed destination—so you can sanity-check payloads before emitting events.

If you are still validating routing before wiring analytics, run the Universal Links Validator, review link analytics, or open the Portal to inspect real click payloads and campaign metadata side by side.

Firebase Analytics (Google Analytics 4)

Official Documentation: Log events

Firebase uses specific parameter names (source, medium, campaign) instead of standard UTM keys (utm_source, etc.). You must map them.

Android (Kotlin)

import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.FirebaseAnalytics.Event
import com.google.firebase.analytics.FirebaseAnalytics.Param

fun logToFirebase(payload: LinkPayload) {
    val utm = payload.utm ?: return
    
    val bundle = Bundle().apply {
        // Standard Firebase Campaign Params
        putString(Param.SOURCE, utm["utm_source"])
        putString(Param.MEDIUM, utm["utm_medium"])
        putString(Param.CAMPAIGN, utm["utm_campaign"])
        putString(Param.TERM, utm["utm_term"])
        putString(Param.CONTENT, utm["utm_content"])
        
        // Add the LinkMe ID for reference
        putString("link_id", payload.linkId)
    }

    // Log the standard CAMPAIGN_DETAILS event
    FirebaseAnalytics.getInstance(context).logEvent(Event.CAMPAIGN_DETAILS, bundle)
}

iOS (Swift)

import FirebaseAnalytics

func logToFirebase(payload: LinkPayload) {
    guard let utm = payload.utm else { return }

    var params: [String: Any] = [:]
    
    // Map UTM keys to Firebase constants
    if let source = utm["utm_source"] { params[AnalyticsParameterSource] = source }
    if let medium = utm["utm_medium"] { params[AnalyticsParameterMedium] = medium }
    if let campaign = utm["utm_campaign"] { params[AnalyticsParameterCampaign] = campaign }
    if let term = utm["utm_term"] { params[AnalyticsParameterTerm] = term }
    if let content = utm["utm_content"] { params[AnalyticsParameterContent] = content }
    
    if let linkId = payload.linkId { params["link_id"] = linkId }

    // Log the standard campaign_details event
    Analytics.logEvent(AnalyticsEventCampaignDetails, parameters: params)
}

PostHog

Official Documentation: Capture events

PostHog accepts standard UTM parameters directly. You can pass them as properties in a Deep Link Opened event or identify the user with them.

// JavaScript / React Native example
posthog.capture('Deep Link Opened', {
  $current_url: payload.path,
  utm_source: payload.utm?.utm_source,
  utm_medium: payload.utm?.utm_medium,
  utm_campaign: payload.utm?.utm_campaign,
  link_id: payload.linkId
});

Segment

Official Documentation: Track

Segment recommends passing campaign data in the context.campaign object.

analytics.track('Deep Link Opened', {
  linkId: payload.linkId,
  path: payload.path
}, {
  campaign: {
    name: payload.utm?.utm_campaign,
    source: payload.utm?.utm_source,
    medium: payload.utm?.utm_medium,
    term: payload.utm?.utm_term,
    content: payload.utm?.utm_content
  }
});

Amplitude

Official Documentation: User Properties

Amplitude recommends tracking UTM parameters as User Properties (for attribution) or Event Properties (for specific campaign interactions).

// Identify user with UTM properties (Attribution)
amplitude.identify(new amplitude.Identify()
  .set('utm_source', payload.utm?.utm_source)
  .set('utm_medium', payload.utm?.utm_medium)
  .set('utm_campaign', payload.utm?.utm_campaign)
);

// Track the open event
amplitude.track('Deep Link Opened', {
  link_id: payload.linkId,
  ...payload.utm // Spread all UTM params as event properties
});

Summary Checklist

  • [ ] Map Parameters: Ensure you map utm_source to source if your provider requires it (like Firebase).
  • [ ] Log on Install: Ensure getInitialLink triggers the log event so you capture ad-driven installs.
  • [ ] Log on Open: Ensure addListener triggers the log event for re-engagement campaigns.
  • [ ] Validate the link first: Confirm your AASA or assetlinks.json responses before debugging analytics payloads.

Need the managed side as well? See pricing for plan details, custom domain setup for branded links, and the Webhooks Guide if you want LinkMe to stream events directly to your backend.