Analytics & Telemetry Implementation

Learn how to implement player analytics and telemetry to track game metrics and player behavior.

Analytics Overview

Analytics help you understand how players interact with your game, identify pain points, and make data-driven improvements.

📊 Player Behavior

Track how players progress through your game

🎯 Engagement Metrics

Measure session length, retention, and replay value

🐛 Error Tracking

Identify crashes and technical issues

💰 Monetization Data

Track in-game purchases and conversion rates

Setting Up Analytics

Step 1: Create Analytics Manager

Create a centralized system for tracking analytics:

1"keyword">using System.Collections.Generic;
2"keyword">using UnityEngine;
3"keyword">using System;
4
5"keyword">public "keyword">class AnalyticsManager : MonoBehaviour
6{
7 "keyword">public "keyword">static AnalyticsManager Instance;
8
9 [Header("Analytics Settings")]
10 "keyword">public "keyword">bool enableAnalytics = true;
11 "keyword">public "keyword">bool debugMode = false;
12 "keyword">public "keyword">string gameVersion;
13
14 [Header("Session Tracking")]
15 "keyword">private DateTime sessionStartTime;
16 "keyword">private "keyword">int sessionNumber;
17
18 "keyword">private Dictionary<"keyword">string, object> sessionData = "keyword">new Dictionary<"keyword">string, object>();
19 "keyword">private List<AnalyticsEvent> eventQueue = "keyword">new List<AnalyticsEvent>();
20
21 "keyword">void Awake()
22 {
23 "keyword">if (Instance == null)
24 {
25 Instance = "keyword">this;
26 DontDestroyOnLoad(gameObject);
27 InitializeAnalytics();
28 }
29 "keyword">else
30 {
31 Destroy(gameObject);
32 }
33 }
34
35 "keyword">void InitializeAnalytics()
36 {
37 "keyword">if (!enableAnalytics) "keyword">return;
38
39 gameVersion = Application.version;
40 sessionStartTime = DateTime.Now;
41 sessionNumber = PlayerPrefs.GetInt("SessionNumber", 0) + 1;
42 PlayerPrefs.SetInt("SessionNumber", sessionNumber);
43
44 "comment">// Track session start
45 TrackEvent("session_start", "keyword">new Dictionary<"keyword">string, object>
46 {
47 {"session_number", sessionNumber},
48 {"game_version", gameVersion},
49 {"platform", Application.platform.ToString()},
50 {"device_model", SystemInfo.deviceModel},
51 {"os_version", SystemInfo.operatingSystem}
52 });
53
54 "keyword">if (debugMode)
55 {
56 Debug.Log($"Analytics initialized - Session {sessionNumber}");
57 }
58 }
59
60 "keyword">public "keyword">void TrackEvent("keyword">string eventName, Dictionary<"keyword">string, object> parameters = null)
61 {
62 "keyword">if (!enableAnalytics) "keyword">return;
63
64 var analyticsEvent = "keyword">new AnalyticsEvent
65 {
66 eventName = eventName,
67 timestamp = DateTime.Now,
68 parameters = parameters ?? "keyword">new Dictionary<"keyword">string, object>(),
69 sessionId = sessionNumber.ToString()
70 };
71
72 eventQueue.Add(analyticsEvent);
73
74 "keyword">if (debugMode)
75 {
76 Debug.Log($"Analytics Event: {eventName} - {">string.Join(", ", analyticsEvent.parameters)}");
77 }
78
79 "comment">// Send event to analytics service
80 SendEvent(analyticsEvent);
81 }
82
83 "keyword">private "keyword">void SendEvent(AnalyticsEvent analyticsEvent)
84 {
85 "comment">// In a real implementation, you would send "keyword">this to your analytics service
86 "comment">// Examples: Unity Analytics, Google Analytics, Firebase, custom backend
87
88 #"keyword">if UNITY_ANALYTICS
89 UnityEngine.Analytics.Analytics.CustomEvent(analyticsEvent.eventName, analyticsEvent.parameters);
90 #endif
91
92 "comment">// Custom backend example
93 StartCoroutine(SendToCustomBackend(analyticsEvent));
94 }
95
96 "keyword">void OnApplicationPause("keyword">bool pauseStatus)
97 {
98 "keyword">if (pauseStatus)
99 {
100 TrackSessionEnd();
101 }
102 "keyword">else
103 {
104 TrackSessionResume();
105 }
106 }
107
108 "keyword">void OnApplicationFocus("keyword">bool hasFocus)
109 {
110 "keyword">if (!hasFocus)
111 {
112 TrackSessionEnd();
113 }
114 }
115
116 "keyword">private "keyword">void TrackSessionEnd()
117 {
118 var sessionDuration = (DateTime.Now - sessionStartTime).TotalSeconds;
119
120 TrackEvent("session_end", "keyword">new Dictionary<"keyword">string, object>
121 {
122 {"session_duration", sessionDuration},
123 {"events_tracked", eventQueue.Count}
124 });
125 }
126
127 "keyword">private "keyword">void TrackSessionResume()
128 {
129 sessionStartTime = DateTime.Now;
130 TrackEvent("session_resume");
131 }
132}
133
134[System.Serializable]
135"keyword">public "keyword">class AnalyticsEvent
136{
137 "keyword">public "keyword">string eventName;
138 "keyword">public DateTime timestamp;
139 "keyword">public Dictionary<"keyword">string, object> parameters;
140 "keyword">public "keyword">string sessionId;
141}

