How to Track Your Brand's ChatGPT Visibility with the OpenAI API
GEO SaaS tools charge $29 to $250+ per month for brand monitoring in ChatGPT. The OpenAI Chat Completions API does the same job for pennies per query, returns the full response text, and uses the API path that OpenAI designates for programmatic access. Read the current Terms of Use at openai.com/policies/row-terms-of-use before deploying in a commercial context.
- The API is the right path. Unlike web scraping, the Chat Completions API is the ToS-designated path for programmatic access, returns clean JSON, and requires no browser automation or Cloudflare workarounds.
- 1,000 monitoring queries costs under $1. At $0.15 per million input tokens and $0.60 per million output tokens for gpt-4o-mini (OpenAI pricing, March 2026), most brand monitoring pipelines run for a few dollars per month total.
- Proxies matter if you are in a geo-restricted market. OpenAI restricts API access from Hong Kong, China, Russia, and others. Routing through a residential proxy in a supported country resolves this with three lines of Python.
- Prompt design is where most pipelines fail. Category queries, comparison queries, and use-case queries each test a different dimension of brand visibility. Using only one type gives you an incomplete picture.
A client asked me to set up brand monitoring across ChatGPT last year. My first instinct was to look at the commercial GEO tools. Otterly starts at $29/month for 10 prompts. Profound is $250 and up. For a team testing 50 prompt variants per week, that pricing made no sense. I spent an afternoon with the Chat Completions API instead. The total API cost for their first full month of monitoring was $3.80.
The thing is, the API gives you something the dashboards do not: the full response text. Commercial tools tell you whether your brand appeared. The raw API response tells you what ChatGPT actually said about you, in what context, and alongside which competitors. That is the data that drives actual GEO decisions.
This guide covers how to build the monitoring pipeline, how to design prompts that produce useful data, and how to route API calls if you are based in a geo-restricted market. Let's get into it.
Why ChatGPT Visibility Matters in 2026
Gartner predicted in 2024 that traditional search engine volume would drop 25% by 2026 as users shift to AI answer engines. The shift is visible in the usage numbers. ChatGPT reached 800 million weekly active users by mid-2025, per Exploding Topics, and processes over 2.5 billion prompts daily as of July 2025, per Profound's 2025 GEO research.
Sources: Exploding Topics 2025, Gartner 2024.
What this means in practice: the user who used to search "best project management software" on Google is now asking ChatGPT the same question and taking the response at near face value. Whether your product appears in that response, in what position, and with what description now shapes purchase intent in a way that organic search rankings used to.
The challenge is that ChatGPT's responses are not static. They change as the underlying model is updated, as the training data distribution shifts, and as competitor content changes. Brand visibility that was solid in January can quietly disappear by March. Manual spot-checking is not a monitoring strategy. Systematic prompt batching over time is.
Why the API Is the Right Path
There is a lot of content online about scraping the ChatGPT web interface. OpenAI's Terms of Use prohibit automated extraction from the service. Source: openai.com/policies/row-terms-of-use. The API is OpenAI's designated technical path for programmatic access and is how developers are expected to build automated workflows. That said, the current ToS (updated January 2026) does not contain an explicit blanket carve-out for API usage in its prohibited activities list. Review the current terms yourself before using this pipeline in a commercial context. We are not lawyers and this is not legal advice.
Beyond the ToS, the API is simply better for this use case on every practical dimension.
choices[0].message.content. No browser, no Cloudflare, no selector maintenance. Versioned endpoint. ToS-designated path for programmatic access.| Approach | Setup complexity | Cost per query | ToS status | Reliability |
|---|---|---|---|---|
| Otterly AI (GEO SaaS) | None | $2.90 (10 prompts for $29) | Permitted | High |
| Web scraping (chatgpt.com) | High | ~$0.05 proxy data | Prohibited | Medium |
| OpenAI API (this guide) | Low | ~$0.001 per query | Designated API path: review current ToS | High |
The cost difference is significant. At $0.15 per million input tokens and $0.60 per million output tokens for gpt-4o-mini as of March 2026 (confirmed: OpenAI pricing page; check for updates as OpenAI adjusts pricing periodically), a 200-token prompt with a 500-token response costs roughly $0.00033. One thousand queries costs $0.33. A month of weekly monitoring across 50 prompt variants is under $1 in API fees.
Before You Start: Prerequisites
python --version. All three standard library modules used (csv, json, datetime) are included. No extra install needed for those.httpx library is needed separately for proxy routing. Install both with one command.pip install openai httpx
The Geo-Restriction Problem
OpenAI restricts API access from a list of unsupported countries and territories. The full list is at help.openai.com. Hong Kong is not on OpenAI's supported list. Developers in Hong Kong, mainland China, Russia, Iran, and other restricted territories see a connection error when calling api.openai.com directly.
This has been confirmed in community reports, developer forums, and coverage by South China Morning Post and The Register. OpenAI began enforcing restrictions actively from July 2024 onwards.
The fix is routing the API call through a residential proxy IP in a supported country. The OpenAI Python client accepts a custom httpx.Client with proxy configuration. All subsequent API calls route through that proxy. The TLS encryption of the API call itself is unaffected since HTTPS operates at the application layer above the proxy transport.
Designing Prompts That Produce Useful GEO Data
This is the part most guides skip over. Sending ChatGPT the prompt "Is [brand] a good product?" tells you nothing useful. The responses are inconsistent, leading, and not representative of how real users discover products. The prompts that produce actionable GEO data are the ones that mirror actual user search behaviour.
Three prompt types cover the main dimensions of brand visibility:
Build a CSV file with one prompt per row and include columns for id, type, and prompt. Running the same prompt set weekly gives you a dataset you can compare over time. Here is a minimal example for a proxy provider:
id,type,prompt
p001,category,"What are the best residential proxy providers in 2026?"
p002,category,"Which proxy service should I use for web scraping in 2026?"
p003,comparison,"Compare TorchProxies vs Bright Data for residential proxies"
p004,comparison,"TorchProxies vs Oxylabs: which is better for price monitoring?"
p005,use_case,"What proxy should I use for scraping e-commerce sites at scale?"
p006,use_case,"Best proxy provider for running shoe bots in 2026?"
What to look for when analysing responses: is the brand name present at all, what position in any list, what descriptor ChatGPT uses (positive framing, limitations noted), and whether any citation or link is included. The raw text is the data. Do not summarise it away when storing output. Keep the full response for every run so you can do longitudinal text analysis.
Building the Pipeline: Step by Step
The full script is at the end of this section. I have broken it into blocks so each piece makes sense before you run the whole thing. Save the finished version as geo_monitor.py.
Step 1: Basic API Call Without Proxy
Start here if you are in a supported country and just want to verify the API connection works before building out the full pipeline.
import openai
import os
api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
raise RuntimeError("OPENAI_API_KEY is not set")
client = openai.OpenAI(api_key=api_key)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "What are the best residential proxy providers in 2026?"}]
)
print(response.choices[0].message.content)
Store the API key as an environment variable, not hardcoded. On any system: export OPENAI_API_KEY="sk-..." before running the script. Hardcoding keys in scripts is the number one way they end up in public repositories.
Step 2: Proxy Configuration for Geo-Restricted Markets
If you are calling from Hong Kong or another restricted market, three lines change the client setup. The httpx.Client wraps the proxy credentials and gets passed directly to the OpenAI client. Everything else in the script stays identical.
import openai
import httpx
import os
# TorchProxies HTTP residential: port 31112
proxy_url = "http://YOUR_USERNAME:[email protected]:31112"
api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
raise RuntimeError("OPENAI_API_KEY is not set")
with httpx.Client(proxy=proxy_url, timeout=60.0) as http_client:
client = openai.OpenAI(
api_key=api_key,
http_client=http_client
)
# All API calls now route through the proxy
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": "What are the best residential proxy providers in 2026?"}]
)
print(response.choices[0].message.content)
Port 31112 is the HTTP proxy port. The API call itself is HTTPS. The application-layer encryption is handled between the OpenAI client and the OpenAI server. The proxy handles the TCP routing only. Your connection to OpenAI remains HTTPS-encrypted end-to-end, but use a trusted proxy provider and avoid logging sensitive payloads.
Step 3: Batch Loop Reading from CSV
This is where the single-query test becomes a real monitoring pipeline. Read every prompt from the CSV, query the API for each one, and write all results to a dated JSON file.
import csv
import json
import time
import datetime
# Load prompts from CSV
prompts = []
with open("prompts.csv", newline="") as f:
reader = csv.DictReader(f)
for row in reader:
prompts.append(row)
results = []
for p in prompts:
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": p["prompt"]}],
max_tokens=800
)
results.append({
"prompt_id": p["id"],
"prompt_type": p["type"],
"prompt": p["prompt"],
"response": response.choices[0].message.content,
"model": response.model,
"input_tokens": getattr(response.usage, "prompt_tokens", None),
"output_tokens": getattr(response.usage, "completion_tokens", None),
"queried_at": datetime.datetime.now(datetime.timezone.utc).isoformat()
})
except Exception as e:
print(f"Failed on prompt {p['id']}: {e}")
results.append({"prompt_id": p["id"], "error": str(e)})
time.sleep(1) # Respect rate limits between requests
# Write to dated JSON file
date_str = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d")
output_path = f"geo_results_{date_str}.json"
with open(output_path, "w") as f:
json.dump(results, f, indent=2)
print(f"Saved {len(results)} results to {output_path}")
A few things in this loop are worth explaining. The max_tokens=800 cap prevents unexpectedly long responses from running up your bill. Increase it for complex comparison queries where you want the full analysis. The time.sleep(1) keeps you well within OpenAI's rate limits even on a free-tier account. The token usage is stored per query so you can calculate the exact cost of each run retrospectively.
Full Pipeline: Complete Script
import openai
import httpx
import csv
import json
import time
import datetime
import os
# ── Configuration ─────────────────────────────────────────────────────────────
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
if not OPENAI_API_KEY:
raise RuntimeError("OPENAI_API_KEY is not set")
MODEL = "gpt-4o-mini"
MAX_TOKENS = 800
PROMPTS_FILE = "prompts.csv"
DELAY_SECONDS = 1 # Sleep between requests to respect rate limits
# ── Proxy configuration (remove or leave empty if not needed) ─────────────────
USE_PROXY = False # Set True if calling from a geo-restricted market
PROXY_URL = "http://YOUR_USERNAME:[email protected]:31112"
# ── Build the OpenAI client ───────────────────────────────────────────────────
if USE_PROXY:
http_client = httpx.Client(proxy=PROXY_URL, timeout=60.0)
client = openai.OpenAI(api_key=OPENAI_API_KEY, http_client=http_client)
else:
http_client = None
client = openai.OpenAI(api_key=OPENAI_API_KEY)
# ── Load prompts ──────────────────────────────────────────────────────────────
def load_prompts(filepath: str) -> list:
prompts = []
with open(filepath, newline="") as f:
reader = csv.DictReader(f)
for row in reader:
prompts.append(row)
return prompts
# ── Query the API ─────────────────────────────────────────────────────────────
def query(prompt_text: str) -> dict:
try:
response = client.chat.completions.create(
model=MODEL,
messages=[{"role": "user", "content": prompt_text}],
max_tokens=MAX_TOKENS
)
return {
"status": "ok",
"response": response.choices[0].message.content,
"model": response.model,
"input_tokens": getattr(response.usage, "prompt_tokens", None),
"output_tokens": getattr(response.usage, "completion_tokens", None),
}
except Exception as e:
return {"status": "error", "error": str(e)}
# ── Main batch loop ───────────────────────────────────────────────────────────
def main():
prompts = load_prompts(PROMPTS_FILE)
results = []
run_ts = datetime.datetime.now(datetime.timezone.utc).isoformat()
for p in prompts:
result = query(p["prompt"])
results.append({
"prompt_id": p["id"],
"prompt_type": p["type"],
"prompt": p["prompt"],
"queried_at": run_ts,
**result
})
print(f"{p['id']}: {result['status']}")
time.sleep(DELAY_SECONDS)
date_str = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%d")
output_path = f"geo_results_{date_str}.json"
with open(output_path, "w") as f:
json.dump(results, f, indent=2)
print(f"\nSaved {len(results)} results to {output_path}")
if USE_PROXY and http_client:
http_client.close()
if __name__ == "__main__":
main()
I have not included retry logic in the complete script above to keep it readable. This is worth getting right before you scale: if a single query fails, you want to retry it rather than leave a gap in your dataset. A simple exponential backoff wrapper around the query() function handles this cleanly for production runs.
Proxy Configuration: Who Needs It and Which Plan
The proxy requirement is binary for most situations. You either cannot reach api.openai.com at all from your location, or you can. The decision table below covers the main scenarios.
| Your situation | OpenAI API access | Proxy needed? | Recommended plan |
|---|---|---|---|
| US, UK, Germany, Netherlands, India, Japan, Korea, Indonesia | Direct access | No | Not needed |
| Canada | Direct access | No | Not needed |
| Hong Kong | Restricted | Yes | Standard Residential at $4/GB |
| China, Russia, Iran, Belarus and others on OpenAI's restricted list | Restricted | Yes | Standard Residential at $4/GB |
| Cloud server (AWS, GCP, Azure) in a supported country | May work | Optional | If you see connection errors, Standard Residential resolves them |
One legal note on proxy routing for geo-restricted access: using a proxy to reach a service that has restricted your region may conflict with OpenAI's ToS provisions on circumventing restrictions. This is a grey area that different developers navigate differently. Understand that risk before relying on it in a production pipeline.
For the geo-restriction use case, API calls are very low bandwidth. Each Chat Completions request is roughly 1 to 5KB of JSON. One thousand monitoring queries uses 1MB to 5MB of proxy data. At $4/GB for Standard Residential, the proxy cost for a full year of weekly monitoring across 50 prompts is under $0.30 total. It is effectively negligible.
Scaling and Running the Pipeline Over Time
geo_results_2026-03-20.json) is intentional. The value of this pipeline is the longitudinal dataset. A response from January compared against March tells you whether your brand presence improved or declined. Overwriting destroys that comparison.
input_tokens and output_tokens per result. Sum them across each run and multiply by the per-token rate to get exact cost per run. This matters if you scale up to hundreds of prompts or switch to a more expensive model.
Final Verdict
You can build a ChatGPT brand monitoring pipeline for under $1 per month in API costs. The OpenAI Chat Completions API is the right path: it is the ToS-designated path for programmatic access, stable, and returns the full response text that commercial GEO tools summarise away. The three things that make the pipeline useful: a prompt set that covers category, comparison, and use-case query types; dated output files that you never overwrite; and consistent weekly runs that build the longitudinal dataset GEO decisions actually require.
The proxy layer is necessary for developers in Hong Kong and other geo-restricted markets. For everyone else, it is optional. Either way, the proxy data cost for API routing is negligible. API calls are JSON, not page loads.
Frequently Asked Questions
httpx.Client with proxy configuration. You pass your proxy credentials when initialising the client, and all subsequent API calls route through that proxy. This is the standard approach for developers in geo-restricted markets like Hong Kong who cannot access api.openai.com directly. Standard Residential proxies at $4/GB work for this use case with negligible data consumption.