Implementing Content Personalization by Audience Segments
Personalization is showing different content to different user segments to increase relevance and conversion. Unlike A/B testing (random distribution), personalization is deterministic: users with specific attributes always see corresponding content.
Types of Segments
- Behavioral: viewed products, categories, previous purchases
- Demographic: geo, language, device
- Traffic source: Google Ads, SEO, email, direct
- Funnel stage: new visitor, returning, registered, paying
- Business attributes: plan, company, role
Personalization Architecture
User Request
↓
Segment Resolver (who is this user?)
↓
Rule Engine (what content to show?)
↓
Content Renderer (render personalized variant)
↓
Analytics (track impression + conversion)
Server-Side Segmentation
# segment_resolver.py
class SegmentResolver:
def resolve(self, user: User, request: Request) -> list[str]:
segments = []
# Geolocation
country = get_geoip(request.remote_addr)
segments.append(f"country:{country}")
# Device
device = parse_device(request.user_agent)
segments.append(f"device:{device}")
# Traffic source
referrer = request.referrer or ''
if 'google' in referrer:
segments.append("source:google")
elif 'email' in request.args.get('utm_medium', ''):
segments.append("source:email")
else:
segments.append("source:direct")
# Lifecycle stage
if not user:
segments.append("lifecycle:anonymous")
elif not user.has_purchases:
segments.append("lifecycle:prospect")
if user.session_count > 3:
segments.append("lifecycle:warm_lead")
else:
segments.append("lifecycle:customer")
segments.append(f"plan:{user.plan}")
# Behavioral (from Redis)
viewed_cats = redis.smembers(f"viewed_cats:{user.id}")
for cat in viewed_cats:
segments.append(f"interest:{cat}")
return segments
Rule Engine for Segment-to-Content Mapping
# personalization_rules.py
RULES = [
{
'id': 'email_promo_banner',
'segments': ['source:email'],
'content': {
'hero_banner': 'Your exclusive code: EMAIL20',
'cta_text': 'Claim 20% discount'
},
'priority': 100
},
{
'id': 'warm_lead_urgency',
'segments': ['lifecycle:warm_lead'],
'content': {
'hero_banner': 'You viewed {last_viewed_product} — only 3 left',
'floating_badge': 'Your cart is waiting'
},
'priority': 90
},
{
'id': 'customer_cross_sell',
'segments': ['lifecycle:customer'],
'content': {
'sidebar': 'recommended_for_customers',
'hero_banner': 'Welcome back! New items for you:'
},
'priority': 80
},
{
'id': 'mobile_simplified',
'segments': ['device:mobile'],
'content': {
'layout': 'mobile_first',
'show_phone_cta': True
},
'priority': 50
}
]
def get_personalized_content(segments: list[str]) -> dict:
matched = []
for rule in sorted(RULES, key=lambda r: r['priority'], reverse=True):
if all(s in segments for s in rule['segments']):
matched.append(rule)
break # Apply only first matching rule
if not matched:
return get_default_content()
return matched[0]['content']
Frontend Implementation with Personalization Slots
// PersonalizationSlot.jsx
function PersonalizationSlot({ slotId, fallback }) {
const [content, setContent] = useState(null)
const { segments } = useUserSegments()
useEffect(() => {
fetch('/api/personalization', {
method: 'POST',
body: JSON.stringify({ slot: slotId, segments })
})
.then(r => r.json())
.then(setContent)
}, [slotId, segments])
if (!content) return fallback || null
return <div dangerouslySetInnerHTML={{ __html: content.html }} />
}
// Usage
function HeroSection() {
return (
<section>
<PersonalizationSlot
slotId="hero_banner"
fallback={<DefaultHeroBanner />}
/>
</section>
)
}
Edge Personalization (No Delay)
// Cloudflare Worker: personalize HTML at Edge
addEventListener('fetch', event => {
event.respondWith(personalizeResponse(event.request))
})
async function personalizeResponse(request) {
const response = await fetch(request)
if (!response.headers.get('Content-Type')?.includes('text/html')) {
return response
}
const segments = getSegmentsFromCookies(request)
const content = getPersonalizedContent(segments)
const html = await response.text()
const personalized = html
.replace('{{hero_headline}}', content.hero_headline)
.replace('{{cta_text}}', content.cta_text)
return new Response(personalized, {
headers: response.headers,
status: response.status
})
}
Recommendation Engine
# Collaborative filtering for product recommendations
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
def get_recommendations(user_id, all_purchases, n=5):
# User × item matrix
users = list(all_purchases.keys())
items = list(set(item for purchases in all_purchases.values() for item in purchases))
matrix = np.zeros((len(users), len(items)))
for i, user in enumerate(users):
for item in all_purchases.get(user, []):
j = items.index(item)
matrix[i][j] = 1
# User similarities
user_idx = users.index(user_id)
similarities = cosine_similarity(matrix[user_idx:user_idx+1], matrix)[0]
# Weighted recommendations
scores = similarities @ matrix
scores[0][list(all_purchases.get(user_id, {}))] = 0 # exclude already bought
top_indices = scores[0].argsort()[-n:][::-1]
return [items[i] for i in top_indices]
Measuring Personalization Impact
def measure_personalization_impact(analytics_db):
# Compare conversion: personalized vs default content
results = analytics_db.query("""
SELECT
is_personalized,
COUNT(DISTINCT session_id) AS sessions,
SUM(converted) AS conversions,
ROUND(AVG(CAST(converted AS FLOAT)) * 100, 2) AS cvr,
ROUND(AVG(order_value), 0) AS avg_order_value
FROM sessions
WHERE date >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY is_personalized
""")
return results
Delivery Time
Implementing personalization system with segmentation, Rule Engine, and impact measurement — 5–10 business days.







