- Add stunning cyberpunk cover page with animated grid background - Integrate Mermaid diagrams for visual architecture and flow charts - Add flexible-alerts for tips, warnings, and notes throughout tutorials - Enhance index.html with 15+ professional plugins (tabs, progress bar, charts) - Add sequence diagrams for authentication and analytics flows - Improve readability with visual callouts and interactive elements - Add graph visualizations for system architecture - Better UX with keyboard shortcuts, word count, and edit links
20 KiB
Analytics Tutorial
Learn how to track player behavior, measure engagement, and make data-driven decisions with AeThex Analytics.
Tip
Analytics is your window into player behavior. Use it to understand what players love, what confuses them, and where they get stuck.
What You'll Build
A complete analytics system that tracks:
- Player events (level complete, item collected, etc.)
- User properties (level, skill, preferences)
- Custom funnels (onboarding, purchases, retention)
- Crash reports and errors
- Performance metrics
Time: 25 minutes
Difficulty: Beginner
Prerequisites: Basic GDScript knowledge
graph LR
Game[🎮 Game Events] -->|Track| SDK[AeThex SDK]
SDK -->|Batch| Cloud[☁️ Cloud]
Cloud -->|Process| Pipeline[Data Pipeline]
Pipeline -->|Store| DB[(Database)]
DB -->|Query| Dashboard[📊 Dashboard]
Dashboard -->|Insights| You[👤 You]
Events[Events<br/>• level_complete<br/>• item_collected<br/>• player_died]
Properties[User Props<br/>• level<br/>• skill<br/>• device]
style Game fill:#00ffff22,stroke:#00ffff
style Cloud fill:#ff00ff22,stroke:#ff00ff
style Dashboard fill:#00ffff22,stroke:#00ffff
Why Use Analytics?
Analytics helps you:
- Understand players - See what they do in your game
- Improve retention - Find where players drop off
- Optimize monetization - Track purchase funnels
- Fix bugs faster - Get crash reports automatically
- Make data-driven decisions - Know what features to build
Note
AeThex Analytics automatically batches events to minimize network usage and battery drain. No need to worry about performance impact.
Step 1: Connect to Analytics
First, connect to AeThex Cloud and initialize analytics:
Warning
Don't track personally identifiable information (PII) like email addresses or real names in analytics events. Use anonymous user IDs instead.
# main.gd
extends Node
func _ready():
# Connect to cloud
var result = await AeThexCloud.connect_to_cloud()
if result.success:
print("Connected to AeThex Cloud")
initialize_analytics()
else:
print("Failed to connect: ", result.error)
func initialize_analytics():
# Analytics initialization is automatic
# Track app start
AeThexAnalytics.track_event("app_started", {
"platform": OS.get_name(),
"version": ProjectSettings.get_setting("application/config/version")
})
Step 2: Track Basic Events
Track important game events:
#player.gd
extends CharacterBody2D
var level = 1
var score = 0
func level_complete():
# Track level completion
AeThexAnalytics.track_event("level_complete", {
"level": level,
"score": score,
"time_spent": get_level_time(),
"deaths": death_count
})
level += 1
func collect_item(item_name: String):
# Track item collection
AeThexAnalytics.track_event("item_collected", {
"item_name": item_name,
"level": level,
"timestamp": Time.get_unix_time_from_system()
})
func player_died():
# Track deaths
AeThexAnalytics.track_event("player_died", {
"level": level,
"cause": death_cause,
"position": global_position
})
Step 3: Set User Properties
Store persistent information about users:
# analytics_manager.gd (autoload)
extends Node
func _ready():
# Set up user properties when game starts
setup_user_properties()
func setup_user_properties():
# Basic user info
AeThexAnalytics.set_user_property("platform", OS.get_name())
AeThexAnalytics.set_user_property("game_version", ProjectSettings.get_setting("application/config/version"))
# Load from save file
var save_data = load_save()
if save_data:
AeThexAnalytics.set_user_property("player_level", save_data.level)
AeThexAnalytics.set_user_property("total_playtime", save_data.playtime)
AeThexAnalytics.set_user_property("achievements_unlocked", save_data.achievements.size())
func on_player_level_up(new_level: int):
# Update user property when it changes
AeThexAnalytics.set_user_property("player_level", new_level)
func on_achievement_unlocked(achievement_id: String):
# Increment property
AeThexAnalytics.increment_user_property("achievements_unlocked", 1)
# Track event
AeThexAnalytics.track_event("achievement_unlocked", {
"achievement_id": achievement_id
})
Step 4: Track Screen Views
Monitor which screens players visit:
# base_screen.gd (inherit from this for all screens)
extends Control
var screen_name: String = "Unknown"
var screen_enter_time: float = 0
func _ready():
screen_enter_time = Time.get_ticks_msec() / 1000.0
track_screen_view()
func _exit_tree():
track_screen_duration()
func track_screen_view():
AeThexAnalytics.track_event("screen_view", {
"screen_name": screen_name,
"timestamp": Time.get_unix_time_from_system()
})
func track_screen_duration():
var duration = (Time.get_ticks_msec() / 1000.0) - screen_enter_time
AeThexAnalytics.track_event("screen_duration", {
"screen_name": screen_name,
"duration_seconds": duration
})
Example usage:
# main_menu.gd
extends "res://scripts/base_screen.gd"
func _ready():
screen_name = "main_menu"
super._ready()
Step 5: Track Economy Events
Monitor in-game economy:
# economy_tracker.gd
extends Node
func currency_earned(currency_name: String, amount: int, source: String):
AeThexAnalytics.track_event("currency_earned", {
"currency": currency_name,
"amount": amount,
"source": source, # "quest", "shop", "reward", etc.
"total_balance": get_currency_balance(currency_name)
})
func currency_spent(currency_name: String, amount: int, item: String):
AeThexAnalytics.track_event("currency_spent", {
"currency": currency_name,
"amount": amount,
"item": item,
"remaining_balance": get_currency_balance(currency_name)
})
func item_purchased(item_id: String, price: int, currency: String):
AeThexAnalytics.track_event("item_purchased", {
"item_id": item_id,
"price": price,
"currency": currency,
"source": "shop" # or "chest", "reward", etc.
})
func real_money_purchase(product_id: String, price: float, currency: String):
AeThexAnalytics.track_event("iap_purchase", {
"product_id": product_id,
"price": price,
"currency": currency,
"revenue": price # Important for revenue tracking
})
Step 6: Create Funnels
Track conversion funnels to understand player flow:
# funnel_tracker.gd
extends Node
# Onboarding funnel
func track_onboarding_funnel(step: String):
var funnel_steps = [
"tutorial_start",
"tutorial_complete",
"first_level_start",
"first_level_complete",
"account_created"
]
AeThexAnalytics.track_event("onboarding_funnel", {
"step": step,
"step_number": funnel_steps.find(step) + 1,
"total_steps": funnel_steps.size()
})
# Purchase funnel
func track_purchase_funnel(step: String, product_id: String = ""):
AeThexAnalytics.track_event("purchase_funnel", {
"step": step, # "view_shop", "select_item", "confirm", "complete"
"product_id": product_id
})
# Level progression funnel
func track_level_funnel(step: String, level: int):
AeThexAnalytics.track_event("level_funnel", {
"step": step, # "start", "complete", "fail", "abandon"
"level": level
})
Example usage:
# tutorial.gd
func _ready():
FunnelTracker.track_onboarding_funnel("tutorial_start")
func on_tutorial_complete():
FunnelTracker.track_onboarding_funnel("tutorial_complete")
# shop.gd
func _on_item_clicked(product_id):
FunnelTracker.track_purchase_funnel("select_item", product_id)
func _on_purchase_confirmed(product_id):
FunnelTracker.track_purchase_funnel("confirm", product_id)
Step 7: Track Engagement Metrics
Measure player engagement:
# engagement_tracker.gd (autoload)
extends Node
var session_start_time: float = 0
var total_sessions: int = 0
var events_this_session: int = 0
func _ready():
start_session()
func start_session():
session_start_time = Time.get_ticks_msec() / 1000.0
total_sessions = load_total_sessions() + 1
save_total_sessions(total_sessions)
AeThexAnalytics.track_event("session_start", {
"session_number": total_sessions,
"days_since_install": get_days_since_install()
})
# Set user property
AeThexAnalytics.set_user_property("total_sessions", total_sessions)
func end_session():
var session_duration = (Time.get_ticks_msec() / 1000.0) - session_start_time
AeThexAnalytics.track_event("session_end", {
"duration_seconds": session_duration,
"events_tracked": events_this_session
})
func _notification(what):
if what == NOTIFICATION_WM_CLOSE_REQUEST:
end_session()
func track_engagement_event():
events_this_session += 1
func get_days_since_install() -> int:
var install_date = load_install_date()
if install_date == 0:
install_date = Time.get_unix_time_from_system()
save_install_date(install_date)
return 0
var current_time = Time.get_unix_time_from_system()
var days = (current_time - install_date) / 86400.0 # seconds in a day
return int(days)
Step 8: Track Errors and Crashes
Automatically report errors:
# error_tracker.gd (autoload)
extends Node
func _ready():
# Catch unhandled errors
Engine.get_singleton("ScriptServer").add_global_constant("ErrorTracker", self)
func track_error(error_message: String, stack_trace: String = ""):
AeThexAnalytics.track_event("error_occurred", {
"error_message": error_message,
"stack_trace": stack_trace,
"platform": OS.get_name(),
"version": ProjectSettings.get_setting("application/config/version")
})
func track_crash(crash_reason: String):
AeThexAnalytics.track_event("game_crash", {
"reason": crash_reason,
"platform": OS.get_name(),
"memory_used": Performance.get_monitor(Performance.MEMORY_STATIC),
"fps": Engine.get_frames_per_second()
})
# Catch GDScript errors
func _on_error(error_message: String):
track_error(error_message, get_stack())
# Helper to get stack trace
func get_stack() -> String:
var stack = get_stack_trace()
var result = ""
for frame in stack:
result += "%s:%d in %s()\n" % [frame.source, frame.line, frame.function]
return result
func get_stack_trace() -> Array:
return [] # Implemented in debug builds
Step 9: Performance Tracking
Track game performance metrics:
# performance_tracker.gd (autoload)
extends Node
const SAMPLE_INTERVAL = 5.0 # seconds
var sample_timer: Timer
func _ready():
sample_timer = Timer.new()
sample_timer.timeout.connect(_sample_performance)
sample_timer.wait_time = SAMPLE_INTERVAL
add_child(sample_timer)
sample_timer.start()
func _sample_performance():
var fps = Engine.get_frames_per_second()
var memory_mb = Performance.get_monitor(Performance.MEMORY_STATIC) / 1024.0 / 1024.0
var draw_calls = Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME)
# Track performance event
AeThexAnalytics.track_event("performance_sample", {
"fps": fps,
"memory_mb": memory_mb,
"draw_calls": draw_calls,
"scene": get_tree().current_scene.name if get_tree().current_scene else "unknown"
})
# Alert on low performance
if fps < 30:
track_low_performance(fps, memory_mb)
func track_low_performance(fps: int, memory_mb: float):
AeThexAnalytics.track_event("low_performance", {
"fps": fps,
"memory_mb": memory_mb,
"platform": OS.get_name(),
"scene": get_tree().current_scene.name if get_tree().current_scene else "unknown"
})
Step 10: A/B Testing
Implement A/B tests to compare features:
# ab_testing.gd (autoload)
extends Node
var user_variant: String = ""
func _ready():
assign_variant()
func assign_variant():
# Check if user already has a variant assigned
user_variant = load_user_variant()
if user_variant.is_empty():
# Randomly assign variant (50/50 split)
user_variant = "A" if randf() < 0.5 else "B"
save_user_variant(user_variant)
# Set as user property
AeThexAnalytics.set_user_property("ab_test_variant", user_variant)
# Track assignment
AeThexAnalytics.track_event("ab_test_assigned", {
"variant": user_variant
})
func get_variant() -> String:
return user_variant
func is_variant_a() -> bool:
return user_variant == "A"
func is_variant_b() -> bool:
return user_variant == "B"
func track_conversion(goal: String):
AeThexAnalytics.track_event("ab_test_conversion", {
"variant": user_variant,
"goal": goal
})
Example usage:
# Configure feature based on variant
func _ready():
if ABTesting.is_variant_a():
# Show red button
$Button.modulate = Color.RED
else:
# Show blue button
$Button.modulate = Color.BLUE
func _on_button_pressed():
# Track which variant converted
ABTesting.track_conversion("button_clicked")
Analytics Dashboard
View your analytics data:
- Go to: https://studio.aethex.io/analytics
- Select your project
- View dashboards:
- Overview: DAU, MAU, retention
- Events: All tracked events
- Funnels: Conversion funnels
- User Properties: Audience segments
- Errors: Crash reports
- Performance: FPS, memory, load times
Best Practices
1. Name Events Consistently
# ✓ DO - Use snake_case
AeThexAnalytics.track_event("level_complete", {})
AeThexAnalytics.track_event("item_collected", {})
# ❌ DON'T - Inconsistent naming
AeThexAnalytics.track_event("LevelComplete", {})
AeThexAnalytics.track_event("item-collected", {})
2. Include Context in Events
# ✓ DO - Rich context
AeThexAnalytics.track_event("button_clicked", {
"button_name": "play",
"screen": "main_menu",
"session_time": get_session_time()
})
# ❌ DON'T - No context
AeThexAnalytics.track_event("button_clicked", {})
3. Track the User Journey
# Track entire player flow
AeThexAnalytics.track_event("game_started", {})
AeThexAnalytics.track_event("tutorial_started", {})
AeThexAnalytics.track_event("tutorial_completed", {})
AeThexAnalytics.track_event("first_level_started", {})
AeThexAnalytics.track_event("first_level_completed", {})
4. Avoid PII (Personally Identifiable Information)
# ❌ DON'T - Include PII
AeThexAnalytics.track_event("user_info", {
"email": "user@example.com", # Never track emails
"name": "John Doe", # Never track real names
"ip_address": "192.168.1.1" # Never track IPs
})
# ✓ DO - Use anonymous identifiers
AeThexAnalytics.track_event("user_info", {
"user_id": "anon_123456",
"player_level": 5
})
5. Batch Events if Needed
# For high-frequency events, batch them
var event_batch = []
func track_player_movement():
event_batch.append({
"event": "player_moved",
"position": player.position
})
if event_batch.size() >= 10:
flush_events()
func flush_events():
for event in event_batch:
AeThexAnalytics.track_event(event.event, event)
event_batch.clear()
Common Metrics to Track
Engagement Metrics:
- Daily Active Users (DAU)
- Monthly Active Users (MAU)
- Session length
- Sessions per user
- Day 1/7/30 retention
Monetization Metrics:
- Average Revenue Per User (ARPU)
- Paying User Rate
- Lifetime Value (LTV)
- Conversion rate
Game Metrics:
- Level completion rate
- Tutorial completion rate
- Time to first action
- Churn points
- Player progression
Example: Complete Analytics Setup
# analytics_complete.gd (autoload)
extends Node
signal analytics_ready
var is_initialized = false
func _ready():
initialize()
func initialize():
# Wait for cloud connection
await get_tree().create_timer(1.0).timeout
if not AeThexCloud.is_connected():
await AeThexCloud.connect_to_cloud()
# Set up user properties
setup_user_properties()
# Start session tracking
start_session()
# Connect to game signals
connect_game_signals()
is_initialized = true
analytics_ready.emit()
func setup_user_properties():
AeThexAnalytics.set_user_property("platform", OS.get_name())
AeThexAnalytics.set_user_property("game_version", get_game_version())
AeThexAnalytics.set_user_property("install_date", get_install_date())
func start_session():
AeThexAnalytics.track_event("session_start", {
"platform": OS.get_name(),
"version": get_game_version()
})
func connect_game_signals():
# Connect to various game events
var game = get_tree().root.get_node("Game")
if game:
game.level_completed.connect(on_level_completed)
game.player_died.connect(on_player_died)
game.item_collected.connect(on_item_collected)
func on_level_completed(level: int, score: int):
AeThexAnalytics.track_event("level_complete", {
"level": level,
"score": score
})
func on_player_died(level: int, cause: String):
AeThexAnalytics.track_event("player_died", {
"level": level,
"cause": cause
})
func on_item_collected(item: String):
AeThexAnalytics.track_event("item_collected", {
"item": item
})
func get_game_version() -> String:
return ProjectSettings.get_setting("application/config/version", "1.0.0")
func get_install_date() -> int:
# Load from save or set to current time
var save_file = FileAccess.open("user://install_date.save", FileAccess.READ)
if save_file:
var date = save_file.get_64()
save_file.close()
return date
else:
var date = Time.get_unix_time_from_system()
save_file = FileAccess.open("user://install_date.save", FileAccess.WRITE)
save_file.store_64(date)
save_file.close()
return date
Testing Analytics
Test your analytics implementation:
# test_analytics.gd
extends Node
func _ready():
test_analytics()
func test_analytics():
print("Testing analytics...")
# Test basic event
AeThexAnalytics.track_event("test_event", {
"test": true
})
# Test user property
AeThexAnalytics.set_user_property("test_property", "test_value")
# Check console for confirmation
print("Analytics test complete. Check dashboard for events.")
Next Steps
- Publishing Guide - Deploy your game with analytics
- API Reference - Complete analytics API
- Dashboard: View your data at studio.aethex.io/analytics
Summary
You've learned how to:
✅ Track custom events
✅ Set user properties
✅ Create conversion funnels
✅ Monitor performance
✅ Track errors and crashes
✅ Implement A/B testing
✅ Measure engagement metrics
Analytics gives you the insights to make your game better and understand your players!
Ready to publish? Check out the Publishing Guide! 🚀