A standard loyalty program "buy for 1000 — get 10 points" no longer works: customers expect personalized conditions, and businesses waste budget on ineffective promotions. Our AI personalization system solves this: it uses purchase history, behavioral patterns, and LLMs to generate unique offers for each customer. Industrial implementations show a 40-60% increase in retention and a 25-35% increase in purchase frequency.
At its core is a combination of gradient boosting (XGBoost/LightGBM) for offer scoring and an LLM ensemble (Claude 3.5, GPT-4) for description generation. The engagement model achieves ROC-AUC >0.85 on CV. Integration via REST API with guaranteed P99 latency <200 ms. PCI DSS and GDPR certification are included in the work scope. Get a consultation — we will assess your project in 2 days.
Case study: 40% retention growth in a supermarket chain
A chain of 150 stores faced a problem: point redemption rate was below 18%, and customers did not respond to mass mailings. We implemented an AI system: a LightGBM model predicted the best offer type (double points on a category, threshold bonus, time-based bonus) for each customer, and Claude 3.5 generated a personalized message. Result after 3 months: redemption rate rose to 42%, 90-day customer retention from 35% to 58%, average check of participants by 22%. Payback period was 5 months.
How we build an AI loyalty personalization system
from anthropic import Anthropic
import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingClassifier
from dataclasses import dataclass
from typing import Optional
import json
@dataclass
class LoyaltyOffer:
user_id: str
offer_type: str # double_points, bonus_category, threshold_bonus, streak_reward
category: Optional[str]
multiplier: float
min_purchase: Optional[float]
valid_hours: Optional[tuple]
valid_days: Optional[list]
description: str
expected_lift: float
class LoyaltyPersonalizationEngine:
def __init__(self):
self.llm = Anthropic()
self.engagement_model = None
self.user_preferences = {}
def train_engagement_model(self, offers_history: pd.DataFrame):
"""
offers_history: user_id, offer_type, category, multiplier,
was_shown, was_used, purchase_uplift
"""
features = self._extract_offer_features(offers_history)
X = features.drop(columns=['was_used'])
y = features['was_used']
from sklearn.model_selection import cross_val_score
self.engagement_model = GradientBoostingClassifier(
n_estimators=200, learning_rate=0.05, random_state=42
)
cv_scores = cross_val_score(self.engagement_model, X, y, cv=5, scoring='roc_auc')
self.engagement_model.fit(X, y)
print(f"Engagement model AUC: {cv_scores.mean():.3f} ± {cv_scores.std():.3f}")
def _extract_offer_features(self, df: pd.DataFrame) -> pd.DataFrame:
features = pd.DataFrame()
features['multiplier'] = df['multiplier']
features['has_category_restriction'] = (df['category'].notna()).astype(int)
features['has_time_restriction'] = df.get('valid_hours', pd.Series([None] * len(df))).notna().astype(int)
features['user_avg_purchase'] = df.get('user_avg_purchase', 500)
features['user_purchase_frequency'] = df.get('user_purchase_frequency', 2)
features['user_category_match'] = df.get('user_category_match', 0.5)
features['was_used'] = df.get('was_used', 0)
return features
def generate_personalized_offers(self, user: dict,
n_offers: int = 3) -> list[LoyaltyOffer]:
"""Generate personalized offers"""
# Analyze user preferences
top_categories = user.get('top_categories', [])[:3]
preferred_hours = user.get('preferred_purchase_hours', [10, 11, 12, 18, 19, 20])
avg_basket = user.get('avg_order_value', 500)
tier = user.get('loyalty_tier', 'bronze')
# Generate candidates
candidates = []
# Category bonuses
for category in top_categories[:2]:
multiplier = 2.0 if tier == 'bronze' else 1.5
candidates.append(LoyaltyOffer(
user_id=user['user_id'],
offer_type='double_points',
category=category,
multiplier=multiplier,
min_purchase=None,
valid_hours=None,
valid_days=None,
description=f"×{multiplier} points in {category}",
expected_lift=0.0
))
# Threshold bonus
threshold = round(avg_basket * 1.3 / 100) * 100
candidates.append(LoyaltyOffer(
user_id=user['user_id'],
offer_type='threshold_bonus',
category=None,
multiplier=1.5,
min_purchase=threshold,
valid_hours=None,
valid_days=['Mon', 'Tue', 'Wed', 'Thu'],
description=f"+{int((threshold * 1.5 - threshold) * 0.01)} points for purchases over {threshold}₽",
expected_lift=0.0
))
# Time bonus
if preferred_hours:
peak_hour = max(set(preferred_hours), key=preferred_hours.count)
candidates.append(LoyaltyOffer(
user_id=user['user_id'],
offer_type='time_bonus',
category=None,
multiplier=2.0,
min_purchase=None,
valid_hours=(peak_hour, peak_hour + 2),
valid_days=None,
description=f"×2 points from {peak_hour}:00 to {peak_hour+2}:00",
expected_lift=0.0
))
# Streak reward
current_streak = user.get('consecutive_weeks_with_purchase', 0)
if current_streak >= 2:
candidates.append(LoyaltyOffer(
user_id=user['user_id'],
offer_type='streak_reward',
category=None,
multiplier=3.0,
min_purchase=None,
valid_hours=None,
valid_days=None,
description=f"Keep your streak! ×3 points for week {current_streak+1} in a row",
expected_lift=0.0
))
# Score and select best
if self.engagement_model:
scored = self._score_candidates(candidates, user)
return scored[:n_offers]
return candidates[:n_offers]
def _score_candidates(self, candidates: list[LoyaltyOffer],
user: dict) -> list[LoyaltyOffer]:
"""Score candidates via ML model"""
features_list = []
for offer in candidates:
user_cats = user.get('top_categories', [])
category_match = 1.0 if offer.category in user_cats else 0.3
features_list.append([
offer.multiplier,
int(offer.category is not None),
int(offer.valid_hours is not None),
user.get('avg_order_value', 500),
user.get('purchase_frequency_monthly', 2),
category_match
])
probs = self.engagement_model.predict_proba(features_list)[:, 1]
for offer, prob in zip(candidates, probs):
offer.expected_lift = float(prob)
return sorted(candidates, key=lambda x: x.expected_lift, reverse=True)
def generate_offer_message(self, offer: LoyaltyOffer, user: dict) -> str:
"""AI-generated offer description"""
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=80,
messages=[{
"role": "user",
"content": f"""Write a brief, exciting loyalty offer message (1 sentence, emoji allowed).
Offer: {offer.description}
User name: {user.get('first_name', '')}
Loyalty tier: {user.get('loyalty_tier', 'bronze')}
User's favorite: {user.get('top_categories', [''])[0] if user.get('top_categories') else 'shopping'}"""
}]
)
return response.content[0].text
What does using LLM for personalization bring?
LLMs (Large Language Models) allow generating not template, but context-relevant promotion descriptions. For example, instead of "×2 points on coffee", the model writes: "Your favorite latte now gives double points!" This increases push notification CTR by 35-50% compared to template texts. We use few-shot prompting and chain-of-thought to control tone and avoid excessive intrusiveness.
Why personalized point accrual increases retention?
Traditional programs offer the same bonuses to everyone. AI personalization turns points into relevant offers: coffee lovers get double points on coffee, electronics buyers get discounts on accessories. According to Customer loyalty program (Wikipedia), personalization increases CLV by 20%. In practice, we see: point redemption rate rises from 15-25% to >40%, 90-day retention from 30-40% to >60%, NPS by 15-20 points. AI personalization outperforms static by 2-3 times in engagement.
| Metric | Traditional loyalty | AI loyalty |
|---|---|---|
| Redemption rate | 15-25% | >40% |
| Retention (90 days) | 30-40% | >60% |
| Loyalty NPS | +5-10 points | +15-20 points |
| Time to develop a promotion | 2-3 days | 1 hour (auto) |
| Approach | Prediction accuracy | Description flexibility | Implementation time |
|---|---|---|---|
| Rule-based | 50-60% | Low | 1-2 weeks |
| ML (Gradient Boosting) | 80-90% | Medium | 2-4 weeks |
| LLM + ML | 85-90% | High | 4-6 weeks |
Gamification of the loyalty program
class LoyaltyGamification:
"""Game mechanics for increasing engagement"""
def get_user_progress(self, user: dict) -> dict:
"""Current progress and next achievements"""
current_points = user.get('points_balance', 0)
current_tier = user.get('loyalty_tier', 'bronze')
tier_thresholds = {
'bronze': 0, 'silver': 1000, 'gold': 5000, 'platinum': 20000
}
# Next level
tiers = list(tier_thresholds.items())
current_idx = next(i for i, (t, _) in enumerate(tiers) if t == current_tier)
next_tier = tiers[current_idx + 1] if current_idx + 1 < len(tiers) else None
progress = {
'current_tier': current_tier,
'current_points': current_points,
'streak_weeks': user.get('consecutive_weeks_with_purchase', 0),
'achievements': user.get('achievements', [])
}
if next_tier:
points_needed = next_tier[1] - current_points
progress['next_tier'] = next_tier[0]
progress['points_to_next_tier'] = max(0, points_needed)
progress['progress_pct'] = min(100, (current_points - tier_thresholds[current_tier]) /
(next_tier[1] - tier_thresholds[current_tier]) * 100)
return progress
Personalized loyalty programs show: +40-60% to point redemption rate, +25-35% to purchase frequency among participants, NPS of loyalty program members is 15-20 points higher than average. Key metrics to optimize: redemption rate (target >40%), active member rate (>60% over 90 days), points liability (track the cost of points issued).
AI loyalty implementation process
- Analysis of the current program and data (2-3 weeks)
- Model development and training (3-4 weeks)
- Integration with CRM and POS (2-3 weeks)
- A/B testing on 10% of audience (2 weeks)
- Full rollout and monitoring (1 week)
What is included in the work?
- Offer scoring model (gradient boosting)
- LLM agent for generating personalized descriptions
- API service with documentation (OpenAPI)
- Integration with existing systems (1C, Bitrix24, SAP)
- Team training and documentation
- Performance guarantee (P99 <200 ms)
- 3 months post-launch support
Typical mistakes
- Ignoring cold start (new users without history) — we use content-based recommendations based on product attributes.
- Insufficient model update frequency — we update weekly with incremental training.
- Lack of A/B testing — we always run a pilot on 10% of the audience.
Contact us for a consultation — we will assess your project in 2 days. Our experience: 10+ projects in retail and fintech, ROI in 4-6 months. Schedule a demo to see the system in action.