Step 2: Unity Analytics Integration

Integrate with Unity's built-in analytics:

1#"keyword">if UNITY_ANALYTICS
2"keyword">using UnityEngine.Analytics;
3#endif
4
5"keyword">public "keyword">class UnityAnalyticsIntegration : MonoBehaviour
6{
7 "keyword">void Start()
8 {
9 #"keyword">if UNITY_ANALYTICS
10 "comment">// Enable Unity Analytics
11 Analytics.enabled = true;
12
13 "comment">// Set user properties
14 Analytics.SetUserGender(Gender.Unknown);
15 Analytics.SetUserBirthYear(1990);
16
17 "comment">// Track initial game launch
18 Analytics.CustomEvent("game_launch", "keyword">new Dictionary<"keyword">string, object>
19 {
20 {"first_launch", !PlayerPrefs.HasKey("HasLaunchedBefore")},
21 {"total_launches", PlayerPrefs.GetInt("LaunchCount", 0) + 1}
22 });
23
24 PlayerPrefs.SetInt("HasLaunchedBefore", 1);
25 PlayerPrefs.SetInt("LaunchCount", PlayerPrefs.GetInt("LaunchCount", 0) + 1);
26 #endif
27 }
28}

Player Metrics Tracking

RPG-Specific Metrics

Track metrics specific to RPG gameplay:

