Back to Blog
Guide
12 min read
December 5, 2024

UTM Parameters for Mobile Apps: Complete Guide

Learn how to effectively use UTM parameters in mobile apps for campaign tracking. Includes best practices, implementation examples in Flutter and React Native, and how to preserve UTMs through install.

What are UTM Parameters?

Definition

UTM parameters (Urchin Tracking Module) are URL parameters that you add to links to track the source, medium, and campaign that drove traffic to your app. They're a standard way to measure marketing effectiveness.

Why They Matter

  • • Track campaign performance
  • • Measure marketing ROI
  • • Identify top traffic sources
  • • Optimize budget allocation
  • • Monitor ad effectiveness
  • • Standard across analytics

Web vs Mobile

  • Web: UTMs in URL query string
  • Mobile: UTMs must be preserved in deep links
  • Challenge: Re-installs lose UTM data
  • Solution: Deferred deep linking services
  • Analytics: Same UTM structure applies

UTM Parameters Structure

5 Standard UTM Parameters

utm_source

The referrer: google, facebook, twitter, newsletter, etc.

Example: utm_source=google

utm_medium

The marketing medium: cpc, social, email, organic, etc.

Example: utm_medium=cpc

utm_campaign

The campaign name: summer_sale, q1_promotion, etc.

Example: utm_campaign=summer_sale

utm_content

Optional: differentiates similar content. Useful for A/B testing.

Example: utm_content=banner_v2

utm_term

Optional: keyword for paid search campaigns.

Example: utm_term=mobile+app

Example: Complete UTM URL

text
https://redirectly.app/product/123?utm_source=facebook&utm_medium=social&utm_campaign=summer_sale&utm_content=carousel_ad

This URL tells you: Traffic came from Facebook (source), via social media (medium), for the summer sale campaign (campaign), using a carousel ad (content).

Preserving UTMs Through Install

The Challenge

When a user clicks a deep link and installs your app for the first time, the URL parameters are lost during the install process. This is called "deferred linking" and requires special handling to preserve UTM data.

Solution: Deferred Deep Linking

Deferred deep linking services capture UTM data before app install and deliver it to your app after installation:

1

User clicks deep link with UTMs

https://redirectly.app/product/123?utm_source=facebook

2

Service captures UTM data and redirects to app store

UTMs stored on Redirectly servers

3

User installs app

App opens for first time

4

App retrieves stored UTM data

UTMs delivered to app and route user accordingly

Flutter Implementation

Reading UTM Parameters from Deep Links

dart
import 'package:flutter/material.dart';
import 'package:uni_links/uni_links.dart';
import 'dart:async';

class UTMTracker {
  static Future<Map<String, String>> extractUTMParameters(Uri uri) async {
    final params = <String, String>{};

    // Extract UTM parameters from query string
    final source = uri.queryParameters['utm_source'] ?? '';
    final medium = uri.queryParameters['utm_medium'] ?? '';
    final campaign = uri.queryParameters['utm_campaign'] ?? '';
    final content = uri.queryParameters['utm_content'] ?? '';
    final term = uri.queryParameters['utm_term'] ?? '';

    if (source.isNotEmpty) params['utm_source'] = source;
    if (medium.isNotEmpty) params['utm_medium'] = medium;
    if (campaign.isNotEmpty) params['utm_campaign'] = campaign;
    if (content.isNotEmpty) params['utm_content'] = content;
    if (term.isNotEmpty) params['utm_term'] = term;

    return params;
  }

  static Future<void> trackUTMs(Uri uri) async {
    final utms = await extractUTMParameters(uri);

    if (utms.isNotEmpty) {
      print('UTM Parameters: $utms');
      // Send to analytics
      _sendToAnalytics(utms);
    }
  }

  static void _sendToAnalytics(Map<String, String> utms) {
    // Example: Send to Firebase Analytics or your analytics service
    // analytics.logEvent(
    //   name: 'app_opened_via_utm',
    //   parameters: utms,
    // );
  }
}

class DeepLinkHandler {
  static Future<void> initialize() async {
    // Handle initial deep link (cold start)
    final String? initialLink = await getInitialLink();
    if (initialLink != null) {
      final uri = Uri.parse(initialLink);
      await UTMTracker.trackUTMs(uri);
    }

    // Listen for deep links when app is running
    linkStream.listen(
      (String link) async {
        final uri = Uri.parse(link);
        await UTMTracker.trackUTMs(uri);
      },
      onError: (err) {
        debugPrint('Deep link error: $err');
      },
    );
  }
}

