AnswerLine Start free

, Local SEO · GEO

Local AI answers: measure them by country, state and city

Gemini takes US-state targeting today. ChatGPT, Copilot, Perplexity and Grok answer at country level: a request that sends them state is refused with a 400 before anything runs, and nothing is billed. ChatGPT and Gemini answer from 213 countries, Copilot, Perplexity and Grok from any country, and Google News takes the 71 countries with a Google News edition.

To see how AI answers change by location, run the same prompt on the same engine and day across a matrix of markets, with the market set explicitly on every request, then compare the brands, sources and places each market returns. The API is built for three levels: country, state for the US on Gemini, and a Google canonical location (or uule) for city-level targeting on Google Search and AI Mode. Location is set per request, so the work is in designing the matrix and in reading the results without mistaking noise for geography.

Definitions

Why answers can change by location

Consumer AI assistants ground many answers in web search, and search results depend on location. For local-intent prompts, that plausibly shifts the businesses named, the directories cited and the map results attached. For product and service prompts, market can change availability, pricing sources and regional publications.

Treat all of this as hypotheses to test on your own prompts. A first experiment: run “best family lawyer” on Gemini for Colorado and for Florida on the same day, several times each, and check whether the named firms and cited directories differ more between states than between repeat runs in one state. The method below makes that comparison systematic.

Geo parameters by engine

The parameters differ by engine. Sending state to an engine that does not accept it, or with a country other than US, is a validation error.

Engine Endpoint Country Sub-country targeting Local result fields
ChatGPT /v1/monitor/chatgpt country (required; 213 countries) none; state refused map[], entities[]
Perplexity /v1/monitor/perplexity country (required; any country) none; state refused none; compare sources[]
Gemini /v1/monitor/gemini country (required; 213 countries) state, US only places[]
Copilot /v1/monitor/copilot country (required; any country) none; state refused map[] (coming)
Grok /v1/monitor/grok country (required; any country) none; state refused none; compare sources[]
Google AI Mode /v1/monitor/aimode country or gl, plus hl location or uule places[], map[]
Google Search /v1/monitor/google country or gl, plus hl location or uule localResults[]
Google News /v1/monitor/google/news country or gl, plus hl none none

Notes:

The engine pages for Google local pack and AI Mode places show those fields in detail.

Running a US state sweep

The sweep below runs on Gemini, which takes state. ChatGPT, Copilot, Perplexity and Grok answer at country level and refuse state with a 400, billing nothing.

  1. Pick prompts with local intent. Twenty is enough to start; prompt set design covers choosing them.
  2. Fetch the market list from GET /v1/states?country=US rather than hardcoding it.
  3. Build one task per prompt and state, with an idempotency key derived from engine, prompt, state and date.
  4. Submit in batches of up to 500 to POST /v1/async/task/batch, with a webhook.
  5. Store the market on every result row. Task results and webhook bodies do not echo the payload, so keep a map from task id or key to prompt and state.
  6. Repeat each market at least a few times on the first sweep to measure normal variance. Add the repeat number to the idempotency key, or same-day repeats are refused as duplicates.
  7. Compare markets only on differences larger than that variance.
import hashlib
import os

import requests

BASE_URL = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
RUN_DATE = "2026-09-16"
PROMPTS = ["best family lawyer", "emergency plumber open now", "best pediatric dentist"]

states = requests.get(f"{BASE_URL}/v1/states", params={"country": "US"}, headers=HEADERS, timeout=30).json()

tasks = []
for prompt in PROMPTS:
    for state in states:
        digest = hashlib.sha256(f"{prompt}|US|{state['code']}".encode()).hexdigest()[:16]
        tasks.append({
            "taskType": "GEMINI",
            "payload": {"prompt": prompt, "country": "US", "state": state["code"]},
            "idempotencyKey": f"gemini-{digest}-{RUN_DATE}",
            "webhook": {"url": "https://example.com/hooks/answers"},
        })

for start in range(0, len(tasks), 500):
    chunk = tasks[start:start + 500]
    res = requests.post(f"{BASE_URL}/v1/async/task/batch", json=chunk, headers=HEADERS, timeout=(10, 360))
    res.raise_for_status()
    for item in res.json().get("results", []):
        if not item["success"] and item.get("error", {}).get("code") != "RESOURCE_ALREADY_EXISTS":
            print(chunk[item["index"]]["payload"], item["error"]["code"])

When results arrive, the webhook body is the finished task. For a COMPLETED task, the engine result is at response.result:

from urllib.parse import urlparse

def local_signals(body: dict) -> dict:
    result = body["response"]["result"]
    return {
        "task_id": body["task"]["id"],
        "domains": sorted({urlparse(s["url"]).hostname for s in result.get("sources", [])}),
        "places": [p.get("name") for p in result.get("places", [])],
    }