1"keyword">public "keyword">class RPGAnalytics : MonoBehaviour
2{
3 "keyword">void Start()
4 {
5 "comment">// Subscribe to game events
6 GameManager.Instance.OnGameStateChanged += TrackGameStateChange;
7
8 "keyword">if (QuestManager.Instance != null)
9 {
10 QuestManager.Instance.OnQuestStarted += TrackQuestStart;
11 QuestManager.Instance.OnQuestCompleted += TrackQuestComplete;
12 }
13
14 var playerStats = GameManager.Instance.playerStats;
15 "keyword">if (playerStats != null)
16 {
17 playerStats.OnLevelUp += TrackLevelUp;
18 playerStats.OnPlayerDeath += TrackPlayerDeath;
19 }
20 }
21
22 "keyword">void TrackGameStateChange(GameState previousState, GameState newState)
23 {
24 AnalyticsManager.Instance.TrackEvent("game_state_change", "keyword">new Dictionary<"keyword">string, object>
25 {
26 {"previous_state", previousState.ToString()},
27 {"new_state", newState.ToString()},
28 {"player_level", GameManager.Instance.playerStats.level}
29 });
30 }
31
32 "keyword">void TrackQuestStart(Quest quest)
33 {
34 AnalyticsManager.Instance.TrackEvent("quest_started", "keyword">new Dictionary<"keyword">string, object>
35 {
36 {"quest_id", quest.questId},
37 {"quest_name", quest.questName},
38 {"quest_type", quest.questType.ToString()},
39 {"player_level", GameManager.Instance.playerStats.level},
40 {"player_location", UnityEngine.SceneManagement.SceneManager.GetActiveScene().name}
41 });
42 }
43
44 "keyword">void TrackQuestComplete(Quest quest, "keyword">bool success)
45 {
46 var completionTime = quest.GetCompletionTime();
47
48 AnalyticsManager.Instance.TrackEvent("quest_completed", "keyword">new Dictionary<"keyword">string, object>
49 {
50 {"quest_id", quest.questId},
51 {"quest_name", quest.questName},
52 {"success", success},
53 {"completion_time_seconds", completionTime},
54 {"player_level", GameManager.Instance.playerStats.level},
55 {"attempts", quest.attemptCount}
56 });
57 }
58
59 "keyword">void TrackLevelUp("keyword">int newLevel, "keyword">int previousLevel)
60 {
61 var playTime = Time.realtimeSinceStartup;
62
63 AnalyticsManager.Instance.TrackEvent("player_level_up", "keyword">new Dictionary<"keyword">string, object>
64 {
65 {"new_level", newLevel},
66 {"previous_level", previousLevel},
67 {"time_to_level_seconds", playTime},
68 {"experience_gained", GameManager.Instance.playerStats.experience},
69 {"location", UnityEngine.SceneManagement.SceneManager.GetActiveScene().name}
70 });
71 }
72
73 "keyword">void TrackPlayerDeath("keyword">string causeOfDeath)
74 {
75 AnalyticsManager.Instance.TrackEvent("player_death", "keyword">new Dictionary<"keyword">string, object>
76 {
77 {"cause_of_death", causeOfDeath},
78 {"player_level", GameManager.Instance.playerStats.level},
79 {"location", UnityEngine.SceneManagement.SceneManager.GetActiveScene().name},
80 {"health_at_death", GameManager.Instance.playerStats.health.Value},
81 {"enemies_nearby", FindObjectsOfType<Enemy>().Length}
82 });
83 }
84
85 "comment">// Track item usage
86 "keyword">public "keyword">void TrackItemUsed(Item item, "keyword">string context)
87 {
88 AnalyticsManager.Instance.TrackEvent("item_used", "keyword">new Dictionary<"keyword">string, object>
89 {
90 {"item_id", item.name},
91 {"item_name", item.itemName},
92 {"item_type", item.type.ToString()},
93 {"context", context}, "comment">// "combat", "exploration", "menu", etc.
94 {"player_level", GameManager.Instance.playerStats.level},
95 {"inventory_slots_used", GetInventoryUsage()}
96 });
97 }
98
99 "comment">// Track combat encounters
100 "keyword">public "keyword">void TrackCombatStart(List<Enemy> enemies)
101 {
102 AnalyticsManager.Instance.TrackEvent("combat_started", "keyword">new Dictionary<"keyword">string, object>
103 {
104 {"enemy_count", enemies.Count},
105 {"enemy_types", "keyword">string.Join(",", enemies.Select(e => e.enemyData.enemyName))},
106 {"player_level", GameManager.Instance.playerStats.level},
107 {"player_health_percentage", GetHealthPercentage()},
108 {"location", UnityEngine.SceneManagement.SceneManager.GetActiveScene().name}
109 });
110 }
111
112 "keyword">public "keyword">void TrackCombatEnd("keyword">bool playerWon, "keyword">float combatDuration)
113 {
114 AnalyticsManager.Instance.TrackEvent("combat_ended", "keyword">new Dictionary<"keyword">string, object>
115 {
116 {"player_won", playerWon},
117 {"combat_duration_seconds", combatDuration},
118 {"player_health_remaining", GetHealthPercentage()},
119 {"experience_gained", 0}, "comment">// You would calculate "keyword">this
120 {"turns_taken", 0} "comment">// Track from combat system
121 });
122 }
123
124 "keyword">private "keyword">float GetHealthPercentage()
125 {
126 var stats = GameManager.Instance.playerStats;
127 "keyword">return ("keyword">float)stats.health.Value / stats.maxHealth.Value;
128 }
129
130 "keyword">private "keyword">int GetInventoryUsage()
131 {
132 var inventory = FindObjectOfType<PlayerInventory>();
133 "keyword">return inventory?.GetUsedSlots() ?? 0;
134 }
135}