Using Redirectly for UTM Preservation

Redirectly automatically preserves UTM parameters through install:

dart
import 'package:redirectly_flutter/redirectly_flutter.dart';

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    _initializeRedirectly();
  }

  Future<void> _initializeRedirectly() async {
    // Initialize Redirectly
    await Redirectly.init(apiKey: 'your-api-key');

    // Listen for deep links with UTM parameters
    Redirectly.onDeepLink((deepLink) {
      final path = deepLink.path;
      final campaign = deepLink.campaign;

      // deepLink.data contains all UTM parameters
      final utmSource = deepLink.data['utm_source'];
      final utmMedium = deepLink.data['utm_medium'];
      final utmCampaign = deepLink.data['utm_campaign'];

      print('Path: $path');
      print('Campaign: $campaign');
      print('UTM Source: $utmSource');
      print('UTM Medium: $utmMedium');
      print('UTM Campaign: $utmCampaign');

      // Route user and track analytics
      _handleDeepLink(deepLink);
    });
  }

  void _handleDeepLink(RedirectlyDeepLink deepLink) {
    // Route to correct screen based on path
    // Log attribution data for analytics
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'My App',
      home: const HomeScreen(),
    );
  }
}

React Native Implementation

Reading UTM Parameters with Redirectly

typescript
import { useEffect } from 'react';
import { useNavigation } from '@react-navigation/native';
import { Redirectly } from '@redirectly/react-native';

interface UTMData {
  utm_source?: string;
  utm_medium?: string;
  utm_campaign?: string;
  utm_content?: string;
  utm_term?: string;
}

export const useUTMTracking = () => {
  const navigation = useNavigation();

  useEffect(() => {
    // Handle initial deep link on app launch
    Redirectly.getInitialLink().then((deepLink) => {
      if (deepLink) {
        handleDeepLinkWithUTM(deepLink);
      }
    });

    // Listen for deep links when app is running
    const unsubscribe = Redirectly.onDeepLink((deepLink) => {
      handleDeepLinkWithUTM(deepLink);
    });

    return unsubscribe;
  }, []);

  const handleDeepLinkWithUTM = (deepLink: DeepLinkData) => {
    const { path, campaign, data } = deepLink;

    // Extract UTM parameters
    const utm: UTMData = {
      utm_source: data?.utm_source,
      utm_medium: data?.utm_medium,
      utm_campaign: data?.utm_campaign,
      utm_content: data?.utm_content,
      utm_term: data?.utm_term,
    };

    // Log UTM data for analytics
    console.log('Deep Link UTM Data:', utm);

    // Send to analytics service
    logToAnalytics(utm);

    // Route to correct screen
    if (path.startsWith('/product/')) {
      const productId = path.split('/')[2];
      navigation.navigate('ProductScreen', {
        productId,
        utm
      });
    } else if (path.startsWith('/promo/')) {
      navigation.navigate('PromoScreen', { utm });
    } else {
      navigation.navigate('Home', { utm });
    }
  };

  return null;
};

const logToAnalytics = (utm: UTMData) => {
  // Send to your analytics service
  // Example: Firebase Analytics, Amplitude, Mixpanel
  if (utm.utm_source || utm.utm_campaign) {
    console.log('Logging UTM attribution:', utm);
    // analytics.logEvent('deep_link_opened', utm);
  }
};

UTM Best Practices

1. Standardize Your Naming

Create a company-wide naming convention for UTM values. Use consistent source and medium names across all campaigns.

2. Use URL Builders

Use Google Analytics URL Builder or similar tools to generate UTM links. This reduces typos and ensures consistency.

3. Track in Analytics

Send UTM data to your analytics service on app open. This creates a complete view of user acquisition and engagement.

4. Use Deferred Deep Linking

Implement deferred deep linking to preserve UTM parameters through app installs. This ensures attribution works even for new users.

5. Monitor UTM Data Quality

Regularly review your UTM data for completeness and accuracy. Check for missing or inconsistent values that might indicate problems.

Start Tracking UTMs in Your Mobile App

Redirectly makes it easy to preserve and track UTM parameters through app install with deferred deep linking.

Related Articles