Look up the prompt and state for task_id from what you stored at submission. Deliveries can repeat, so dedupe by task.id; see webhook reliability design. Batch patterns for larger matrices are in rank tracking pipelines with batches.

City-level targeting on Google

For city granularity, send location to AI Mode, or to Google Search for the classic local pack. The same prompt can be compared across cities in AI Mode’s places:

import { Client } from "@answerline/sdk";

type Named = { title: string };

const client = new Client({ apiKey: process.env.API_KEY! });
const cities = ["Austin,Texas,United States", "Denver,Colorado,United States"];

for (const location of cities) {
  const aiMode = await client.aiMode({ prompt: "emergency plumber near me", country: "US", location });
  const places = (aiMode.result as { places?: Named[] }).places ?? [];
  console.log(location, { aiModePlaces: places.map((p) => p.title) });
}

These are synchronous calls, fine for a spot check. For a recurring city matrix, submit AIMODE tasks in batches as above; the local rank tracking use case covers the pipeline.

What a sweep costs

Every market is its own request at the same price, so cost grows with the number of markets. Starter-tier base prices: ChatGPT $0.0006, Gemini $0.0006, AI Mode $0.00206, Google Search $0.00103, Google News $0.0002, Copilot $0.00274, Perplexity $0.0015, Grok $0.00218.

State sweep on Gemini:

City check on AI Mode: 20 prompts × 10 cities × $0.00206 = $0.412 per run.

Variance runs: three repeats of one prompt in 5 states on Gemini is 3 × 5 × $0.0006 = $0.009, a cheap way to calibrate before a full sweep.

A new account’s 100 free requests work on both engines, enough to test a few states or cities before sizing a program. Cost planning covers sizing a recurring program.

Reading a sweep: metrics per market

Per-market metrics, computed once results are stored with their market:

Metric Computed from What it shows
Presence rate Share of runs where your brand appears in text (or entities[] on ChatGPT) Where you are named at all
Citation share Share of citationPills[] or sources[] pointing at your domains Where your pages ground the answer
Place inclusion Whether your business is in map[], places[] or localResults[] Local visibility in structured results
Domain overlap Cited domains shared between two markets, divided by all cited domains in either How similar two markets’ source pools are
Competitor set Brands named in a market that are never named nationally Regional competitors you may not track

Compute every metric per engine, because field availability differs: Grok has no citationPills and only ChatGPT returns entities. Keep Google Search’s localResults separate from AI answers: the local pack is a ranked list, while AI answers name a handful of businesses in prose, so positions do not mean the same thing.

Country and language sweeps

Outside the US, the market unit is the country. ChatGPT and Gemini answer from 213 countries and Copilot, Perplexity and Grok from any country; on these the market is country alone. On Google Search, Google News and AI Mode, set hl as well to choose the interface language explicitly. Keep one prompt language per country run and record it, so a difference caused by translation is not reported as a difference in market. Multilingual AI answers covers translation choices.

Separating geography from noise

AI answers vary between identical runs. Before concluding that Florida sees different firms than Colorado:

  1. Hold everything else constant: same prompt text, engine, day, and include flags.
  2. Measure within-market variance from repeat runs in one state.
  3. Compare frequencies, not single answers: “named in 4 of 5 Colorado runs vs 0 of 5 Florida runs” is a finding; one run each is not.
  4. Aggregate carefully: a national average can hide the states where a brand is absent, so report per market first.

AI answer volatility covers variance in more depth.

Pitfalls

Field details for local results are on the Google Search engine page; the quickstart gets a first request running.

Questions

Which engines accept US state targeting?

Gemini, as a two-letter code in state, valid only with country US. ChatGPT, Copilot, Perplexity and Grok answer at country level: a request that sends them state is refused with a 400 and nothing is billed. Google News accepts country or gl and hl only.

How many countries and states can I target?

GET /v1/countries returns the supported ISO country codes and accepts ?model= to list the countries for a specific engine. Google News takes the 71 countries with a Google News edition; ChatGPT, Gemini, AI Mode and Google Search answer from 213 countries; Copilot, Perplexity and Grok take any country. GET /v1/states?country=US returns the 51 entries state targeting uses.

How much will a 50-state sweep cost?

Each state is a separate request. 20 prompts across the 51 entries from GET /v1/states on Gemini is 20 x 51 x $0.0006 = $0.612 per sweep at the Starter tier.

Does the same prompt give different answers in different states?

It can, and that is what a state sweep measures. Hold the prompt, engine and day constant, repeat runs to measure normal variance, and treat only differences larger than that variance as geographic.

How do I target a city on Google?

On Google Search or AI Mode, send location as a Google canonical location name in City,Region,Country form, such as Austin,Texas,United States, together with country. Alternatively send a pre-encoded uule; location and uule are mutually exclusive.

Try it on your own prompts

100 free requests on any engine, no card. One POST returns the answer, sources and citations as JSON.

Keep reading