Inspiration
Every minor-league and mid-market club has an emptiest Tuesday. Promotions teams fill those weeknights with theme nights, and they plan dozens of them each off-season, usually from the same list every other club uses.
Whether a night actually sells comes down to taste. Does our city love this more than other markets? Do those fans live near our ballpark? Does it fit Tuesday's crowd? Which sponsor shares that audience? An LLM on its own can't answer any of these: it suggests the same Star Wars Night for Durham and for Los Angeles. Qloo can answer every one of them, so we built an agent that asks.
What it does
Theme Night GM is an AI promotions agent. You give it your club, market, venue and home schedule. It picks the weak dates, gives each one a target crowd (families, Gen Z, young pros or 55+), and works like a promotions GM:
- Read the room: which movies, TV shows, artists, video games and books does this city over-index on compared with national popularity?
- Size the fandom: who are the fans, is interest rising, and where around the venue do they live?
- Fit the audience: which fandom fits each date's crowd, and does it bring new fans?
- Build the night: sponsors in the club's own sales categories, an in-game playlist, partner places within 6 km, a podcast media partner.
- Ship it with receipts: every pick traces back to a numbered Qloo request.
Each date becomes a ready-to-use theme night kit: a title, a Taste Fit Score (0–100) with its breakdown, a heatmap of where the fans live, sponsor pitches ready to paste into an email, a giveaway and activations, promo copy, an IP-licensing flag, a printable sponsor one-pager, and every Qloo request behind it, copyable as curl.

After the plan, directors can Ask the GM to explain or change a night (it re-runs only the Qloo research it needs and revises just that night), share a read-only link, replay how the agent built the plan, and compare any two cities in Market DNA.
How we built it
The agent. Gemini 3.8 Flash runs a function-calling loop over eight tools, streaming its thoughts, every tool call and every Qloo request to the browser over Server-Sent Events. Each tool answers one business question with several Qloo calls, so the model reasons about the plan instead of composing query strings.
Deep, combined Qloo use. Seven endpoints work together:
/v2/insightswithsignal.location.queryto find local over-indexes, andbias.trendswhere Qloo supports itfilter.results.entitiesre-ranked undersignal.demographics.ageor a/v2/audienceslife stage to fit each date's crowdurn:heatmapwithfilter.locationaround the venue, plusurn:demographics,urn:tagand/v2/trending/v2/tags→filter.tags/filter.exclude.tagson brands, withfeature.explainability, to find sponsors in the club's own categoriesurn:entity:placewithin a 6 km radius, artists, podcasts,/v2/analysis/compare,/searchand/entities
Scores computed in code, never by the model. The Taste Fit Score weighs local affinity (30%), audience fit (25%), fans near the venue (20%), momentum (15%) and new-fan reach (10%). Because Qloo normalizes affinity per query, every comparison is a rank inside one result set. Anything Qloo couldn't measure is marked est. instead of quietly defaulted.
Guardrails in code. The plan validator rejects any entity Qloo didn't return during the run and sends specific errors back so the model can fix its plan. Safety rules are enforced server-side: no political, religious, crime or tragedy anchors, no identity-framed nights, and no alcohol brands or bars on family and Gen Z nights. No personal data is ever sent to Qloo.
Built to survive a live demo. Per-run Qloo budgets and deadlines, retries, rate limits, a deterministic safety net that finishes the plan if Gemini fails, and a store that keeps working when Redis is full or down. 107 tests and CI run on every push.
Stack: Next.js 16, TypeScript, Tailwind CSS v4, Gemini 3.8 Flash (@google/genai), Qloo Insights API, MapLibre, Redis, Vercel.
Challenges we ran into
- Per-query normalization. Qloo affinity can't be compared across requests, so we compare ranks inside one query's result set: local rank vs national-popularity rank for "lift", and one shared pool per domain for audience fit.
- A "near the venue" number that means something. Our first version, a ratio of mean heatmap affinities, sat near 0.5 for every fandom. Comparing the catchment's share of the fandom's hotspots with its share of all cells finally separated them.
- API realities.
takeabove 50 returns an error, books and video games have no trending data, the trending series end in September 2025, and heatmaps ignoretake(Los Angeles returned 2,741 cells). Each one is handled in code and shown honestly in the UI. - Honest numbers from a language model. In a live run, Gemini described a near-venue index of 0.58 as "58% of fans live nearby". We rewrote the rules so indexes are read as indexes, and the scores themselves never come from the model.
- Safety rules without false alarms. Our identity-night rule first rejected a tagline about "artisanal pride". It now judges framing ("Pride Night", "celebrate our heritage"), not single words.
- A free 30 MB Redis. Caching heatmaps filled it within a few runs, so share links started failing. We now cache only small responses, purge the disposable cache when the store is full, and keep the demo plans working even if Redis disappears.
Accomplishments that we're proud of
- Qloo's effect is measured, not claimed. The same Gemini model plans the same dates without Qloo, and its picks are fact-checked and scored with the same formula. Across four live markets the agent wins by +28 Taste Fit points on average (Durham 45 → 71, Los Angeles 44 → 73, Portland 44 → 74, Nashville 41 → 68), and every LLM pick was found in Qloo, so it's a fair fight.

- It works live. A full six-night season takes 65–155 seconds and 84–138 Qloo requests on the deployed app. In one live run the validator rejected the model's first plan, and the model fixed it and resubmitted on its own.
- Follow-ups are cheap. An Ask the GM change to one night takes 36–100 seconds and leaves every other night untouched.
- Receipts everywhere. Every entity in a night kit, and every score input not marked as estimated, traces back to a numbered Qloo request.
What we learned
- Qloo is most powerful when signals are combined: location finds local taste, demographics re-rank the shortlist, the heatmap shows where fans live, and a geographic filter finds partners.
- Tools should be shaped like business questions, not API calls.
- Grounding has to be enforced on the server. A rule in a prompt is a request, not a guarantee.
- An honest "we couldn't measure this" beats a quiet default.
What's next
- Let clubs upload attendance history to pick weak dates from their own data.
- Use a team's own Qloo entity for fan-base overlap where one exists.
- Expose Theme Night GM as an MCP server so other agents can plan with it.
- Run the agent vs control comparison at scale, across many markets and repeated runs.
Built With
- carto
- gemini
- github-actions
- google-genai
- maplibre
- next.js
- node.js
- openstreetmap
- qloo
- qloo-insights-api
- react
- redis
- tailwindcss
- typescript
- vercel
- vitest
- zod
Log in or sign up for Devpost to join the conversation.