Custom Events

Economic Tracking

Track in-game economy and player spending:

1"keyword">public "keyword">class EconomyAnalytics : MonoBehaviour
2{
3 "keyword">public "keyword">void TrackPurchase(Item item, "keyword">int quantity, "keyword">int totalCost, "keyword">string vendor)
4 {
5 AnalyticsManager.Instance.TrackEvent("item_purchased", "keyword">new Dictionary<"keyword">string, object>
6 {
7 {"item_id", item.name},
8 {"item_name", item.itemName},
9 {"quantity", quantity},
10 {"total_cost", totalCost},
11 {"unit_cost", totalCost / quantity},
12 {"vendor", vendor},
13 {"player_gold_before", GetPlayerGold()},
14 {"player_level", GameManager.Instance.playerStats.level}
15 });
16 }
17
18 "keyword">public "keyword">void TrackSale(Item item, "keyword">int quantity, "keyword">int totalValue)
19 {
20 AnalyticsManager.Instance.TrackEvent("item_sold", "keyword">new Dictionary<"keyword">string, object>
21 {
22 {"item_id", item.name},
23 {"quantity", quantity},
24 {"total_value", totalValue},
25 {"player_gold_after", GetPlayerGold() + totalValue}
26 });
27 }
28
29 "keyword">public "keyword">void TrackGoldFound("keyword">int amount, "keyword">string source)
30 {
31 AnalyticsManager.Instance.TrackEvent("gold_acquired", "keyword">new Dictionary<"keyword">string, object>
32 {
33 {"amount", amount},
34 {"source", source}, "comment">// "quest_reward", "enemy_drop", "treasure_chest", etc.
35 {"player_total_gold", GetPlayerGold() + amount},
36 {"location", UnityEngine.SceneManagement.SceneManager.GetActiveScene().name}
37 });
38 }
39
40 "keyword">private "keyword">int GetPlayerGold()
41 {
42 var inventory = FindObjectOfType<PlayerInventory>();
43 "keyword">return inventory?.GetGoldAmount() ?? 0;
44 }
45}
46
47"comment">// Progression Analytics
48"keyword">public "keyword">class ProgressionAnalytics : MonoBehaviour
49{
50 "keyword">public "keyword">void TrackSkillUpgrade("keyword">string skillName, "keyword">int newLevel, "keyword">int cost)
51 {
52 AnalyticsManager.Instance.TrackEvent("skill_upgraded", "keyword">new Dictionary<"keyword">string, object>
53 {
54 {"skill_name", skillName},
55 {"new_level", newLevel},
56 {"upgrade_cost", cost},
57 {"player_level", GameManager.Instance.playerStats.level}
58 });
59 }
60
61 "keyword">public "keyword">void TrackAreaDiscovered("keyword">string areaName, "keyword">int playerLevel)
62 {
63 AnalyticsManager.Instance.TrackEvent("area_discovered", "keyword">new Dictionary<"keyword">string, object>
64 {
65 {"area_name", areaName},
66 {"discovery_level", playerLevel},
67 {"play_time_hours", Time.realtimeSinceStartup / 3600f}
68 });
69 }
70
71 "keyword">public "keyword">void TrackAchievementUnlocked("keyword">string achievementId, "keyword">string achievementName)
72 {
73 AnalyticsManager.Instance.TrackEvent("achievement_unlocked", "keyword">new Dictionary<"keyword">string, object>
74 {
75 {"achievement_id", achievementId},
76 {"achievement_name", achievementName},
77 {"unlock_time_hours", Time.realtimeSinceStartup / 3600f},
78 {"player_level", GameManager.Instance.playerStats.level}
79 });
80 }
81}

