Gaming Event Spec
This page defines all standard gaming events for Datafly Signal — covering web, mobile, and desktop games. The events span the full player lifecycle: discovery and acquisition, sessions, progression, in-game economy, social play, and retention. Implement these events to enable accurate server-side delivery to advertising and analytics platforms.
Gaming events use snake_case identifiers following the noun_past convention (game_started, level_completed, achievement_unlocked). These are Signal’s canonical event names, taken from the live gaming blueprints. Where GA4 has a native gaming equivalent (e.g. level_start, earn_virtual_currency), Signal’s blueprints map to it automatically — see the Vendor Mapping table. Cross-vertical events (search, sign_up, login, generate_lead, view_promotion, select_promotion, ad_impression) use their canonical names.
All events are sent via datafly.track(). Properties are passed as a flat object in the second argument. Use stable identifiers for game_id, level_id, item_id, and achievement_id — these are used as join keys in your data warehouse, so avoid changing them once live. Never put raw PII (email, phone, name) in track() properties.
Acquisition Events
Events tracking how players discover, evaluate, and sign up for the game.
view_promotion
Fired when a promotional banner, featured-game tile, or store creative is visible to the player.
datafly.track('view_promotion', {
promotion_id: 'LAUNCH_S3',
promotion_name: 'Season 3 Launch',
creative_name: 'season3-hero-v2.mp4',
creative_slot: 'store-featured'
})| Property | Type | Required | Description |
|---|---|---|---|
promotion_id | string | Optional | Identifier for the promotion |
promotion_name | string | Optional | Human-readable name of the promotion |
creative_name | string | Optional | Name or URL of the creative asset shown |
creative_slot | string | Optional | Slot or placement where the promotion appeared |
select_promotion
Fired when a player clicks a promotional banner, featured tile, or store creative.
datafly.track('select_promotion', {
promotion_id: 'LAUNCH_S3',
promotion_name: 'Season 3 Launch',
creative_name: 'season3-hero-v2.mp4',
creative_slot: 'store-featured'
})| Property | Type | Required | Description |
|---|---|---|---|
promotion_id | string | Optional | Identifier for the promotion |
promotion_name | string | Optional | Human-readable name of the promotion |
creative_name | string | Optional | Name or URL of the creative asset shown |
creative_slot | string | Optional | Slot or placement where the promotion appeared |
search
Fired when a player submits a search query (for games, items, players, or guides).
datafly.track('search', {
search_term: 'battle royale co-op'
})| Property | Type | Required | Description |
|---|---|---|---|
search_term | string | Required | The search term entered by the player |
generate_lead
Fired when a prospective player submits interest before a full account exists — e.g. a beta waitlist, pre-registration, or newsletter opt-in. Never pass raw email or phone here; the contact PII is hashed server-side via Signal’s identity blueprint.
datafly.track('generate_lead', {
lead_type: 'pre_registration',
game_id: 'dungeon_quest',
value: 0,
currency: 'GBP'
})| Property | Type | Required | Description |
|---|---|---|---|
lead_type | string | Optional | Kind of lead (e.g. pre_registration, beta_waitlist, newsletter) |
game_id | string | Optional | Identifier for the game the lead relates to |
value | number | Optional | Estimated monetary value of the lead |
currency | string | Optional | ISO 4217 currency code |
sign_up
Fired when a player completes account registration.
datafly.track('sign_up', {
method: 'email'
})| Property | Type | Required | Description |
|---|---|---|---|
method | string | Optional | Registration method (e.g. email, google, apple, steam, guest) |
login
Fired when a player signs in to their account.
datafly.track('login', {
method: 'steam'
})| Property | Type | Required | Description |
|---|---|---|---|
method | string | Optional | Login method (e.g. email, google, apple, steam) |
Session Events
Events tracking game sessions from launch to close.
game_started
Fired when a player has launched the game and begun a session.
datafly.track('game_started', {
game_id: 'dungeon_quest',
game_version: '2.4.1',
platform: 'mobile',
mode: 'single_player'
})| Property | Type | Required | Description |
|---|---|---|---|
game_id | string | Optional | Identifier for the game or game mode |
game_version | string | Optional | Application or build version (e.g. 2.4.1) |
platform | string | Optional | Platform: web, mobile, desktop, console |
mode | string | Optional | Play mode: single_player, multiplayer, co_op |
game_ended
Fired when a player’s session has ended.
datafly.track('game_ended', {
game_id: 'dungeon_quest',
session_duration_seconds: 1842,
reason: 'quit'
})| Property | Type | Required | Description |
|---|---|---|---|
game_id | string | Optional | Identifier for the game |
session_duration_seconds | number | Optional | Total session length in seconds |
reason | string | Optional | How the session ended: completed, quit, disconnect |
Progression Events
Events tracking player advancement through levels, tutorials, and achievements.
tutorial_started
Fired when a player has entered a tutorial sequence.
datafly.track('tutorial_started', {
tutorial_id: 'tut_basic_controls'
})| Property | Type | Required | Description |
|---|---|---|---|
tutorial_id | string | Optional | Identifier for the tutorial |
tutorial_completed
Fired when a player has finished a tutorial sequence.
datafly.track('tutorial_completed', {
tutorial_id: 'tut_basic_controls',
duration_seconds: 95,
skipped_steps: 0
})| Property | Type | Required | Description |
|---|---|---|---|
tutorial_id | string | Optional | Identifier for the tutorial |
duration_seconds | number | Optional | Time taken to complete the tutorial |
skipped_steps | number | Optional | Number of steps the player skipped |
tutorial_skipped
Fired when a player has opted to skip a tutorial.
datafly.track('tutorial_skipped', {
tutorial_id: 'tut_advanced_crafting',
at_step: 3
})| Property | Type | Required | Description |
|---|---|---|---|
tutorial_id | string | Optional | Identifier for the tutorial |
at_step | number | Optional | Step number at which the player skipped (1-indexed) |
level_started
Fired when a player has begun a level or stage.
datafly.track('level_started', {
level_id: 'world_2_level_4',
level_name: 'The Dark Cavern',
attempt: 1
})| Property | Type | Required | Description |
|---|---|---|---|
level_id | string | Required | Stable identifier for the level |
level_name | string | Optional | Display name (e.g. The Dark Cavern) |
attempt | number | Optional | Which attempt at this level this is (1 for first play, 2 for first retry, etc.) |
level_completed
Fired when a player successfully finishes a level. For failures, send the dedicated level_failed event below.
datafly.track('level_completed', {
level_id: 'world_2_level_4',
level_name: 'The Dark Cavern',
score: 48200,
stars: 3,
duration_seconds: 147,
attempt: 2
})| Property | Type | Required | Description |
|---|---|---|---|
level_id | string | Required | Stable identifier for the level |
level_name | string | Optional | Display name |
score | number | Optional | Score achieved |
stars | number | Optional | Star rating earned (0–3) |
duration_seconds | number | Optional | Time taken to finish the level |
attempt | number | Optional | Which attempt number this was |
level_failed
Fired when a player has failed a level.
datafly.track('level_failed', {
level_id: 'world_2_level_4',
level_name: 'The Dark Cavern',
score: 12400,
duration_seconds: 63,
attempt: 1,
failure_reason: 'no_lives'
})| Property | Type | Required | Description |
|---|---|---|---|
level_id | string | Required | Stable identifier for the level |
level_name | string | Optional | Display name |
score | number | Optional | Score at point of failure |
duration_seconds | number | Optional | Time played before failing |
attempt | number | Optional | Which attempt this failure was on |
failure_reason | string | Optional | Reason for failure (e.g. time_expired, no_lives, boss_defeated_player) |
achievement_unlocked
Fired when a player has unlocked an achievement or badge.
datafly.track('achievement_unlocked', {
achievement_id: 'ach_speed_runner',
achievement_name: 'Speed Runner',
achievement_type: 'speed',
points: 50
})| Property | Type | Required | Description |
|---|---|---|---|
achievement_id | string | Required | Stable achievement identifier |
achievement_name | string | Optional | Display name (e.g. Speed Runner) |
achievement_type | string | Optional | Category (e.g. speed, completion, social, collection) |
points | number | Optional | Points awarded for the achievement |
Economy Events
Events tracking real-money purchases, virtual-currency flows, and in-game item usage.
Distinguish real-money purchases (item_purchased) from virtual-currency transactions (currency_spent / currency_earned). This separation is essential for revenue reporting and App Store / Play Store reconciliation. Only item_purchased carries real revenue for ad-platform value optimisation.
item_purchased
Fired when a real-money (IAP or store) purchase of an item, bundle, or currency pack completes successfully. This is the most important monetisation event — ensure it fires reliably and carries a unique transaction_id for deduplication.
datafly.track('item_purchased', {
transaction_id: 'IAP-10042',
value: 9.99,
currency: 'GBP',
items: [
{
item_id: 'pack_gems_1200',
item_name: '1,200 Gems Pack',
item_category: 'currency_pack',
price: 9.99,
quantity: 1,
currency: 'GBP'
}
]
})| Property | Type | Required | Description |
|---|---|---|---|
transaction_id | string | Required | Unique purchase identifier — used for deduplication |
value | number | Optional | Total real-money revenue |
currency | string | Optional | ISO 4217 currency code |
items | array | Optional | Items purchased (see Items Array Schema) |
Always send transaction_id on purchase events for deduplication. Platforms like Meta CAPI and GA4 use the transaction ID to prevent double-counting alongside client-side events.
currency_earned
Fired when a player receives virtual currency.
datafly.track('currency_earned', {
virtual_currency_name: 'coins',
value: 500,
source: 'level_complete'
})| Property | Type | Required | Description |
|---|---|---|---|
virtual_currency_name | string | Required | Name of the virtual currency (e.g. gems, coins, star_tokens) |
value | number | Optional | Amount earned |
source | string | Optional | How the currency was earned: level_complete, daily_reward, achievement, purchase |
currency_spent
Fired when a player spends virtual currency.
datafly.track('currency_spent', {
virtual_currency_name: 'gems',
value: 200,
item_id: 'powerup_shield_x3',
item_name: 'Shield Pack x3'
})| Property | Type | Required | Description |
|---|---|---|---|
virtual_currency_name | string | Required | Name of the virtual currency |
value | number | Optional | Amount spent |
item_id | string | Optional | Item acquired with the currency |
item_name | string | Optional | Display name of the item acquired |
item_equipped
Fired when a player equips an item to their character or loadout.
datafly.track('item_equipped', {
item_id: 'skin_dragon_red',
item_name: 'Red Dragon Skin',
slot: 'character_skin'
})| Property | Type | Required | Description |
|---|---|---|---|
item_id | string | Required | Identifier of the equipped item |
item_name | string | Optional | Display name |
slot | string | Optional | Equipment slot the item was placed in (e.g. helmet, primary_weapon, character_skin) |
Social Events
Events tracking multiplayer activity, friend interactions, and community features.
friend_invited
Fired when a player sends a friend or referral invitation, or shares a clip, score, or achievement to a social channel.
datafly.track('friend_invited', {
invitation_method: 'link_share',
content_type: 'invite'
})| Property | Type | Required | Description |
|---|---|---|---|
invitation_method | string | Optional | How the invitation was sent: in_game, link_share, sms, email, twitter, discord |
content_type | string | Optional | Type of content shared, if any (e.g. invite, clip, score, achievement) |
match_started
Fired when a multiplayer match has begun.
datafly.track('match_started', {
match_id: 'match_9f3a2c1e',
match_type: 'ranked',
player_count: 10,
game_mode: 'battle_royale'
})| Property | Type | Required | Description |
|---|---|---|---|
match_id | string | Optional | Unique identifier for the match |
match_type | string | Optional | Match type: ranked, casual, custom |
player_count | number | Optional | Total number of players in the match |
game_mode | string | Optional | In-game mode or map (e.g. capture_the_flag, battle_royale) |
match_completed
Fired when a multiplayer match has ended.
datafly.track('match_completed', {
match_id: 'match_9f3a2c1e',
outcome: 'win',
score: 2840,
duration_seconds: 624,
rank_change: 18
})| Property | Type | Required | Description |
|---|---|---|---|
match_id | string | Optional | Match identifier |
outcome | string | Optional | Player’s result: win, loss, draw |
score | number | Optional | Final score for this player |
duration_seconds | number | Optional | Total match duration in seconds |
rank_change | number | Optional | Change in ranking points as a result of the match (can be negative) |
leaderboard_viewed
Fired when a player opens a leaderboard or posts a score to a scoreboard.
datafly.track('leaderboard_viewed', {
leaderboard_id: 'ldr_season_3_ranked',
scope: 'friends',
score: 48200
})| Property | Type | Required | Description |
|---|---|---|---|
leaderboard_id | string | Optional | Identifier for the leaderboard |
scope | string | Optional | Leaderboard scope: global, friends, regional |
score | number | Optional | The player’s score being posted or viewed, if applicable |
Retention & Monetisation Events
Events tracking returning players, ad engagement, and re-engagement.
ad_impression
Fired when an in-game ad (rewarded, interstitial, or banner) is shown to the player.
datafly.track('ad_impression', {
ad_platform: 'admob',
ad_format: 'rewarded',
ad_unit_name: 'extra_life_reward',
value: 0.012,
currency: 'USD'
})| Property | Type | Required | Description |
|---|---|---|---|
ad_platform | string | Optional | Mediation or ad network (e.g. admob, applovin, unity_ads) |
ad_format | string | Optional | Ad format: rewarded, interstitial, banner |
ad_unit_name | string | Optional | Name of the ad placement |
value | number | Optional | Estimated ad revenue for the impression |
currency | string | Optional | ISO 4217 currency code |
Items Array Schema
Store and economy events accept an items array. Each object in the array can include the following properties. The items[] array uses GA4-style field names. Signal’s server-side blueprints automatically transform these to vendor-specific formats (e.g., Meta’s contents[] with id/title fields).
| Property | Type | Description |
|---|---|---|
item_id | string | Your internal item or SKU identifier |
item_name | string | Item display name |
item_category | string | Item category (e.g. skin, currency_pack, loot_box, powerup) |
item_brand | string | Brand or franchise name |
item_variant | string | Selected variant (e.g. Legendary, Gold) |
price | number | Unit price |
quantity | number | Number of units |
index | number | Position in list (0-indexed, relevant in list/search contexts) |
currency | string | ISO 4217 currency code |
discount | number | Monetary discount applied to this item |
Vendor Mapping
The table below shows how Datafly Signal maps gaming events to the native event names expected by each vendor’s server-side API. Signal uses its own established snake_case event names as the canonical format (left column), and blueprints handle the transformation to vendor-specific payloads. Where GA4 has a native gaming event, that native name appears in the GA4 column; Signal’s event name does not change.
| Signal Event | GA4 | Meta CAPI | TikTok Events API |
|---|---|---|---|
view_promotion | view_promotion | (custom) | (custom) |
select_promotion | select_promotion | (custom) | (custom) |
search | search | Search | Search |
generate_lead | generate_lead | Lead | SubmitForm |
sign_up | sign_up | CompleteRegistration | CompleteRegistration |
login | login | (custom) | (custom) |
game_started | (custom) | (custom) | (custom) |
game_ended | (custom) | (custom) | (custom) |
tutorial_started | tutorial_begin | (custom) | (custom) |
tutorial_completed | tutorial_complete | (custom) | (custom) |
tutorial_skipped | (custom) | (custom) | (custom) |
level_started | level_start | (custom) | (custom) |
level_completed | level_end | (custom) | (custom) |
level_failed | (custom) | (custom) | (custom) |
achievement_unlocked | unlock_achievement | AchievementUnlocked | UnlockAchievement |
item_purchased | purchase | Purchase | CompletePayment |
currency_earned | earn_virtual_currency | (custom) | (custom) |
currency_spent | spend_virtual_currency | SpendCredits | SpendCredits |
item_equipped | (custom) | (custom) | (custom) |
friend_invited | share | (custom) | (custom) |
match_started | (custom) | (custom) | (custom) |
match_completed | (custom) | (custom) | (custom) |
leaderboard_viewed | post_score | (custom) | (custom) |
ad_impression | ad_impression | (custom) | (custom) |