AnswerLine Start free

, GEO · Local SEO · Brand Monitoring

Multilingual AI visibility: monitor answers by language

A program that monitors only English prompts measures only English-language answers. The engines reply in the language they are asked in, can cite sources from that language’s web, and can name different brands. The French answer to “iPhone 17 ou Galaxy S26 ?” need not be a translation of the English answer, and the way to find out how far apart they are for your category is to collect both.

ChatGPT, Gemini, AI Mode and Google Search answer from 213 countries, Copilot, Perplexity and Grok take any country, and Google News the 71 countries with a Google News edition, with hl for the language. The coverage check in the setup below skips pairs an engine does not serve.

Two axes: language and market

Google Search, AI Mode and Google News expose both axes as parameters.

Engine Market Language Finer location
Gemini country (213 countries) Prompt text state (US only)
ChatGPT country (213 countries) Prompt text none
Copilot, Perplexity, Grok country (any) Prompt text none
AI Mode (/v1/monitor/aimode) country or gl Prompt text, plus hl location or uule
Google Search (/v1/monitor/google) country or gl Query text, plus hl location or uule
Google News (/v1/monitor/google/news) country or gl Query text, plus hl none

hl is Google’s interface language code (for example en, de, pt-BR). It is free-form and overrides the language the API would otherwise derive from the country, so the interface language and the result geography can differ. gl is an alternative to country using Google’s own parameter name; send one or the other, because sending both with different values returns 400.

Why answers diverge across languages

An answer that cites the web is assembled from searches the engine runs. When the question is in French and asked from France, those searches are likely to be in French and to surface French-language pages, so the pool of citable sources changes, and with it the brands the answer names. The searches themselves are not visible: ChatGPT’s searchQueries[] field comes back empty on the ChatGPT answers served today. Their effect is: compare the language and domains of the cited sources[] across markets.

Your English-language pages, however strong, may not be in the pool for a German answer, so visibility has to be measured per language.

Decide which market-language pairs to monitor

A market is not always one language. Monitor pairs, not countries:

Situation Pairs to monitor
One dominant language FR + French prompts
Several official languages CH + German, CH + French; CA + English, CA + French; BE + Dutch, BE + French
Large second-language population you sell to US + Spanish prompts alongside US + English
English used for business buying NL or SE + English prompts, alongside the local language
No revenue or sales plans Skip; add later as a new cohort

Prioritize by revenue or pipeline in each pair, not by country size.

Setting it up

1. Check engine coverage for each market

Not every engine accepts every country. GET /v1/countries?model=<engine> returns the supported ISO codes for that engine (chatgpt, gemini, or google for Google News). Build your matrix from the intersection:

import os
import requests

API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['ANSWERLINE_API_KEY']}"}

ENGINES = ["chatgpt", "gemini"]
MARKETS = ["US", "FR", "DE", "CH", "JP"]

supported = {}
for engine in ENGINES:
    r = requests.get(f"{API}/v1/countries", headers=HEADERS, params={"model": engine}, timeout=30)
    r.raise_for_status()
    supported[engine] = set(r.json())  # a JSON array of country codes

for market in MARKETS:
    missing = [e for e in ENGINES if market not in supported[e]]
    print(market, "all engines" if not missing else f"not supported on: {missing}")

2. Write native prompts per intent

Start from your English prompt set as a list of intents, each with a stable ID. For each market-language pair, have a native speaker write the prompt the way a local buyer would ask it:

Keep the intent ID on every prompt so you can compare “the same question” across markets even though the wording differs. Prompt set design covers intent grouping.

3. Define brand aliases per language

Brand detection fails silently in other scripts and languages. Keep a per-language alias list: transliterations (Japanese katakana forms of Latin brand names), local product names, and legal-entity names that appear in local press. Measuring brand mentions covers matching with word boundaries.

4. Submit one batch per run

Each task carries the market in country and the language in the prompt text. Idempotency keys include the intent ID, market, language, engine and date, so a retried submission never creates duplicates.

import datetime

RUN = datetime.date.today().isoformat()

prompts = [
    {"intent": "phone-compare", "country": "FR", "lang": "fr", "prompt": "iPhone 17 ou Galaxy S26 ?"},
    {"intent": "phone-compare", "country": "DE", "lang": "de", "prompt": "iPhone 17 oder Galaxy S26?"},
    {"intent": "phone-compare", "country": "CH", "lang": "fr", "prompt": "iPhone 17 ou Galaxy S26 ?"},
    {"intent": "phone-compare", "country": "US", "lang": "en", "prompt": "iPhone 17 or Galaxy S26?"},
]

tasks, meta = [], []
for p in prompts:
    jobs = [
        ("CHATGPT", {"prompt": p["prompt"], "country": p["country"]}),
        ("GEMINI", {"prompt": p["prompt"], "country": p["country"]}),
    ]
    for task_type, payload in jobs:
        if task_type.lower() not in supported or p["country"] not in supported[task_type.lower()]:
            continue
        tasks.append({
            "taskType": task_type,
            "payload": payload,
            "idempotencyKey": f"ml-{p['intent']}-{p['country']}-{p['lang']}-{task_type}-{RUN}",
            "webhook": {"url": "https://your-app.example/hooks/answers"},
        })
        meta.append({**p, "engine": task_type})

resp = requests.post(f"{API}/v1/async/task/batch", headers=HEADERS, json=tasks, timeout=360)
resp.raise_for_status()
body = resp.json()
print(body["summary"])
for item in body["results"]:
    if not item["success"]:
        print(meta[item["index"]], item["error"]["code"])

