May 16, 2026 · 7 min read · Use cases
Recommendation engines and the destination cold-start problem.
Every travel recommendation product starts with no users, no clicks, and no signal. The cold-start problem is real. The fix isn't to wait for clickstream — it's to ship destinations that are objectively worth visiting and the user can actually enter.
Why classical collaborative filtering fails on day one
Collaborative filtering needs co-occurrence. "Users who liked Tokyo also liked Kyoto." That works once you have a million sessions. On day one you have zero. So the cold-start fallback is "popular destinations" — which, in practice, means Paris, Tokyo, New York, Bali, on repeat, for everyone.
For a travel product, "popular" is a worse signal than "good and reachable." A user in Dhaka being recommended Paris is being recommended a 90-day visa wait. A user in Chicago being told "consider Pyongyang" is being trolled. The cold-start defaults are bad for a structural reason: they ignore the two filters that matter most, quality and access.
The two-call cold-start pattern
Bootstrap recommendations from two endpoints. Quality first, then intersect with visa eligibility for the user's passport.
GET https://api.travelminds.ai/v1/cities?min_score=70&limit=200
Authorization: Bearer YOUR_KEY
{
"cities": [
{"name": "Lisbon", "iso_alpha2": "PT", "master_score": 86,
"tier": "A", "narrative": "Atlantic capital, mild..."},
{"name": "Hanoi", "iso_alpha2": "VN", "master_score": 84, ...},
{"name": "Mexico City","iso_alpha2": "MX","master_score": 83, ...}
]
}
Then filter by what the user's passport can actually enter:
GET https://api.travelminds.ai/v1/visa?passport=IN
{
"passport": "IN",
"visa_free": ["BT","NP","MV","TH","ID","MY", ...],
"visa_on_arrival": ["LK","KH","LA", ...],
"e_visa": ["VN","KE","RW", ...]
}
Server-side, intersect the two lists. The result is a starter feed of destinations that are (a) high-quality by an absolute score and (b) actually reachable for this user. No clickstream needed. No "popular in your country" generic feed.
Personalize as signal accumulates
Once users do click, swipe, save, or book, the cold-start filter becomes a re-ranker rather than the only ranker. But you'll find you keep the score floor and the visa intersection forever — they are filters, not preferences. A user being shown a destination they can't enter is a UX failure regardless of personalization.
Two practical refinements
First: add a flight-time band. A user in Singapore might want "good destinations within 5 hours." Once you have the candidate set, intersect with a flight-distance filter you compute from lat/lon. The lat/lon comes back on every city record.
Second: weight by season. Hanoi in February is excellent, Hanoi in July is wet. Pass the user's planned travel month into a second-stage re-rank that uses the city's narrative or your own seasonal logic. The score is an average; the narrative often tells you when the average doesn't apply.
Why this works for AI products specifically
Chatbot and AI-recommendation products have a specific failure mode the classical recommender doesn't: confidently suggesting destinations that don't fit the user's reality. Visa filtering fixes one slice of that. Score filtering fixes another. Combining the two, server-side, before the model writes anything, means the model is constrained to a candidate set that already makes sense.
Free tier covers 1,000 calls a month. That's enough to build a full cold-start pipeline and stress-test it before committing to a paid plan.