AI Hotel Guest Experience Personalization System
Personalization in hospitality ranges from pillow preferences to menu predictions. Hilton and Marriott use AI to load guest profiles before arrival, auto-configure rooms, and proactively offer services. Result: +15-20% to RevPAR (Revenue Per Available Room) and NPS gains of +12-18 points.
Guest Profile and Pre-Arrival Personalization
import pandas as pd
import numpy as np
from anthropic import Anthropic
import json
class GuestProfileManager:
"""Managing guest profiles from all data sources"""
def build_unified_profile(self, guest_id: str,
booking_history: pd.DataFrame,
feedback_data: pd.DataFrame,
crm_data: dict) -> dict:
"""Unified profile from history, reviews, and CRM"""
guest_stays = booking_history[booking_history['guest_id'] == guest_id]
if guest_stays.empty:
return {'guest_id': guest_id, 'is_new_guest': True}
# Preferences from history
profile = {
'guest_id': guest_id,
'is_new_guest': False,
'total_stays': len(guest_stays),
'avg_spend_per_night': guest_stays['revenue_per_night'].mean(),
# Room preferences
'preferred_room_type': guest_stays['room_type'].mode().iloc[0] if len(guest_stays) > 0 else 'standard',
'preferred_floor': self._infer_floor_preference(guest_stays),
'prefers_high_floor': (guest_stays['floor'] > 5).mean() > 0.6,
'prefers_quiet_room': guest_stays.get('quiet_room_requested', pd.Series([False])).mean() > 0.5,
# Food & beverage preferences
'preferred_breakfast': guest_stays.get('breakfast_option', pd.Series(['buffet'])).mode().iloc[0],
'dietary_restrictions': crm_data.get('dietary', []),
'avg_restaurant_spend': guest_stays.get('f_and_b_spend', pd.Series([0])).mean(),
# Additional services
'typically_uses_spa': guest_stays.get('spa_used', pd.Series([False])).mean() > 0.4,
'typically_uses_gym': guest_stays.get('gym_visits', pd.Series([0])).mean() > 0.5,
'late_checkout_history': guest_stays.get('late_checkout', pd.Series([False])).mean() > 0.3,
# Behavioral profile
'travel_purpose': self._infer_travel_purpose(guest_stays, crm_data),
'loyalty_tier': crm_data.get('loyalty_tier', 'standard'),
}
# Analyze feedback for patterns
guest_feedback = feedback_data[feedback_data['guest_id'] == guest_id]
if not guest_feedback.empty:
profile['sentiment_themes'] = self._extract_sentiment_themes(guest_feedback)
return profile
def _infer_floor_preference(self, stays: pd.DataFrame) -> str:
if 'floor' not in stays.columns:
return 'no_preference'
avg_floor = stays['floor'].mean()
if avg_floor > 8:
return 'high'
elif avg_floor < 3:
return 'low'
return 'mid'
def _infer_travel_purpose(self, stays: pd.DataFrame, crm: dict) -> str:
if crm.get('company_name'):
return 'business'
# By check-in day: Fri-Sun = leisure, Mon-Thu = business
if 'checkin_weekday' in stays.columns:
weekend_ratio = stays['checkin_weekday'].isin([4, 5, 6]).mean()
return 'leisure' if weekend_ratio > 0.6 else 'business'
return 'mixed'
def _extract_sentiment_themes(self, feedback: pd.DataFrame) -> list[str]:
positive_reviews = feedback[feedback['rating'] >= 4]['text'].tolist()
themes = []
# Simplified theme extraction - in production: NLP topic modeling
keywords = {'bed': 'comfortable_bed', 'pool': 'pool_lover', 'service': 'service_focused',
'quiet': 'prefers_quiet', 'breakfast': 'breakfast_fan'}
for review in positive_reviews[:10]:
for kw, theme in keywords.items():
if kw in review.lower() and theme not in themes:
themes.append(theme)
return themes[:5]
class PreArrivalPersonalizer:
"""Pre-arrival personalization"""
def __init__(self):
self.llm = Anthropic()
def prepare_room_settings(self, guest_profile: dict,
available_rooms: list[dict]) -> dict:
"""Prepare room according to guest preferences"""
preferred_type = guest_profile.get('preferred_room_type', 'standard')
prefers_high = guest_profile.get('prefers_high_floor', False)
prefers_quiet = guest_profile.get('prefers_quiet_room', False)
# Select best available room
scored_rooms = []
for room in available_rooms:
score = 0
if room.get('type') == preferred_type:
score += 3
if prefers_high and room.get('floor', 0) > 5:
score += 2
if prefers_quiet and room.get('wing') == 'quiet':
score += 2
# Loyal guests get upgrade consideration
if guest_profile.get('loyalty_tier') in ['gold', 'platinum']:
if room.get('is_upgrade_eligible'):
score += 1
scored_rooms.append({**room, 'score': score})
best_room = max(scored_rooms, key=lambda x: x['score']) if scored_rooms else {}
# Room setup before arrival
room_setup = {
'room_number': best_room.get('number'),
'temperature_c': 21 if guest_profile.get('travel_purpose') == 'business' else 22,
'pillow_type': 'firm' if 'comfortable_bed' not in guest_profile.get('sentiment_themes', []) else 'soft',
'welcome_amenities': self._select_amenities(guest_profile),
'minibar_stocked': guest_profile.get('avg_spend_per_night', 0) > 150,
}
return room_setup
def _select_amenities(self, profile: dict) -> list[str]:
amenities = ['welcome_card']
if profile.get('total_stays', 0) > 5:
amenities.append('loyalty_gift')
if profile.get('travel_purpose') == 'business':
amenities.extend(['bottled_water', 'charging_station'])
if profile.get('typically_uses_spa'):
amenities.append('spa_welcome_kit')
return amenities
def generate_pre_arrival_email(self, guest_profile: dict,
booking: dict) -> str:
"""Personalized pre-arrival email"""
response = self.llm.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=300,
messages=[{
"role": "user",
"content": f"""Write a personalized pre-arrival email for a hotel guest.
Guest: {guest_profile.get('total_stays', 0)} previous stays, {guest_profile.get('loyalty_tier')} member
Travel purpose: {guest_profile.get('travel_purpose', 'leisure')}
Arrives: {booking.get('checkin_date', 'soon')}
Special preferences: {guest_profile.get('sentiment_themes', [])}
Include:
1. Warm personalized welcome (mention loyalty status if gold/platinum)
2. One specific upgrade or perk based on their profile
3. 2 relevant offers (spa/restaurant/local experiences)
4. Check-in info (online check-in available)
Avoid generic phrases. Be specific and genuine. 150-200 words."""
}]
)
return response.content[0].text
class DynamicRevenueOptimizer:
"""Revenue management with AI personalization"""
def calculate_personalized_rate(self, guest_profile: dict,
base_rate: float,
hotel_occupancy: float) -> dict:
"""Personalized rate based on guest value"""
# Loyal guests get discounts
loyalty_discount = {
'standard': 0.0,
'silver': 0.05,
'gold': 0.10,
'platinum': 0.15
}.get(guest_profile.get('loyalty_tier', 'standard'), 0.0)
# Dynamic occupancy multiplier
if hotel_occupancy > 0.85:
occupancy_multiplier = 1.2
elif hotel_occupancy > 0.70:
occupancy_multiplier = 1.0
else:
occupancy_multiplier = 0.9
final_rate = base_rate * occupancy_multiplier * (1 - loyalty_discount)
return {
'base_rate': base_rate,
'personalized_rate': round(final_rate, 2),
'loyalty_savings': round(base_rate * loyalty_discount, 2),
'rate_type': 'member_rate' if loyalty_discount > 0 else 'standard'
}
Experience personalization works best for repeat guests (30%+ of luxury segment base). The system pays for itself through upsells: spa, restaurants, room upgrades. Average incremental revenue from personalized guests: +$45-80 per night versus standard stays.







