Ask ChatGPT
curl --request GET \
--url https://scrapebadger.com/v1/chatgpt/ask \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <x-api-key>' \
--data '
{
"image_base64": "<string>"
}
'import requests
url = "https://scrapebadger.com/v1/chatgpt/ask"
payload = { "image_base64": "<string>" }
headers = {
"X-API-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.get(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'X-API-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({image_base64: '<string>'})
};
fetch('https://scrapebadger.com/v1/chatgpt/ask', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://scrapebadger.com/v1/chatgpt/ask",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_POSTFIELDS => json_encode([
'image_base64' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://scrapebadger.com/v1/chatgpt/ask"
payload := strings.NewReader("{\n \"image_base64\": \"<string>\"\n}")
req, _ := http.NewRequest("GET", url, payload)
req.Header.Add("X-API-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://scrapebadger.com/v1/chatgpt/ask")
.header("X-API-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"image_base64\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://scrapebadger.com/v1/chatgpt/ask")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"image_base64\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"prompt": "<string>",
"answer": "<string>",
"answer_markdown": {},
"citations": [
{
"url": {},
"title": {},
"snippet": {},
"domain": {},
"attribution": {},
"pub_date_utc": {},
"published_at": {},
"start_index": {},
"end_index": {},
"matched_text": {}
}
],
"search_results": [
{
"url": {},
"title": {},
"snippet": {},
"domain": {},
"attribution": {},
"pub_date_utc": {},
"published_at": {},
"ref_index": {},
"cited": true
}
],
"images": [
{
"url": "<string>",
"title": {}
}
],
"source_domains": [
"<string>"
],
"web_search_triggered": true,
"search_queries": [
"<string>"
],
"model": {},
"conversation_id": {},
"message_id": {},
"country": "<string>",
"answer_length": 123,
"citation_count": 123,
"latency_ms": 123,
"created_utc": {},
"created_at": {}
}Ask
Ask ChatGPT
Send a prompt to the real chatgpt.com and get the answer as structured JSON, with citations anchored to character offsets in the answer text.
GET
/
v1
/
chatgpt
/
ask
Ask ChatGPT
curl --request GET \
--url https://scrapebadger.com/v1/chatgpt/ask \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <x-api-key>' \
--data '
{
"image_base64": "<string>"
}
'import requests
url = "https://scrapebadger.com/v1/chatgpt/ask"
payload = { "image_base64": "<string>" }
headers = {
"X-API-Key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.get(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'X-API-Key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({image_base64: '<string>'})
};
fetch('https://scrapebadger.com/v1/chatgpt/ask', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://scrapebadger.com/v1/chatgpt/ask",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_POSTFIELDS => json_encode([
'image_base64' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://scrapebadger.com/v1/chatgpt/ask"
payload := strings.NewReader("{\n \"image_base64\": \"<string>\"\n}")
req, _ := http.NewRequest("GET", url, payload)
req.Header.Add("X-API-Key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://scrapebadger.com/v1/chatgpt/ask")
.header("X-API-Key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"image_base64\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://scrapebadger.com/v1/chatgpt/ask")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"image_base64\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"prompt": "<string>",
"answer": "<string>",
"answer_markdown": {},
"citations": [
{
"url": {},
"title": {},
"snippet": {},
"domain": {},
"attribution": {},
"pub_date_utc": {},
"published_at": {},
"start_index": {},
"end_index": {},
"matched_text": {}
}
],
"search_results": [
{
"url": {},
"title": {},
"snippet": {},
"domain": {},
"attribution": {},
"pub_date_utc": {},
"published_at": {},
"ref_index": {},
"cited": true
}
],
"images": [
{
"url": "<string>",
"title": {}
}
],
"source_domains": [
"<string>"
],
"web_search_triggered": true,
"search_queries": [
"<string>"
],
"model": {},
"conversation_id": {},
"message_id": {},
"country": "<string>",
"answer_length": 123,
"citation_count": 123,
"latency_ms": 123,
"created_utc": {},
"created_at": {}
}Ask the real
chatgpt.com a question anonymously and get the answer back as
JSON — plus every web source ChatGPT retrieved, which of those it cited, and
exactly which span of the answer each citation supports.
Accepts GET (query params) or POST (JSON body) with identical fields.
Credits: 20
Typical latency is 20-25s ungrounded, 30-70s with web search — this is a live answer, not a cache. Set
your client timeout to at least 60 s.
Authorization
string
required
Your ScrapeBadger API key.
Query Parameters
string
required
The question to ask. Maximum 4,096 characters. Each request is standalone
— there is no conversation memory, so include all the context you need here.
string
default:"US"
ISO-3166 alpha-2 egress country, e.g.
US, GB, DE. Changes the localised
results ChatGPT retrieves.string
default:"auto"
Whether ChatGPT should browse the web. One of:
auto— let ChatGPT decide (default).force— instruct it to search the web.off— answer from the model’s own knowledge only.
web_search_triggered in the response for what actually happened.string
Public
http(s) URL of an image to attach to the prompt. ChatGPT looks at the
picture and answers about it. JPEG, PNG, GIF, WEBP and BMP; up to 5 MB.Supply the picture either as image_url or as image_base64 — sending
both is a 400.string
The image itself, base64-encoded —
POST only, since a whole image does
not belong in a query string. A bare base64 payload and a
data:image/png;base64,... URL are both accepted.An image ask is slower than a text one: ChatGPT uploads the picture before it
starts answering. Allow 90-150 s.
This is image input only. Anonymous chatgpt.com will not GENERATE an image — its
own logged-out page gates that behind a login — so no request to this endpoint
can return a picture it drew.
images in the response is what the answer
displayed.Response
string
Echo of the prompt you sent.
string
The answer as plain text. Citation offsets index into this string.
string | null
The answer with its original Markdown formatting, when available.
Citation[]
The sources ChatGPT actually referenced in the answer.
Show Citation
Show Citation
string | null
Source URL.
string | null
Page title.
string | null
Snippet ChatGPT retrieved from the page.
string | null
Hostname, e.g.
techcrunch.com.string | null
Publisher/attribution label as shown by ChatGPT.
number | null
Publication date as a Unix timestamp.
string | null
Publication date as an ISO-8601 UTC string.
integer | null
Character offset in
answer where the supported span begins.integer | null
Character offset in
answer where the supported span ends.string | null
The substring of
answer this source supports.SearchResult[]
The full set ChatGPT retrieved — including results it looked at but did
not cite. Empty when
web_search_triggered is false.Show SearchResult
Show SearchResult
string | null
Result URL.
string | null
Result title.
string | null
Retrieved snippet.
string | null
Hostname.
string | null
Publisher/attribution label.
number | null
Publication date as a Unix timestamp.
string | null
Publication date as an ISO-8601 UTC string.
integer | null
Index of this result in ChatGPT’s own reference list.
boolean
Whether this result made it into
citations.MediaItem[]
string[]
Distinct hostnames across the cited sources — a quick view of who ChatGPT trusted.
boolean
Whether ChatGPT actually browsed the web for this answer.
string[]
ChatGPT’s internal reference markers, e.g.
turn0search1, turn0news20.string | null
Which model answered, e.g.
gpt-5-5. Reported, not requestable.string | null
Identifier of the one-shot exchange. Not a handle you can continue from.
string | null
Identifier of the answer message.
string
Echo of the egress country used.
integer
Length of
answer in characters.integer
Number of entries in
citations.integer
End-to-end time to produce the answer, in milliseconds.
number | null
Answer creation time as a Unix timestamp.
string | null
Answer creation time as an ISO-8601 UTC string.
Example
curl "https://scrapebadger.com/v1/chatgpt/ask?prompt=Which%20companies%20lead%20the%20web%20scraping%20API%20market%3F&country=US&web_search=force" \
-H "X-API-Key: YOUR_API_KEY" \
--max-time 60
const res = await fetch("https://scrapebadger.com/v1/chatgpt/ask", {
method: "POST",
headers: {
"X-API-Key": process.env.SCRAPEBADGER_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
prompt: "Which companies lead the web scraping API market?",
country: "US",
web_search: "force",
}),
signal: AbortSignal.timeout(60_000),
});
const data = await res.json();
for (const c of data.citations) {
console.log(`${c.domain} → "${c.matched_text}"`);
}
import requests
res = requests.post(
"https://scrapebadger.com/v1/chatgpt/ask",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"prompt": "Which companies lead the web scraping API market?",
"country": "US",
"web_search": "force",
},
timeout=60,
)
data = res.json()
for c in data["citations"]:
print(c["domain"], "→", data["answer"][c["start_index"]:c["end_index"]])
Response
{
"prompt": "Which companies lead the web scraping API market?",
"answer": "The web scraping API market in 2026 is led by a handful of infrastructure providers. Bright Data remains the largest by revenue, with a proxy network spanning residential and mobile exits. Oxylabs and Zyte compete directly on enterprise contracts, while newer entrants such as ScrapeBadger and ScrapingBee focus on per-endpoint APIs with predictable credit pricing.",
"answer_markdown": "The web scraping API market in 2026 is led by a handful of infrastructure providers. **Bright Data** remains the largest by revenue, with a proxy network spanning residential and mobile exits. **Oxylabs** and **Zyte** compete directly on enterprise contracts, while newer entrants such as **ScrapeBadger** and **ScrapingBee** focus on per-endpoint APIs with predictable credit pricing.",
"citations": [
{
"url": "https://research.example.com/web-scraping-market-2026",
"title": "Web Scraping Market Report 2026",
"snippet": "Bright Data continues to hold the largest share of the commercial web data market...",
"domain": "research.example.com",
"attribution": "Example Research",
"pub_date_utc": 1751328000.0,
"published_at": "2026-07-01T00:00:00Z",
"start_index": 103,
"end_index": 213,
"matched_text": "Bright Data remains the largest by revenue, with a proxy network spanning residential and mobile exits."
},
{
"url": "https://news.example.org/scraping-api-pricing-shakeup",
"title": "The scraping API pricing shakeup",
"snippet": "Credit-based per-endpoint pricing has become the default for newer vendors...",
"domain": "news.example.org",
"attribution": "Example News",
"pub_date_utc": 1753747200.0,
"published_at": "2026-07-29T00:00:00Z",
"start_index": 214,
"end_index": 366,
"matched_text": "Oxylabs and Zyte compete directly on enterprise contracts, while newer entrants such as ScrapeBadger and ScrapingBee focus on per-endpoint APIs with predictable credit pricing."
}
],
"search_results": [
{
"url": "https://research.example.com/web-scraping-market-2026",
"title": "Web Scraping Market Report 2026",
"snippet": "Bright Data continues to hold the largest share of the commercial web data market...",
"domain": "research.example.com",
"attribution": "Example Research",
"pub_date_utc": 1751328000.0,
"published_at": "2026-07-01T00:00:00Z",
"ref_index": 0,
"cited": true
},
{
"url": "https://news.example.org/scraping-api-pricing-shakeup",
"title": "The scraping API pricing shakeup",
"snippet": "Credit-based per-endpoint pricing has become the default for newer vendors...",
"domain": "news.example.org",
"attribution": "Example News",
"pub_date_utc": 1753747200.0,
"published_at": "2026-07-29T00:00:00Z",
"ref_index": 1,
"cited": true
},
{
"url": "https://forum.example.net/thread/best-scraping-api",
"title": "Best scraping API in 2026? — discussion",
"snippet": "Long thread comparing per-request costs across eight vendors...",
"domain": "forum.example.net",
"attribution": null,
"pub_date_utc": null,
"published_at": null,
"ref_index": 2,
"cited": false
}
],
"source_domains": ["research.example.com", "news.example.org"],
"web_search_triggered": true,
"search_queries": ["turn0search0", "turn0news1"],
"model": "gpt-5-5",
"conversation_id": "6a1f2c9e-3d54-4b17-9f0a-2c7de51b8a44",
"message_id": "b03d7f18-5c2a-49e6-8f31-77d1c0a9e512",
"country": "US",
"answer_length": 366,
"citation_count": 2,
"latency_ms": 24817,
"created_utc": 1754323200.0,
"created_at": "2026-08-04T16:00:00Z"
}
search_results is the full retrieved set; citations is the subset that made
it into the answer. When web_search_triggered is false, both are empty and
ChatGPT answered from its own knowledge — that is a valid response, not an
error.Asking about an image
Attach a picture and ChatGPT answers about it.image_url works on GET and
POST; image_base64 is POST only.
curl -X POST "https://scrapebadger.com/v1/chatgpt/ask" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "What product is in this photo, and what is it usually used for?",
"image_url": "https://example.com/product.jpg"
}' \
--max-time 150
import base64, requests
with open("product.jpg", "rb") as fh:
encoded = base64.b64encode(fh.read()).decode()
res = requests.post(
"https://scrapebadger.com/v1/chatgpt/ask",
headers={"X-API-Key": "YOUR_API_KEY"},
json={
"prompt": "What product is in this photo, and what is it usually used for?",
"image_base64": encoded,
},
timeout=150,
)
print(res.json()["answer"])
import { readFile } from "node:fs/promises";
const encoded = (await readFile("product.jpg")).toString("base64");
const res = await fetch("https://scrapebadger.com/v1/chatgpt/ask", {
method: "POST",
headers: {
"X-API-Key": process.env.SCRAPEBADGER_API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
prompt: "What product is in this photo, and what is it usually used for?",
image_base64: encoded,
}),
signal: AbortSignal.timeout(150_000),
});
console.log((await res.json()).answer);
An image ChatGPT cannot read is a
400 with "code": "invalid_image", raised
before the request reaches a browser — so a broken picture never costs you
credits. Sending both image_url and image_base64 is also a 400.ChatGPT is non-deterministic. The same prompt can return different wording and
different sources on each call. For tracking, sample on a schedule and
aggregate.

