Query Simulation (M17)
Run any query text across AI providers on demand and compare brand mention results side-by-side. The developer tools equivalent for Module 3 — debug AI visibility gaps without waiting for the scheduled query runner.
What it does#
The /ai-reach/simulate page lets you:
- Enter any free-form query text
- Select which providers to query (ChatGPT, Perplexity, Claude, Gemini, Grok)
- Run all selected providers in parallel (synchronous, results in ≤30s)
- See a brand mention diff showing which brands every provider mentions vs. some vs. none
- Expand each provider's raw response
Results are saved as AIQueryResult rows with is_simulated=True and no parent AIQuery.
Usage#
Navigate to AI Visibility → Simulate in the sidebar, or go to /ai-reach/simulate.
Enter a query (e.g. "best trail running shoes under $150"), select providers, and click Run Simulation. An elapsed timer shows progress. Partial results are shown if any provider times out (28s timeout).
Diff panel#
The diff panel shows all brands mentioned across any provider response, color-coded:
| Color | Meaning |
|---|---|
| 🟢 Green | Mentioned by all selected providers |
| 🟡 Yellow | Mentioned by some providers |
| 🔴 Red | Not mentioned by any provider |
API#
POST /api/ai-reach/simulate/
Request:
providers is optional — omit or pass [] to query all 5 providers.
Response:
timed_out: true means at least one provider exceeded 28 seconds — partial results are returned.
Architecture#
SimulateViewusesconcurrent.futures.ThreadPoolExecutorfor parallel provider execution (not Celery — response must be synchronous).- Each worker calls
adapter.execute()+extract_entities()fromapps/ai_reach/. AIQueryResult.queryFK is nullable (null=True) — simulation results have no parentAIQuery.- Diff is computed server-side: brand names are lowercased and deduplicated across results.
Deferred#
- Perplexity citation display (raw response text contains inline markers)
- Historical replay (compare vs. prior runs of a registered query)
- Segment intersection ("which user segments would this answer target?")
Key code paths#
- Backend:
apps/api/apps/ai_reach/views.py—SimulateView,_compute_diff() - Frontend:
apps/web/app/(app)/ai-reach/simulate/page.tsx - Types:
apps/web/lib/api.ts—SimulateResponse,SimulateDiffEntry