ML Audience Targeting in Advertising
Machine learning for targeting translates from "show to all women aged 25-34" to "show to those with a 73%+ probability of conversion within the next 7 days." The efficiency difference is 3-5x with the same budget. We implement such models for advertising campaigns: in a typical project, CTR grows from 0.08% to 0.4%, and the cost per lead drops by 40%. We rely solely on first-party data — the only sustainable path in a world without third-party cookies. For example, in one e-commerce project, CPA dropped from $12 to $7 — a 42% savings. Request a consultation on implementing an ML targeting model — we'll select the optimal solution for your data.
Problems We Solve
Blind demographic targeting. Age and gender do not guarantee interest. A 35-year-old user might be looking for a gift for a child, not for themselves. An ML model evaluates behavioral signals: frequency of viewing product pages, add-to-cart actions, time between sessions. The result is a conversion prediction accuracy >85%.
Bloated audiences with low conversion. Lookalike models based on 50+ seed users expand the audience while preserving the concentration of "hot" leads. We use a supervised classifier (LightGBM) with calibrated probabilities, not simple kNN — this yields an ROC-AUC improvement of 0.08–0.12.
Loss of context after retargeting. When a user navigates to a technology article and is shown credit cards — a context break. Our contextual engine analyzes the URL and page text, determines the IAB category (e.g., IAB19 — Technology) and selects creatives in the same topic. It works without user data, which is important for GDPR.
How Does the ML Model Assess Propensity?
The key is quality features. We take raw events: product_view, add_to_cart, checkout_start, search. We compute recency (hours since last event), session frequency, funnel depth (weighted average number of actions), activity trend (last 7 days vs previous). These features are fed into a LightGBM classifier with tuned parameters: learning_rate=0.01, max_depth=6, colsample_bytree=0.8. We obtain for each user a purchase_probability and tiers: cold (<10%), warm (10-30%), hot (30-60%), ready_to_buy (>60%).
import pandas as pd
import numpy as np
import lightgbm as lgb
from sklearn.cluster import MiniBatchKMeans
from sklearn.preprocessing import LabelEncoder
class PredictiveAudienceBuilder:
"""Creating audiences based on conversion probabilities"""
def build_intent_features(self, user_events: pd.DataFrame) -> pd.DataFrame:
"""
Intent features from user events.
user_events: user_id, event_type, page_url, timestamp, session_id
"""
df = user_events.copy()
df['ts'] = pd.to_datetime(df['timestamp'])
# Recency of last activity
now = df['ts'].max()
recency = df.groupby('user_id')['ts'].max().apply(
lambda t: (now - t).total_seconds() / 3600
).rename('hours_since_last_event')
# Behavioral features
behavior = df.groupby('user_id').agg(
total_sessions=('session_id', 'nunique'),
total_events=('event_type', 'count'),
product_views=('event_type', lambda x: (x == 'product_view').sum()),
cart_adds=('event_type', lambda x: (x == 'add_to_cart').sum()),
checkout_starts=('event_type', lambda x: (x == 'checkout_start').sum()),
search_queries=('event_type', lambda x: (x == 'search').sum()),
)
# Conversion funnel (normalized)
behavior['funnel_depth'] = (
behavior['product_views'] * 1 +
behavior['cart_adds'] * 3 +
behavior['checkout_starts'] * 7
) / behavior['total_sessions'].clip(1)
# Session activity: trend of last 7 days vs previous 7
last_7d = df[df['ts'] >= now - pd.Timedelta(days=7)]
prev_7d = df[df['ts'].between(now - pd.Timedelta(days=14), now - pd.Timedelta(days=7))]
activity_last = last_7d.groupby('user_id')['event_type'].count().rename('events_last_7d')
activity_prev = prev_7d.groupby('user_id')['event_type'].count().rename('events_prev_7d')
result = behavior.join(recency).join(activity_last).join(activity_prev).fillna(0)
result['activity_trend'] = (
result['events_last_7d'] - result['events_prev_7d']
) / (result['events_prev_7d'] + 1)
return result
def score_purchase_propensity(self, features: pd.DataFrame,
model: lgb.LGBMClassifier) -> pd.DataFrame:
"""Estimate purchase probability for each user"""
scores = model.predict_proba(features)[:, 1]
result = pd.DataFrame({
'user_id': features.index,
'purchase_probability': scores,
'audience_tier': pd.cut(
scores,
bins=[0, 0.1, 0.3, 0.6, 1.0],
labels=['cold', 'warm', 'hot', 'ready_to_buy']
)
})
return result.sort_values('purchase_probability', ascending=False)
class BehavioralClusteringAudience:
"""Behavioral segmentation without supervision"""
def segment_by_behavior(self, user_features: pd.DataFrame,
n_clusters: int = 8) -> pd.DataFrame:
"""
K-Means clustering to identify hidden audience segments.
"""
from sklearn.preprocessing import StandardScaler
feature_cols = user_features.select_dtypes(include=[np.number]).columns
X = user_features[feature_cols].fillna(0)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
kmeans = MiniBatchKMeans(n_clusters=n_clusters, random_state=42, n_init=10)
clusters = kmeans.fit_predict(X_scaled)
user_features = user_features.copy()
user_features['cluster'] = clusters
# Cluster profiles
profiles = user_features.groupby('cluster')[feature_cols].mean()
return user_features, profiles
def label_clusters(self, cluster_profiles: pd.DataFrame) -> dict:
"""Automatic cluster labeling based on profiles"""
labels = {}
for cluster_id, row in cluster_profiles.iterrows():
# Simplified heuristic labeling
if row.get('checkout_starts', 0) > 2:
label = 'high_intent_buyers'
elif row.get('product_views', 0) > 10 and row.get('cart_adds', 0) == 0:
label = 'browsers_not_buyers'
elif row.get('total_sessions', 0) > 20:
label = 'loyal_visitors'
elif row.get('hours_since_last_event', 9999) > 720:
label = 'dormant_users'
else:
label = f'segment_{cluster_id}'
labels[cluster_id] = label
return labels
How to Set Up Contextual Targeting Without Cookies?
class ContextualTargetingEngine:
"""ML targeting based on page content (cookieless)"""
def classify_page_context(self, page_text: str,
page_url: str) -> dict:
"""
IAB categorization of a page for contextual targeting.
Works without user-level data (GDPR-compliant).
"""
# Key context signals
url_signals = self._extract_url_signals(page_url)
# In production: BERT-based classifier trained on IAB taxonomy
# Here simplified keyword-based version
iab_keywords = {
'IAB19': ['technology', 'software', 'programming', 'tech'],
'IAB13': ['finance', 'investment', 'stock', 'crypto', 'money'],
'IAB7': ['health', 'fitness', 'medical', 'diet'],
'IAB9': ['hobby', 'crafts', 'games', 'gaming'],
}
text_lower = page_text.lower()
scores = {}
for iab_cat, keywords in iab_keywords.items():
score = sum(text_lower.count(kw) for kw in keywords)
if score > 0:
scores[iab_cat] = score
if not scores:
return {'categories': ['IAB24'], 'confidence': 0.5}
primary_cat = max(scores, key=scores.get)
total = sum(scores.values())
return {
'primary_category': primary_cat,
'all_categories': list(scores.keys()),
'confidence': round(scores[primary_cat] / total, 2),
'url_signals': url_signals,
}
def _extract_url_signals(self, url: str) -> list:
signals = []
if '/news/' in url or '/article/' in url:
signals.append('editorial_content')
if '/product/' in url or '/shop/' in url:
signals.append('ecommerce')
if '/blog/' in url:
signals.append('blog_content')
return signals
Why Predictive Targeting Outperforms Demographic Targeting?
Demographic targeting (age/gender) is a relic. CPM is low, but conversion fluctuates at 0.05-0.1%. Behavioral targeting based on third-party cookies yields CTR of 0.2-0.5%, but will soon disappear. ML models based on first-party data provide CTR of 0.3-0.8% and minimal budget waste on "cold" audiences. In the long term, only the first one is independent of regulatory risks. Predictive targeting is 2-4 times more effective than lookalike models based on kNN, as it uses gradient boosting instead of simple clustering.
Comparison of Targeting Methods
| Method | CPM | CTR | Conversion | Privacy |
|---|---|---|---|---|
| Demographic (age/gender) | low | 0.05-0.1% | low | safe |
| Behavioral (3rd party cookies) | high | 0.2-0.5% | medium | limited |
| Predictive (ML propensity) | medium | 0.3-0.8% | high | 1st party |
| Lookalike ML | medium | 0.2-0.6% | medium | 1st party |
| Contextual (cookieless) | medium | 0.1-0.3% | medium | safe |
Using predictive targeting saves up to 40% of the advertising budget and reduces CPA by 30-50%. As experts note, gradient boosting is the industry standard for binary classification tasks with tabular data.
More about model metrics
To evaluate the quality of the propensity model, we use AUPRC (Area Under Precision-Recall Curve) — it is sensitive to class imbalance. The target value is ≥0.75. Additionally, we control the calibration of probabilities using a calibration curve. If the model overestimates the probability for a cold audience, we adjust the threshold.How to Implement Predictive Targeting: Step-by-Step Plan
- Data audit: check the quality of event tracking (Google Tag Manager, Amplitude, custom pipelines).
- Feature engineering: Python/Pandas for generating features (activity, funnel, trends).
- Model training: LightGBM classifier with probability calibration, time-based cross-validation.
- Clustering: MiniBatchKMeans for identifying segments (lazy, hot, abandoners).
- Contextual engine: NLP module based on BERT for page classification according to IAB taxonomy (up to 30 categories).
- Integration with DSP: API for sending segments to Facebook Ads, Google Ads, Yandex.Direct or a self-serve platform.
- A/B testing: launch against baseline targeting for 2 weeks — we guarantee a ROAS increase of 25%+ or free adjustment.
What's Included in the Work
Our experience: over 50 successful projects for e-commerce and fintech.
- Data audit: assessment of the quality and completeness of event data, tracking setup.
- Feature development: Python/Pandas scripts for feature generation.
- Propensity model: LightGBM classifier with probability calibration, AUPRC ≥0.75.
- Clustering: MiniBatchKMeans for identifying segments.
- Contextual engine: NLP module based on BERT for page classification according to IAB taxonomy.
- Integration with DSP: API for sending segments to advertising platforms.
- Test drive: A/B testing of the model against baseline targeting for 2 weeks — we guarantee a ROAS increase of 25%+ or free adjustment.
Work Process
| Stage | Duration |
|---|---|
| Analytics: collection and ETL of tracker | 2-3 days |
| Feature engineering: data mart formation | 3-5 days |
| ML development: model training and validation | 5-7 days |
| Testing: A/B experiment in a real campaign | 7-14 days |
| Deployment: model rollout to production | 2-3 days |
Timeline and Cost
Estimated timeframes — from 4 to 6 weeks to a working MVP. Cost is calculated individually depending on the volume of data, number of target events, and integrations. Get a consultation — we'll lock in success metrics at the start.
Additional resources: LightGBM, IAB taxonomy.







