AeThex-Engine-Core/docs/tutorials/ANALYTICS_TUTORIAL.md
MrPiglr faa98bf76f
Enhance docs with WOW features: cover page, diagrams, alerts, and interactive elements
- 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
2026-02-25 04:04:27 +00:00

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:

  1. Go to: https://studio.aethex.io/analytics
  2. Select your project
  3. 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


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! 🚀