Data Analysis & Visualization

Analytics Dashboard

Create an in-editor analytics dashboard:

1#"keyword">if UNITY_EDITOR
2"keyword">using UnityEditor;
3
4"keyword">public "keyword">class AnalyticsDashboard : EditorWindow
5{
6 "keyword">private Vector2 scrollPosition;
7 "keyword">private Dictionary<"keyword">string, "keyword">int> eventCounts = "keyword">new Dictionary<"keyword">string, "keyword">int>();
8
9 [MenuItem("RPG Tools/Analytics Dashboard")]
10 "keyword">public "keyword">static "keyword">void ShowWindow()
11 {
12 GetWindow<AnalyticsDashboard>("Analytics Dashboard");
13 }
14
15 "keyword">void OnGUI()
16 {
17 GUILayout.Label("RPG Analytics Dashboard", EditorStyles.boldLabel);
18
19 EditorGUILayout.Space();
20
21 "keyword">if (GUILayout.Button("Refresh Data"))
22 {
23 RefreshAnalyticsData();
24 }
25
26 EditorGUILayout.Space();
27
28 scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
29
30 "comment">// Display event counts
31 EditorGUILayout.LabelField("Event Summary", EditorStyles.boldLabel);
32 "keyword">foreach (var kvp in eventCounts)
33 {
34 EditorGUILayout.BeginHorizontal();
35 EditorGUILayout.LabelField(kvp.Key, GUILayout.Width(200));
36 EditorGUILayout.LabelField(kvp.Value.ToString(), GUILayout.Width(100));
37 EditorGUILayout.EndHorizontal();
38 }
39
40 EditorGUILayout.EndScrollView();
41
42 EditorGUILayout.Space();
43
44 "keyword">if (GUILayout.Button("Export Analytics Data"))
45 {
46 ExportAnalyticsData();
47 }
48 }
49
50 "keyword">void RefreshAnalyticsData()
51 {
52 "comment">// In a real implementation, you would load data from your analytics service
53 "comment">// or local storage
54 eventCounts.Clear();
55
56 "comment">// Example data loading
57 var events = LoadAnalyticsEvents();
58 "keyword">foreach (var analyticsEvent in events)
59 {
60 "keyword">if (eventCounts.ContainsKey(analyticsEvent.eventName))
61 {
62 eventCounts[analyticsEvent.eventName]++;
63 }
64 "keyword">else
65 {
66 eventCounts[analyticsEvent.eventName] = 1;
67 }
68 }
69 }
70
71 "keyword">void ExportAnalyticsData()
72 {
73 "keyword">string path = EditorUtility.SaveFilePanel("Export Analytics", "", "analytics_data", "csv");
74 "keyword">if (!"keyword">string.IsNullOrEmpty(path))
75 {
76 var csv = "keyword">new System.Text.StringBuilder();
77 csv.AppendLine("Event Name,Count");
78
79 "keyword">foreach (var kvp in eventCounts)
80 {
81 csv.AppendLine($"{kvp.Key},{kvp.Value}");
82 }
83
84 System.IO.File.WriteAllText(path, csv.ToString());
85 EditorUtility.DisplayDialog("Export Complete", "Analytics data exported successfully!", "OK");
86 }
87 }
88
89 "keyword">private List<AnalyticsEvent> LoadAnalyticsEvents()
90 {
91 "comment">// Placeholder - load from your data source
92 "keyword">return "keyword">new List<AnalyticsEvent>();
93 }
94}
95#endif

Privacy Compliance

GDPR & Privacy Considerations

Implement privacy-compliant analytics:

