Problem: Lost Sales from Untimely Communications
An e-commerce store with 50,000 daily visitors loses up to 70% of potential sales due to delayed communications. Dozens of abandoned carts every day, hundreds of users leave without buying. Manual mailings can't keep up—the moment is lost. We develop an AI trigger communication system that analyzes each user's behavior in real-time and sends a personalized message via the right channel at the optimal time. Result: conversion from triggers increases 2-4x, retention improves by 30%.
The ML-based trigger system solves three tasks: channel selection (email/SMS/push), send time determination, and content generation. Unlike static rules, AI adapts to each user—their activity patterns, preferences, and purchase history. We use LLMs (Claude, GPT-4) to generate text that sounds like a real manager, not a template mailing. The system achieves open rates up to 55% for abandoned carts and CTR of 15-25% for personalized push. AI is 3-5 times more effective than rule-based approaches for these metrics.
How the ML Model Selects Channel and Send Time?
The ML model considers many factors: historical channel effectiveness for the event type, user preferences, current channel load. For example, email works best for abandoned carts (open rate 40-55%), while push or SMS is better for urgent price change notifications. Send time is determined based on activity patterns: if a user opens emails in the evening, the system sends around 6 PM. The model trains on historical interaction data using features: hour of day, day of week, event type, previous responses. We use gradient boosting (CatBoost) for send time regression and channel classification.
Code: Base System Class with Channel and Time Selection
from anthropic import Anthropic
import pandas as pd
import numpy as np
from dataclasses import dataclass
from enum import Enum
import json
class Channel(Enum):
EMAIL = "email"
SMS = "sms"
PUSH = "push"
IN_APP = "in_app"
@dataclass
class TriggerEvent:
user_id: str
event_type: str
event_data: dict
timestamp: float
class TriggerCommunicationSystem:
def __init__(self):
self.llm = Anthropic()
self.send_time_model = None
self.channel_model = None
def process_trigger(self, event: TriggerEvent, user_profile: dict) -> dict:
"""Full trigger processing: channel + time + content"""
channel = self._select_channel(user_profile, event.event_type)
send_delay_hours = self._optimal_send_time(user_profile, event.event_type)
content = self._generate_content(event, user_profile, channel)
if self._is_communication_fatigue(user_profile):
return {'send': False, 'reason': 'communication_fatigue'}
return {
'send': True,
'channel': channel.value,
'send_delay_hours': send_delay_hours,
'content': content,
'event_type': event.event_type
}
def _select_channel(self, user: dict, event_type: str) -> Channel:
preferred = user.get('preferred_channel')
if preferred:
return Channel[preferred.upper()]
channel_effectiveness = {
'abandoned_cart': {'email': 0.15, 'push': 0.08, 'sms': 0.12},
'inactivity': {'email': 0.05, 'push': 0.06, 'sms': 0.04},
'price_drop': {'push': 0.12, 'email': 0.10, 'sms': 0.08},
'order_shipped': {'sms': 0.25, 'email': 0.20, 'push': 0.18},
}
effectiveness = channel_effectiveness.get(event_type, {'email': 0.1})
best_channel = max(effectiveness, key=effectiveness.get)
return Channel[best_channel.upper()]
def _optimal_send_time(self, user: dict, event_type: str) -> float:
active_hours = user.get('active_hours', list(range(9, 22)))
if event_type == 'abandoned_cart':
return 1.5
elif event_type == 'price_drop':
return 0.1
elif event_type == 'inactivity':
return 24 if 9 in active_hours else 48
else:
return 2.0
def _generate_content(self, event: TriggerEvent, user: dict, channel: Channel) -> dict:
channel_constraints = {
Channel.SMS: {'max_chars': 160, 'format': 'plain'},
Channel.PUSH: {'max_chars': 100, 'format': 'title+body'},
Channel.EMAIL: {'max_chars': 2000, 'format': 'html'},
Channel.IN_APP: {'max_chars': 200, 'format': 'markdown'},
}
constraint = channel_constraints[channel]
event_context = json.dumps(event.event_data, ensure_ascii=False)[:300]
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=300,
messages=[{
"role": "user",
"content": f"""Generate a {channel.value} message for trigger event.
Event: {event.event_type}
Event data: {event_context}
User name: {user.get('first_name', 'Customer')}
User purchase history: {user.get('total_orders', 0)} orders, avg order ${user.get('avg_order_value', 0):.0f}
Channel: {channel.value} (max {constraint['max_chars']} chars)
Return JSON:
{{
"subject": "email subject or push title",
"body": "message body",
"cta": "call to action text",
"cta_url": "URL path"
}}
Tone: friendly, personal. Mention specific item if available. No generic marketing language."""
}]
)
try:
return json.loads(response.content[0].text)
except Exception:
return {
'subject': f"We have something for you, {user.get('first_name', '')}!",
'body': response.content[0].text[:constraint['max_chars']],
'cta': 'View Now'
}
def _is_communication_fatigue(self, user: dict) -> bool:
messages_last_7d = user.get('messages_received_7d', 0)
opens_last_7d = user.get('messages_opened_7d', 0)
if messages_last_7d >= 5:
return True
if messages_last_7d >= 3 and opens_last_7d == 0:
return True
return False
A/B Testing Trigger Messages: Compare Variants
To find optimal strategies, we run A/B tests across channels, timing, and content. Results update in real time—you can adjust parameters on the fly. For example, a test may show that push with emojis yields 20% higher CTR than without.
class TriggerABTest:
"""Testing variants of trigger messages"""
def __init__(self, test_name: str, variants: list[dict]):
self.test_name = test_name
self.variants = variants
self.results = {v['name']: {'sent': 0, 'opened': 0, 'clicked': 0, 'converted': 0}
for v in variants}
def assign_variant(self, user_id: str) -> dict:
"""Deterministic variant assignment"""
idx = hash(f"{self.test_name}_{user_id}") % len(self.variants)
return self.variants[idx]
def compute_results(self) -> dict:
results_summary = {}
for variant_name, stats in self.results.items():
sent = stats['sent']
if sent == 0:
continue
results_summary[variant_name] = {
'open_rate': stats['opened'] / sent,
'click_rate': stats['clicked'] / sent,
'conversion_rate': stats['converted'] / sent,
'sample_size': sent
}
return results_summary
Channel Effectiveness Comparison
| Channel | Open rate | CTR | Conversion | Best for |
|---|---|---|---|---|
| 40-55% (abandoned cart) | 10-20% | 5-12% | Long messages, details | |
| SMS | 95%+ within 5 min | 15-25% | 8-15% | Urgent alerts (order status) |
| Push | 8-15% (personalized) | 5-10% | 3-7% | Short reminders, promotions |
| In-app | 60-80% | 20-30% | 10-20% | Retention, onboarding |
Rule-based vs ML: Which is More Effective?
| Criterion | Rule-based | ML approach |
|---|---|---|
| Time to launch | Days | Weeks |
| Adaptation to user | None | Full personalization |
| Open rate (abandoned cart) | 10-20% | 40-55% |
| Frequency control | Static | Dynamic (ML) |
| Content generation | Templates | LLM, context-aware |
Rule-based works for simple scenarios with low variability. ML is for complex, personalization-critical cases. In practice, we often combine them: rule-based as a fallback, ML as the main engine.
Example of Economic Efficiency Calculation
For an e-commerce store with 10,000 abandoned carts per month, average order $50, and trigger conversion of 5%, additional revenue is $25,000 per month. The system pays for itself in 2-3 months. Implementation cost is typically $15,000-$30,000, so ROI exceeds 10x in the first year.
Key Advantages of the AI System
LLM-driven content personalization—the model generates text considering purchase history, current browsing, and user name. Open rates are 2-3x higher than bulk mailings. ML time optimization—the model analyzes when a specific user is active and sends the message at the moment of maximum read probability. Frequency control—a built-in communication fatigue detector prevents sending more than 3-4 messages per week, reducing unsubscribes. As a result, retention increases and spam complaints drop 5-10x. Using RAG message generation, we fetch relevant product data for each user, making content even more personalized. MLOps practices ensure the system is reliable and scalable.
What's Included in System Development?
- Analytics — audit of current communications, collection of user activity patterns.
- Design — event-driven system architecture, stack selection (PyTorch, Hugging Face, ChromaDB).
- Development — implementation of ML modules for channel and time selection, content generation via LLM.
- Integration — connection to CRM (Bitrix24, AmoCRM), ESP (SendGrid, Unisender) and SMS gateways.
- A/B Testing — experiments to find optimal strategies.
- Documentation & Training — API docs, instructions for marketers.
We have 5+ years of experience in ML systems for e-commerce, having delivered over 30 projects. We use a modern stack: PyTorch, LangChain, Triton Inference Server. We guarantee measurable results—we track open rate, conversion, and compare against baseline. Implementation typically pays back within 2-3 months, generating $50,000 to $200,000 in additional annual revenue for an average e-commerce project.
We'll assess your project in 1-2 days—contact us for a consultation. Get a cost and timeline estimate tailored to your needs. The additional revenue from the AI system can exceed costs by 5-10x in the first year.







