Inspiration
Before a show goes on sale, a promoter's advance team makes five calls: where to play, who opens, which room, where the after-party is, and who sponsors. Today those come from ticket history (which only exists where you have already played) and a genre chart (which ranks what is popular, not what this audience loves). The taste of the actual fans is the missing input, and that is what Qloo's graph holds.
What it does
Type one sentence, such as "Phoebe Bridgers in Chicago and Denver" or "Metallica in Berlin and Munich, Germany". Advance returns a booking brief:
- Where to play: markets whose audience over-indexes on the headliner, big enough to draw a room, with the state named and Qloo's market-size index beside the taste score.
- Who opens: artists the same audience loves, capped below the headliner's popularity.
- Two room lists per city: Most-booked rooms (the city's most-played rooms, no taste signal) and Which room (what these fans favour, reordered by what stands out for this act against a panel of five unlike acts). Every line carries address, phone, the room's own website and a room-feel cue from Qloo reviews.
- After the show: bars, cocktail bars and clubs the fans pick within 3 km of the most-booked room.
- Who sponsors: brands with audience affinity.
- Tour routing: your cities and the best markets joined into the shortest order by OSRM road time, drawn on a map, with road distance and driving time per leg and a fly advisory past 12 hours.
- A downloadable promoter brief (Markdown): notes, routing, every list with contacts, what is not covered, and next booking actions.
Every line shows Qloo's score and the exact request behind it.
How we built it
An agent with three steps, each labelled on the page:
- Plan: Apertus 70B (Swiss open model via Public AI) fills a JSON schema: headliner, up to three cities, country, how small an opener may be.
- Ask Qloo: one /v2/insights call per question, through a client that refuses any parameter not on a per-entity-type allow-list (Qloo ignores unknown parameters silently, and a silently ignored filter is a wrong answer that looks right).
- Advise: the model writes up to three recommendations from a schema whose enum contains only names Qloo returned, so it cannot recommend anything that is not in the brief.
If the model is unavailable, a pattern planner and a template take over and the page says so. Python standard library only, 40+ tests on two Python versions, deployed on Render, open source (MIT).
Does it work? Three tests, one of them against us
1. Support acts: taste beats an LLM. 115 real tours (2023-2025) with their support acts from Wikipedia; each method gets only the headliner. 113 tours are scored (2 headliners Qloo cannot find); 619 real openers exist in Qloo.
| real openers found | Qloo taste | LLM alone (Apertus 70B) | genre chart |
|---|---|---|---|
| in the top 10 | 26 | 21 | 1 |
| in the top 25 | 48 | 32 | 4 |
| in the top 100 | 109 | 37 | 17 |
Taste finds at least one real opener in its top 100 in 61 of 113 tours, the LLM in 22; it beats the LLM in 49 tours, loses in 8 and ties in 56 (48 of them both find none). Recall is 17.6%, and the LLM is better at the very top (median rank 9 against 31) on tours that are on Wikipedia. There is no separate holdout: it is a retrospective test (docs/METHOD.md).
2. Rooms: taste loses to popularity, so Advance shows both. 417 US tour stops from 107 real tours: is the room the tour actually played in the first 8 of the list? The city's most-played rooms: 50%. Qloo's taste list for the headliner: 37%. Popular rooms ordered by taste: 42%. Matching room kind to headliner size does not rescue taste (52% sized, 50% with taste). Taste adds 7 hits the popular list misses and loses 58. So the brief gives the better predictor of where tours play (most-booked) and, separately, what these fans favour (docs/VENUE_BACKTEST.md, VENUE_CASES.md for 20 random cases, VENUE_SIZE_MATCH.md).
3. Audits you can rerun. Top rooms of 15 briefs: 12 of 15 pass city, website and show-wording checks, and the audit lists what is still wrong (an opera house first for one act; two rooms in suburbs) (VENUE_AUDIT.md). Re-ordering by what stands out for the act raised distinct top rooms from 7 to 11 of 15; the first room is unchanged under a different comparison panel in 11 to 12 of 15 briefs (PANEL_SENSITIVITY.md). After-show places anchored on the room: 27 of 30 pass distance, website and drinks checks (AFTERSHOW_AUDIT.md). Sponsors are not validated: public data that lets a third party verify audience alignment was not found.
All Qloo and model responses are recorded, so the backtests replay offline from the repo.
Challenges we ran into
Five places where the data or the API fails quietly, each now guarded by a test:
- take above 50 is a 400, so Advance pages.
- /search names a genre urn:tag:genre:pop_rock, but /v2/insights only honours urn:tag:genre:music:pop_rock; the first returns an empty 200 (our genre baseline scored zero until we found it).
- Place insights without a category return airports and skyscrapers, so venue and bar categories.
- The bar category also tags hotel lobbies, campgrounds, galleries and landmarks, so filter.exclude.tags.
- Ranking by affinity alone is not a booking list: our first live brief put Bar Harbor and Williamstown above Boston, because Qloo scores affinity, not market size. We found it by reading the output as a promoter would.
Accomplishments that we're proud of
Tests that could have shown taste losing. On support acts it wins; on rooms it loses to popularity, and we changed the product to show both instead of hiding it. Every number above is reproducible from the repo.
What we learned
Taste data is strongest where general knowledge runs out: the 20th to 100th name, the opener who is not the obvious one. For rooms, tours book big familiar buildings, and taste is the signal for which room suits these fans, not for which room is booked.
What's next
Venue capacity and availability (Qloo does not hold them), a metro-population signal kept beside affinity, and a case-by-case study of rooms the taste list finds that the popular list misses, which is where Qloo adds something.
Built With
- apertus
- html5
- javascript
- python
- qloo
- render