KIQA.DEV
Back to writing
AI
Jun 20, 2026
8 min read
by Kristian Gjergji

Why I chose OpenAI over Gemini for TravelMe's recommendations engine

I tested both models for two weeks. The answer wasn't about price. It came down to what happens when you tell the model someone has a dietary restriction.

When I started building TravelMe, I knew the core product lived or died on the quality of the AI recommendations. The model had to understand nuanced travel preferences, produce structured JSON reliably, handle ambiguous requests gracefully, and do all of this at a cost that made a consumer app viable.

I tested GPT-4o and Gemini 1.5 Pro seriously for two weeks. This is what I found.

The evaluation criteria

I evaluated both models across five things that matter specifically for TravelMe:

  1. 1.JSON output reliability: does it follow the schema consistently without requiring repair?
  2. 2.Instruction following: does it honour stated preferences (no tourist traps, specific budget, dietary restrictions)?
  3. 3.Specificity: does it give specific, useful suggestions or generic travel blog filler?
  4. 4.Handling ambiguity: what does it do when the user's request is vague or contradictory?
  5. 5.Cost per request: how much does a full itinerary generation cost at each price tier?

JSON reliability

Both models handle structured JSON output well when you use the dedicated JSON mode (OpenAI) or response MIME type setting (Gemini). Without these settings, both occasionally add markdown code fences around the JSON or include explanatory text before or after it, both of which break JSON.parse().

With the settings enabled, OpenAI's JSON mode was slightly more reliable in my tests, about 97% valid JSON vs 94% for Gemini with the same schema. The 3% failures in Gemini were mostly truncated responses for long itineraries (10+ days), which suggests a max-tokens issue rather than a fundamental problem.

Instruction following

This is where the tests got interesting. I created a standard test prompt: a 7-day trip to Italy for someone who explicitly hates touristy restaurants, has a €150/day budget, is vegetarian, and wants to see lesser-known areas.

GPT-4o followed all four constraints in every test run. No tourist traps, budget within range, all meals vegetarian, suggestions in non-obvious locations.

Gemini 1.5 Pro followed three out of four consistently. The vegetarian constraint was honoured in about 80% of runs. In the remaining 20%, meat dishes would appear in restaurant suggestions, sometimes flagged with a note ('can be made vegetarian on request') and sometimes not. For a travel app where dietary restrictions can be a safety concern (religious dietary laws, allergies), 80% is not good enough.

Specificity

Both models produce specific suggestions, but GPT-4o's suggestions felt more curated. Asking for Rome without the tourist trap filter would get the Colosseum and the Vatican from both, as expected. Applying the filter, GPT-4o suggested Quartiere Coppedè, the Protestant Cemetery in Testaccio, and a specific family-run osteria in Pigneto. Gemini suggested similar alternatives but stayed closer to the well-known neighbourhoods.

This is partly about training data and partly about how the model interprets 'avoid tourist traps'. For TravelMe, where differentiation lives in exactly this kind of local knowledge, the difference matters.

Cost

Gemini 1.5 Pro is significantly cheaper. At the time of testing, a full 7-day itinerary generation was costing approximately:

  • GPT-4o: ~$0.04–0.07 per generation (depending on itinerary length)
  • Gemini 1.5 Pro: ~$0.01–0.02 per generation
  • GPT-4o-mini: ~$0.003–0.006 per generation (quality noticeably lower)

For a freemium app where free-tier users get a limited number of generations per month, GPT-4o is affordable. For a high-volume app with many free users, the cost difference would be significant.

The decision

I went with GPT-4o for TravelMe's initial launch. The instruction-following reliability was the deciding factor, specifically the dietary restriction handling. Travel planning is a domain where getting someone's preferences wrong has real consequences, not just a slightly off playlist recommendation.

The cost difference is real, and I'll revisit Gemini once Google addresses the instruction-following consistency. I'm not permanently committed to OpenAI. The model layer in TravelMe's backend is intentionally abstracted so I can swap providers without changing the app.

typescript
// Provider-agnostic interface in TravelMe's backend
interface TravelPlannerModel {
  generateItinerary(prompt: string): Promise<TravelPlan>;
}

// Easy to swap: OpenAI today, Gemini tomorrow
class OpenAITravelPlanner implements TravelPlannerModel {
  async generateItinerary(prompt: string): Promise<TravelPlan> {
    // GPT-4o implementation
  }
}

class GeminiTravelPlanner implements TravelPlannerModel {
  async generateItinerary(prompt: string): Promise<TravelPlan> {
    // Gemini implementation, ready when needed
  }
}
🧠

Abstract your AI provider from day one. The model landscape is changing fast, what's best today may not be best in six months. Keeping the interface clean means you can switch without rewriting your whole application.

Written by

Kristian Gjergji

Developer · Kosovo / Italy

Work with me →
Chat on WhatsApp