# UTM Parameters for Mobile Apps: Complete Guide > Learn how to structure UTM parameters for deep links, preserve them through install, and read UTM data in Flutter and React Native apps. - Canonical: https://redirectly.app/blog/utm-parameters-mobile-apps - Site: [Redirectly](https://redirectly.app) — deferred deep linking for Flutter & React Native - Published: 2024-12-05 - Author: Dmytro Vyrych - Category: Marketing · 8 min read 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. ## Table of Contents 1. What are UTM Parameters? 2. UTM Structure & Parameters 3. UTMs in Mobile Deep Links 4. Preserving UTMs Through Install 5. Flutter Implementation 6. React Native Implementation 7. Best Practices ## 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). ## UTMs in Mobile Deep Links ### Mobile Deep Link Format Mobile deep links can include UTM parameters. The format depends on your deep linking scheme: ```text // Custom scheme myapp://product/123?utm_source=google&utm_medium=cpc&utm_campaign=summer // Universal/App Links https://myapp.com/product/123?utm_source=google&utm_medium=cpc&utm_campaign=summer // Deep link service (Redirectly) https://redirectly.app/link/abc123?utm_source=google&utm_medium=cpc&utm_campaign=summer ``` ### UTM Best Practices for Mobile - **Use lowercase:** Always use lowercase for parameter values for consistency - **Use underscores:** Use underscores instead of spaces (e.g., summer_sale not summer sale) - **Keep it short:** Shorter URLs are less prone to being truncated by platforms - **Use URL encoding:** Properly encode special characters (%20 for space, etc.) - **Consistent naming:** Use the same source/medium values across campaigns ## 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> extractUTMParameters(Uri uri) async { final params = {}; // 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 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 utms) { // Example: Send to Firebase Analytics or your analytics service // analytics.logEvent( // name: 'app_opened_via_utm', // parameters: utms, // ); } } class DeepLinkHandler { static Future 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 createState() => _MyAppState(); } class _MyAppState extends State { @override void initState() { super.initState(); _initializeRedirectly(); } Future _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. ## Related - [Mobile Install Attribution: Complete Guide](https://redirectly.app/blog/mobile-install-attribution-guide.md) - [Deferred Deep Linking Guide](https://redirectly.app/deferred-deep-linking.md) --- Full site index for AI agents: https://redirectly.app/llms.txt