SegOps AIDocs

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:

  1. Enter any free-form query text
  2. Select which providers to query (ChatGPT, Perplexity, Claude, Gemini, Grok)
  3. Run all selected providers in parallel (synchronous, results in ≤30s)
  4. See a brand mention diff showing which brands every provider mentions vs. some vs. none
  5. 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:

ColorMeaning
🟢 GreenMentioned by all selected providers
🟡 YellowMentioned by some providers
🔴 RedNot mentioned by any provider

API#

POST /api/ai-reach/simulate/

Request:

json
{
  "query_text": "best trail running shoes",
  "providers": ["chatgpt", "perplexity", "claude"]
}

providers is optional — omit or pass [] to query all 5 providers.

Response:

json
{
  "query_text": "best trail running shoes",
  "providers": ["chatgpt", "perplexity", "claude"],
  "timed_out": false,
  "results": [
    {
      "id": 42,
      "provider": "chatgpt",
      "raw_response": "...",
      "mentioned_brands": [{"name": "Salomon", "position": 1, "sentiment": "positive"}],
      "mentioned_products": [],
      "position": null,
      "sentiment": "neutral",
      "is_simulated": true,
      "captured_at": "2026-05-09T12:00:00Z"
    }
  ],
  "diff": [
    {"brand_name": "salomon", "status": "all", "providers": ["chatgpt", "perplexity", "claude"]},
    {"brand_name": "brooks", "status": "some", "providers": ["chatgpt"]},
    {"brand_name": "hoka", "status": "none", "providers": []}
  ]
}

timed_out: true means at least one provider exceeded 28 seconds — partial results are returned.

Architecture#

  • SimulateView uses concurrent.futures.ThreadPoolExecutor for parallel provider execution (not Celery — response must be synchronous).
  • Each worker calls adapter.execute() + extract_entities() from apps/ai_reach/.
  • AIQueryResult.query FK is nullable (null=True) — simulation results have no parent AIQuery.
  • 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.pySimulateView, _compute_diff()
  • Frontend: apps/web/app/(app)/ai-reach/simulate/page.tsx
  • Types: apps/web/lib/api.tsSimulateResponse, SimulateDiffEntry