A batch takes up to 500 tasks; split larger runs. Results arrive at the webhook as the same JSON that GET /v1/async/task/{taskId} returns, with the answer under response.result. Verify the signature before trusting the body; see webhooks and verifying webhook signatures.

The same submission with the TypeScript SDK (@answerline/sdk):

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

const client = new Client({ apiKey: process.env.ANSWERLINE_API_KEY! });
const run = new Date().toISOString().slice(0, 10);

const markets = [
  { intent: "phone-compare", country: "FR", lang: "fr", prompt: "iPhone 17 ou Galaxy S26 ?" },
  { intent: "phone-compare", country: "DE", lang: "de", prompt: "iPhone 17 oder Galaxy S26?" },
];

const chatgptCountries = new Set(await client.countries("chatgpt"));

const tasks = markets
  .filter((m) => chatgptCountries.has(m.country))
  .map((m) => ({
    taskType: "CHATGPT" as const,
    payload: { prompt: m.prompt, country: m.country },
    idempotencyKey: `ml-${m.intent}-${m.country}-${m.lang}-CHATGPT-${run}`,
  }));

const batch = await client.createBatch(tasks);
for (const item of batch.results) {
  if (!item.success) console.warn(tasks[item.index].idempotencyKey, item.error.code);
}

5. Analyze per market-language pair

For each stored result, compute the same metrics you use in English, grouped by market, language and engine:

from collections import Counter, defaultdict
from urllib.parse import urlparse

ALIASES = {"en": ["Acme"], "fr": ["Acme"], "de": ["Acme"], "ja": ["Acme", "アクメ"]}
MY_DOMAINS = {"acme.com", "acme.fr", "acme.de"}

def host(url):
    h = urlparse(url).hostname or ""
    return h[4:] if h.startswith("www.") else h

stats = defaultdict(lambda: {"answers": 0, "mentioned": 0, "mine": 0, "sources": 0, "domains": Counter()})

def record(meta, result):
    s = stats[(meta["country"], meta["lang"], meta["engine"])]
    text = result.get("text", "").lower()
    s["answers"] += 1
    s["mentioned"] += any(a.lower() in text for a in ALIASES[meta["lang"]])
    for src in result.get("sources", []):
        d = host(src["url"])
        s["sources"] += 1
        s["mine"] += d in MY_DOMAINS
        s["domains"][d] += 1

def report():
    for (country, lang, engine), s in sorted(stats.items()):
        rate = s["mentioned"] / s["answers"]
        share = s["mine"] / s["sources"] if s["sources"] else 0.0
        top = ", ".join(d for d, _ in s["domains"].most_common(5))
        print(f"{country}-{lang} {engine}: mention rate {rate:.0%}, citation share {share:.0%}, top sources: {top}")

Call record(meta, response["result"]) from your webhook handler for each COMPLETED task, then report() after the run. MY_DOMAINS lists every localized domain you own; a French answer citing acme.fr is a citation for you.

Reading the results

Localized pages and hreflang

For Google’s surfaces, Google documents hreflang (as HTML tags, HTTP headers or sitemap entries) as the way to tell it about localized variants of the same content, with ISO 639-1 language codes and optional ISO 3166-1 alpha-2 region codes, and x-default as the fallback. It also says it does not use hreflang or the HTML lang attribute to detect a page’s language; it detects language algorithmically (Google Search Central: localized versions, checked 2026-09-17). That page does not discuss AI answers, so treat correct hreflang as hygiene for Google’s index and measure citations of your localized URLs rather than assuming an effect.

What it costs

The price depends on the engine and options, never on the language. As async tasks at the Starter tier:

Task Price
CHATGPT $0.0006
GEMINI $0.0006
Per prompt per market-language pair per run $0.0012

For example, 30 intents across 6 market-language pairs is 180 prompts, or $0.216 per run; weekly for four weeks is $0.864. See pricing and cost planning.

Pitfalls

For state-level differences inside the US, see local AI answers by state. To start, follow the quickstart or see the ChatGPT engine page and Gemini engine page.

Questions

Do AI assistants give different answers in different languages?

They can. The answer is written in the prompt's language and may cite different sources and name different brands. The only reliable way to know for your category is to run native-language prompts per market and compare the stored answers.

How do I set the language and market for a monitored AI answer?

Every engine takes a country code in country. For ChatGPT, Gemini, Copilot, Perplexity and Grok, the language is the language you write the prompt in; ChatGPT and Gemini answer from 213 countries, and Copilot, Perplexity and Grok take any country. Google News takes the 71 countries with a Google News edition and also accepts hl for the interface language and gl as an alternative to country, as does AI Mode. Google Search takes country or gl, and hl, which defaults to the country's language.

Which countries does each engine support?

Call GET /v1/countries with a model filter such as chatgpt or gemini, or google for Google News. It returns the ISO 3166-1 alpha-2 codes that engine accepts. Copilot, Perplexity and Grok take any country, and AI Mode and Google Search answer from 213.

Should I translate my English prompt set?

Use the English set as an intent list, then have a native speaker write each prompt as a local buyer would ask it, with local currency, units, competitors and idioms. Word-for-word translations produce prompts real users do not type.

Does monitoring in another language cost more?

No. The price depends on the engine and options, not the language: for example $0.0006 for a ChatGPT task and $0.0006 for Gemini at the Starter tier.

Does hreflang make AI engines cite my localized pages?

No source says so. Google documents hreflang as the way to tell it about localized variants of a page, and says it detects page language algorithmically rather than from hreflang. Measure which localized URLs get cited instead of assuming.

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