1"keyword">public "keyword">class PrivacyManager : MonoBehaviour
2{
3 "keyword">public "keyword">static PrivacyManager Instance;
4
5 [Header("Privacy Settings")]
6 "keyword">public "keyword">bool requireConsent = true;
7 "keyword">public "keyword">bool allowDataCollection = false;
8
9 "keyword">void Awake()
10 {
11 "keyword">if (Instance == null)
12 {
13 Instance = "keyword">this;
14 DontDestroyOnLoad(gameObject);
15
16 "comment">// Load consent status
17 allowDataCollection = PlayerPrefs.GetInt("AnalyticsConsent", 0) == 1;
18
19 "keyword">if (requireConsent && !HasConsentBeenAsked())
20 {
21 ShowConsentDialog();
22 }
23 }
24 "keyword">else
25 {
26 Destroy(gameObject);
27 }
28 }
29
30 "keyword">bool HasConsentBeenAsked()
31 {
32 "keyword">return PlayerPrefs.HasKey("ConsentAsked");
33 }
34
35 "keyword">void ShowConsentDialog()
36 {
37 "comment">// Show privacy consent UI
38 var consentUI = FindObjectOfType<ConsentUI>();
39 "keyword">if (consentUI != null)
40 {
41 consentUI.ShowConsentDialog(OnConsentResponse);
42 }
43 }
44
45 "keyword">void OnConsentResponse("keyword">bool consented)
46 {
47 allowDataCollection = consented;
48 PlayerPrefs.SetInt("AnalyticsConsent", consented ? 1 : 0);
49 PlayerPrefs.SetInt("ConsentAsked", 1);
50
51 "comment">// Update analytics manager
52 "keyword">if (AnalyticsManager.Instance != null)
53 {
54 AnalyticsManager.Instance.enableAnalytics = consented;
55 }
56
57 "keyword">if (consented)
58 {
59 Debug.Log("User consented to data collection");
60 }
61 "keyword">else
62 {
63 Debug.Log("User declined data collection");
64 }
65 }
66
67 "keyword">public "keyword">bool CanCollectData()
68 {
69 "keyword">return allowDataCollection;
70 }
71
72 "keyword">public "keyword">void RevokeConsent()
73 {
74 allowDataCollection = false;
75 PlayerPrefs.SetInt("AnalyticsConsent", 0);
76
77 "comment">// Clear existing data
78 ClearAnalyticsData();
79
80 "keyword">if (AnalyticsManager.Instance != null)
81 {
82 AnalyticsManager.Instance.enableAnalytics = false;
83 }
84 }
85
86 "keyword">void ClearAnalyticsData()
87 {
88 "comment">// Clear local analytics data
89 PlayerPrefs.DeleteKey("SessionNumber");
90
91 "comment">// Request data deletion from analytics services
92 #"keyword">if UNITY_ANALYTICS
93 "comment">// Unity Analytics data deletion would be handled through Unity Dashboard
94 #endif
95 }
96}
97
98"keyword">public "keyword">class ConsentUI : MonoBehaviour
99{
100 [Header("UI References")]
101 "keyword">public GameObject consentPanel;
102 "keyword">public Text consentText;
103 "keyword">public Button acceptButton;
104 "keyword">public Button declineButton;
105
106 "keyword">private System.Action<"keyword">bool> onConsentCallback;
107
108 "keyword">void Start()
109 {
110 acceptButton.onClick.AddListener(() => RespondToConsent(true));
111 declineButton.onClick.AddListener(() => RespondToConsent(false));
112 }
113
114 "keyword">public "keyword">void ShowConsentDialog(System.Action<"keyword">bool> callback)
115 {
116 onConsentCallback = callback;
117 consentPanel.SetActive(true);
118
119 consentText.text = "This game collects anonymous gameplay data to improve your experience. " +
120 "No personal information is collected. You can change ">this setting at any time.";
121 }
122
123 "keyword">void RespondToConsent("keyword">bool consented)
124 {
125 consentPanel.SetActive(false);
126 onConsentCallback?.Invoke(consented);
127 }
128}

Analytics Best Practices

📊 Meaningful Metrics

Track metrics that directly relate to player experience and business goals

🔒 Privacy First

Always respect player privacy and comply with data protection regulations

⚡ Performance Impact

Ensure analytics don't negatively impact game performance

🎯 Actionable Data

Focus on collecting data that you can act upon to improve your game

Continue Learning

Explore related tutorials to expand your knowledge