How this works
Every change on the list comes from Qloo's taste data. The model only talks; it never picks a place or a reason.
1. The default list
A stand-in for the hotel's own list: Qloo Insights for places in the city, with no taste signal.
GET /v2/insights?filter.type=urn:entity:place&filter.location.query=London&filter.tags=urn:tag:genre:place:restaurant&take=50
That tag also returns hotels, department stores, arenas and fast-food chains. A concierge doesn't hand those out, so both lists keep only sit-down food and drink by Qloo's primary_genre (restaurants, bars, pubs, cafés; no fast food, burger, ice-cream or donut shops, delivery or food courts) and drop anything at an airport or more than 25 km from the city centre (for New York, Qloo is asked for “New York City”). Well-known chains (Hard Rock Cafe, PizzaExpress, Starbucks and similar, a fixed list in the code) are dropped too. The top 10 that remain are the default list.
1b. Or the hotel's own list
Under “Your guest (and list)” a concierge can paste the hotel's own list, up to 10 lines. Each line is looked up with GET /search?types=urn:entity:place and matched to a restaurant or bar within 25 km, on whole words, never for lines like “Our rooftop bar” (same dining filter as above, except that chains the hotel lists itself are kept): an exact name first, then a place whose name contains the line (“Dishoom” → “Dishoom King's Cross”), then a place whose name the line contains (when Qloo's search returns that shorter name). Lines that start with “our”, “my”, “hotel's” or “in-house” name the hotel's own places and are not looked up. The screen says “listed as ‘Dishoom’”. Lines that don't match stay on the list as typed, marked “not matched”, and are never struck; a line naming a place already on the list is skipped and shown as a repeat.
2. The guest
Up to three favourites (a band, show, film, brand or game), found with GET /search. If a name matches more than one thing, it asks. The one exception: when a single exact match has Qloo popularity of at least 0.9 and every other exact match is at least 0.15 lower (“Succession” the show, not the film), it takes it and shows its type on the list, so you can see what it used.
3. The guest's taste matches
The same query with the guest's favourites as the signal and explainability switched on:
…&signal.interests.entities=<ids>&feature.explainability=true&take=50
4. The edit (deterministic)
- Struck: list entries that are not in the guest's top 50, the ones this guest's taste likes least first (Qloo's affinity for exactly the places on the list, via
filter.results.entities; places Qloo gives no score come after all scored ones, lowest on the list first), at most as many as “Lines that may change” (3, 5 or 10). - Inserted: the guest's best matches that aren't on the list yet, one per struck entry, in Qloo's order.
- Same level as the list (restaurants & bars): the list's level is the median of Qloo's price level (1 to 4) of its entries, when at least three have one. The guest's matches are then asked for at that level or above (
filter.price_level.min), and on a list at level 3 or above no pub, Irish pub or sports bar is inserted. Theme venues (Qloo decor tag “Themed”) and a fixed list of chains are never inserted. - Kept: everything else, unmarked. If the guest has fewer new matches than the budget, fewer things change. The list is never padded.
- Notes: for an insert, the favourite with the highest explainability score for that place (both names when they are within 0.1), then up to three of the place's own Qloo tags (its first interest tag, its first ambience tag that isn't a generic one such as “casual”, and “late night” when Qloo lists it) and the neighbourhood. For a strike: its rank by this guest's taste affinity among the list's places (“Lowest taste affinity on this list for this guest”), or “Not among this guest's top 50 taste matches” when Qloo gave it no score. The small bar under each note is Qloo's taste affinity of this guest for that place (0 to 1).
Same guest, same city, same budget: same list.
5. The agent
“Ask the agent” runs a Google ADK agent (Claude via LiteLLM) with five tools: resolve_interest, default_list, taste_places, edit_list, explain_place. It reads the favourites out of free text, asks when a name is unclear and returns the same edited list as the form, on the hotel's own list if one is pasted. Its tool calls are shown under the result; its sentence is checked on the server and replaced by a plain summary if it names a number the tools didn't return or compares the list to anything. The same capability is an MCP tool at https://your-kind-of-place-api-588508999301.us-east1.run.app/mcp/: edit_hotel_list(city, interests[], budget, hotel_list[]).
6. Tomorrow's arrivals
Under “Arrivals → morning report” a concierge pastes up to six arrival notes as the front desk or CRM wrote them. A second ADK agent reads them and calls record_guest once per note with up to three favourites. The server keeps a favourite only if it is literally written in that note and not negated in the same clause (“hates Coldplay”), then resolves each in Qloo. Without the agent (“Skip the agent”, or if it fails) the concierge types favourites per guest. The concierge confirms or removes every favourite (and picks when a name is ambiguous); only then is each guest's list edited with the same rules as above, on the hotel's own list if one was pasted. The morning report shows each guest's full list and can be copied or printed.
What we measured
A blind test with 12 pairs of opposite guests in San Francisco, Austin and London, first on 25 October 2026 and again on 30 October with the price-level rule the product uses:
| Blind matching | A separate model saw two lists and two guest profiles, with no hint of Qloo, and matched them correctly in 10 of 12 cases (11 of 12 without the price-level rule). |
|---|---|
| Stability | The same queries 14 minutes later overlapped 0.99 on average. |
| Default vs. taste | A guest's list and the list with no taste signal overlapped 0.12 on average: the default list gets rewritten a lot. |
The 10 of 12 run used the product's dining filter and price-level rule; the first run (11 of 12) used the restaurant-tag query without them. Stability and overlap are from the first run. The judge was a language model, not a person; 12 cases is a small sample, and the profiles were deliberately opposite.
Which kinds of place we offer, and why only these
Before adding a category we ran the same blind test on it (written down before the run: 12 pairs of opposite guests in San Francisco, Austin and London, a separate model matching two lists to two guests without knowing about Qloo, pass at 10 of 12 or better; a list with fewer than 8 places counts as a miss). Only what passes goes into the product; every result, passed or not, is listed here.
| Restaurants & bars | 10 of 12 with the price-level rule (11 of 12 without the price-level rule) — offered, and the demo path |
|---|---|
| Live music & nightlife | 10 of 12 — offered under “Your guest (and list)” and “Morning report”. Right on the line. |
| Daytime: museums & galleries | 10 of 12 — passed, but not offered: right on the line, with low judge confidence (2.4 of 5), and two opposite guests shared most museums (overlap 0.78), so the edit changed little. |
| Daytime: parks & gardens | 8 of 12 — not offered: two opposite guests got largely the same parks. |
| Daytime: cafés | 5 of 12 — not offered: too few cafés in 3 cases, and the rest hard to tell apart. |
| Daytime: spa & wellness | 4 of 12 — not offered: under the spa tag Qloo mostly returns hotels, so 8 of 12 lists were too short. |
| Shops | 9 of 12 — not offered: two opposite guests got largely the same shops. |
| Sights & attractions | 3 of 12 — not offered: with a guest's taste, Qloo's attraction tag drifts to hotels and arcades, and in 6 of 12 cases too few real sights were left. |
The nightlife test kept everything Qloo files under live music and night clubs except hotels. The product is stricter: it keeps venues, clubs, bars and pubs only, and in every category drops adult venues (by Qloo genre, tag or place description).
Toronto and Montreal (the client demo)
The client demo shows a fictional hotel, Montreonto, with one house in Toronto and one in Montreal. Before it used these two cities, both passed a smoke test (10 places each, all with a neighbourhood; the house list's price level is 2) and the same blind test, written down before the run: 12 pairs of opposite guests with Canadian favourites, 6 per city, restaurants & bars at the house list's price level. The separate model matched 12 of 12. The two sample guests per city are the test pair whose guests share the fewest additions (none), picked by a rule written down before the run. The same limits apply: opposite guests, a language model as judge, 12 cases. The test covered restaurants & bars; the “After dark” tab (live music & nightlife) was not tested in these two cities, and in Montreal it changes little (0 and 1 of 10 for the two sample guests).
What we don't claim
Fits this guest, not 'better'. Even similar tastes get different lists, so we don't claim anything about similar guests.
The examples in the app are opposite guests, one after the other or side by side under “Compare”.
Accept and reject are only kept on your screen. Demo guests may be answered from saved Qloo results and are marked “cached result”. Notes are aggregate taste affinity from Qloo, not reviews.
Coming next
Pick the right branch when a name matches several (today the first one in town is taken and shown).