For judges, in 30 seconds
- Qloo use: an agent calls Search, Insights and Tags (8–14 calls per plan) and crosses a game's or book's audience into podcasts, artists, TV, books, movies and brands.
- Grounding: every name in the plan must appear in a Qloo result of the right kind. The server removes and lists anything that doesn't (
checkReport). - For whom: about 19,000 games launched on Steam in 2025, and nearly half got fewer than 10 reviews. Solo creators can't buy audience research.
- Try it: no login, and four finished plans load instantly. Start with "Fishing horror on a small budget".
Inspiration
Indie game developers and self-published authors launch with a small budget and a big question: who is this actually for, and where do those people spend their time? Publishers answer it with "comps" (comparable titles) and paid audience research. A solo developer usually guesses. On Steam alone about 19,000 games launched in 2025, and nearly half got fewer than 10 reviews (SteamDB, via GamingOnLinux). They post in their own genre's subreddit, sponsor the podcast everyone in that genre already sponsors, and the budget is gone. I sell game assets on itch.io and I'm making my own game, so this is a tool I need myself.
The useful answer is cross-domain. Fans of Stardew Valley don't only play farming games. What do they listen to, watch and read? That is exactly what Qloo's taste graph models, and it's the part a creator can't find by searching their own genre.
What it does
You describe your game or book in a sentence or two and, optionally, name a few titles it feels like. Comps returns a launch plan:
- Who this is for: a short audience summary, written from the evidence.
- Comparable titles: titles Qloo's Insights links to your comps, plus your own titles where the plan uses them. Each is labelled "your title" or "found by Qloo".
- Where to reach them: 2–4 picks in each domain Qloo returns (podcasts, artists, TV shows, books, movies, brands). Each pick shows its Qloo affinity and popularity, and suggests what to do with it (pitch a guest segment, reference it in ads, and so on). In small-budget mode for a DREDGE-like fishing horror game, Qloo points to Deck of Friendship! (popularity 0.39), The Insert Credit Show (0.56) and the artist Dedf1sh (0.39). These are names a small team can email, and none of them appears in the model-alone list.
- Positioning: themes and tags the audience responds to.
- Our interpretation: taglines and campaign ideas, clearly labelled "not Qloo data".
- What this does not tell you: the limits of the data, plus each item the server removed and the reason.
Three features make the plan trustworthy and usable:
- Every pick has its receipt. Each line cites an evidence id (E1, E2, …). Click it and a drawer shows the query the agent sent to Qloo (type, signal entities by name, filters) and every result Qloo returned with its affinity and popularity, with the pick highlighted.
- Small-budget mode. It caps Qloo popularity at 0.7 for podcasts, artists, TV, movies and brands, so the plan points at less mainstream names, the kind a small team has a chance of contacting, not the biggest show in each category.
- "What Qloo adds". The plan sits next to what the same model suggests for the same pitch with no data: what only Qloo found, what both found, and what the model alone guessed. The finished plans show it already; on a new plan, press Compare with a model alone. In the fishing-horror sample, Qloo's 13 picks and the model's 24 share no names. The data adds different channels, not just the same ones with a citation. (The no-data model isn't told about the small budget, so in that mode part of the gap is the popularity cap.)
The landing page has four finished plans (a cozy farming game, a fishing-horror game on a small budget, a poker roguelike and a cozy fantasy novel), so a judge can explore results without waiting.
How we built it
Qloo workflows
| Tool the agent calls | Qloo endpoint | Why |
|---|---|---|
qloo_search |
GET /search (types=urn:entity:videogame or book) |
Resolve the creator's comps to Qloo entity ids. |
qloo_insights |
GET /v2/insights with filter.type + signal.interests.entities or signal.interests.tags (and filter.popularity.max in small-budget mode) |
The core step: what the comps' audience also likes in other domains. |
qloo_tags |
GET /v2/tags with filter.query |
Turn a theme from the pitch ("cozy", "roguelike") into a tag signal. |
The agent is a two-step loop on OpenAI gpt-4.1, using raw HTTP function calling with no framework.
- Research. The model decides which comps to resolve and which domains to query. When a query comes back empty, the tool result tells the model so, and it tries another comp or domain instead of guessing. In the novel sample, five empty domains were re-queried with other comps and returned results. A typical run makes 8–14 Qloo calls.
- Report. The model writes the plan as strict JSON-schema output, and every item must cite evidence ids.
Provenance by construction. The server records every Qloo call as an evidence record. After the model writes the plan, a deterministic check (checkReport) runs over it:
- A channel must be an entity returned by an Insights query for that same domain. A podcast has to come from a podcast query.
- A comp must come from an Insights query seeded by comp entities, or be a title the creator typed. A search hit alone only proves the title exists, and a tag-only query doesn't count.
- A positioning point must name an entity or tag that appears in the evidence.
Items that fail are removed and listed, with the reason, at the end of the plan. If the name is in a qualifying record but the model cited another record or a raw Qloo id, the citation is pointed at the record that contains it, and the plan says how many were corrected. The walkthrough below shows one item the check removed.
Stack
- React + Vite front end; Node/TypeScript API on Vercel functions.
- Upstash Redis holds the cached results and the sample plans. Qloo responses are not committed to the repo.
- 10 unit tests cover the evidence check, the Qloo response parser, input validation, the mock client and the judging-window allowance.
- Keys stay server-side and results are cached. New runs are rate limited, with a daily allowance and a spend budget that are raised during judging. When either runs out, the page says live runs are paused, and the four finished plans stay available.
Challenges we ran into
- Models cite loosely. Even gpt-4.1 sometimes puts the right name under the wrong evidence id, or cites a raw Qloo entity id instead of an evidence id. We first dropped those items. Now "not in the data" is dropped with its reason, "in the data, cited wrong" is corrected and counted, and a raw id sitting next to a valid evidence id is simply removed from the citation list.
- A search hit is not an audience signal. A search for "Stardew Valley" returns twenty games with "Valley" in the name. Treating search results as evidence let lookalike titles through. The check now tells search records apart from Insights records.
- Is the surprise real? Cozy-game fans scoring high on horror audio dramas could have been a default list Qloo returns for any game. We checked by seeding the same podcast query with other games (
scripts/seed-check.tsreruns it):- DOOM Eternal and Call of Duty: Black Ops 6 return gaming-news podcasts (Nintendo Voice Chat, Giant Bombcast, Podcast Beyond - IGN's PlayStation Show).
- Stardew Valley + A Short Hike return The Magnus Archives, Welcome to Night Vale and Archive 81.
- The Sims 4 alone also returns horror shows (Creepy, The NoSleep Podcast, The Magnus Archives).
So the list depends on the seed. It is one query per seed, and the shows are all popular (0.94+), so it shows the overlap exists, not why.
- Mainstream skew. Default results are mostly at popularity 0.85–1.0, so the default plan names the biggest show in each category. Small-budget mode caps popularity at 0.7 (books and games are not capped). In the sample, its picks run from 0.1 to 0.7.
Accomplishments that we're proud of
- A plan a creator can audit line by line. Every name in it traces back to a specific Qloo request.
- Cross-domain findings a creator wouldn't reach by searching their own genre, with the evidence one click away.
- An honest comparison with a model that has no data, shown in the product rather than claimed in this write-up.
What we learned
- Qloo is most useful across domains. In the same domain it mostly confirms what a creator already knows.
- Grounding has to be enforced in code. A prompt that says "only cite evidence" isn't enough.
- Popularity is a lever, not noise. In our small-budget sample the useful picks sat below 0.7, well under the 0.9+ of the default plan.
What's next for Comps
- Refining a plan ("skew older", "less mainstream", "more US") by re-querying with Qloo demographic and location signals.
- Exporting the plan as a checklist with contact research for each pick.
- More media types for authors (newsletters, BookTok creators) as Qloo coverage allows.
How a result becomes a line (walkthrough)
From the "Cozy lighthouse farming game" sample. Live API, 10 Qloo calls, entity ids redacted.
- Input. Pitch: a cozy farming game about keeping a lighthouse running on a small island. Comps: Stardew Valley, A Short Hike.
- Search.
GET /searchfor each comp (E1, E2). The agent picks the matchingurn:entity:videogameentities. - Insights. Six
GET /v2/insightscalls seeded with both entities, one per domain: books, movies, TV, podcasts, artists and brands (E3–E8). - Tags.
GET /v2/tags?filter.query=cozy(E9), then an Insights call for videogames with that tag (E10). - One result → one line. The podcast query (E6) returns The Magnus Archives with affinity 0.96. The plan's podcast line reads "The Magnus Archives: pitch for sponsorship or a guest segment …" and cites E6. The check confirms the name is in E6 and that E6 is a podcast query.
- Removed. The model proposed Monument Valley as a comp. Its only citation was the Stardew Valley search (E1), which returns twenty games with "Valley" in the name. It also proposed NieR: Automata, from the tag-only query (E10). Neither came from an Insights query seeded by the comps, so both were dropped and listed with that reason.
Limitations: what a result does not establish
- Qloo affinities describe what groups of people tend to like. They don't predict what any individual will do, and they are not a sales or conversion forecast.
- Very small indie titles may not be in Qloo's graph. The plan then rests on larger comps, which pull it toward a more mainstream audience.
- The prose around each pick (why, what to do) and the "interpretation" section are written by the model. Only the names are checked against Qloo data.
- The comparison model gets the same pitch but no budget instruction, so in small-budget mode the gap between the two columns is wider than the data alone explains.
- No personal data is sent to Qloo: only titles, themes and entity ids.
Testing instructions
No login needed. Open https://comps-three-pi.vercel.app and pick any finished plan, or press Build my launch plan with the prefilled pitch (it is answered from the cached sample at once). Then:
- Click any evidence chip (E1, E6, …) to see the Qloo query and its results.
- Open "Fishing horror on a small budget" to see small-budget mode: lower popularity on every pick.
- Scroll to the end of the "Cozy lighthouse farming game" plan to see what was removed and why.
- "What Qloo adds" shows the no-data comparison; on a new plan, press Compare with a model alone.
A new pitch runs live, with Qloo plus gpt-4.1. It takes about 30–60 seconds and is subject to the demo's daily allowance.
To run locally:
# Node.js 22.18 or newer
git clone https://github.com/tsang326/comps.git && cd comps
npm ci --ignore-scripts
npm test
cp .env.example .env # OPENAI_API_KEY, QLOO_API_KEY, QLOO_MODE=live
npm start # web on http://localhost:5173, API on :3001
Built With
- node.js
- openai
- qloo
- react
- typescript
- upstash-redis
- vercel
- vite
- zod
Log in or sign up for Devpost to join the conversation.