The business problem
Mobile games lose 75% of players within the first 3 days and 90% within 30 days. For a game generating $100M annually, every 1% improvement in Day-30 retention is worth $5-10M in incremental revenue. The challenge: identifying players at risk of churning before they disengage, while there is still time to intervene with targeted offers, social features, or content recommendations.
Traditional churn models use individual player metrics: sessions per week, levels completed, in-app purchases. They miss the social context that is the strongest predictor of retention. A player whose guild is thriving has fundamentally different churn risk than one whose friends have all gone silent, even if their individual metrics are identical.
Why flat ML fails
- No social anchoring: Players with 5+ active friends churn at 1/3 the rate of solo players. Flat models reduce this to “friend_count = 5”, losing the activity and engagement patterns of those friends.
- No contagion modeling: Churn is contagious in gaming. When a guild leader quits, members follow within days. Flat models cannot propagate this risk signal.
- Progression context: Being stuck at level 20 means something different in a game where most players quit at level 18 vs one where they quit at level 50. The player graph provides this context.
- Spending patterns: A whale (high spender) whose co-players are churning may be about to stop spending. The social graph signals spending risk before individual spending changes.
The relational schema
Node types:
Player (id, level, total_playtime, iap_spend, days_since_install)
Guild (id, member_count, avg_activity, founded_date)
Match (id, mode, duration, result, timestamp)
Edge types:
Player --[friends_with]--> Player (since_date)
Player --[member_of]--> Guild (role, join_date)
Player --[played_in]--> Match (score, kills, assists)
Player --[co_played]--> Player (match_count, last_played)Social edges (friends, guild, co-play) carry the strongest signal. Match participation edges capture behavioral patterns.
PyG architecture: GATConv on social-behavioral graph
import torch
import torch.nn.functional as F
from torch_geometric.nn import GATConv, HeteroConv, Linear
class PlayerChurnGNN(torch.nn.Module):
def __init__(self, hidden_dim=64, heads=4):
super().__init__()
self.player_lin = Linear(-1, hidden_dim)
self.guild_lin = Linear(-1, hidden_dim)
self.match_lin = Linear(-1, hidden_dim)
self.conv1 = HeteroConv({
('player', 'friends_with', 'player'): GATConv(
hidden_dim, hidden_dim // heads, heads=heads),
('player', 'member_of', 'guild'): GATConv(
hidden_dim, hidden_dim // heads, heads=heads),
('player', 'played_in', 'match'): GATConv(
hidden_dim, hidden_dim // heads, heads=heads),
('player', 'co_played', 'player'): GATConv(
hidden_dim, hidden_dim // heads, heads=heads),
}, aggr='sum')
self.conv2 = HeteroConv({
('player', 'friends_with', 'player'): GATConv(
hidden_dim, hidden_dim // heads, heads=heads),
('player', 'member_of', 'guild'): GATConv(
hidden_dim, hidden_dim // heads, heads=heads),
('player', 'co_played', 'player'): GATConv(
hidden_dim, hidden_dim // heads, heads=heads),
}, aggr='sum')
self.classifier = Linear(hidden_dim, 1)
def forward(self, x_dict, edge_index_dict):
x_dict['player'] = self.player_lin(x_dict['player'])
x_dict['guild'] = self.guild_lin(x_dict['guild'])
x_dict['match'] = self.match_lin(x_dict['match'])
x_dict = {k: F.elu(v) for k, v in
self.conv1(x_dict, edge_index_dict).items()}
x_dict = self.conv2(x_dict, edge_index_dict)
return torch.sigmoid(
self.classifier(x_dict['player']).squeeze(-1))GATConv attention weights learn which social connections matter: active co-players get higher attention than dormant friends. Two hops propagate guild-level health signals.
Expected performance
- Engagement heuristics: ~55 AUROC
- LightGBM (flat-table): 62.44 AUROC
- GNN (GATConv social graph): 75.83 AUROC
- KumoRFM (zero-shot): 76.71 AUROC
Or use KumoRFM in one line
PREDICT is_churned FOR player
USING player, guild, match, sessionOne PQL query. KumoRFM constructs the social-behavioral graph, captures friend activity patterns, and outputs churn probabilities per player.