# ChatGPT Results Scraper: Answers, Citations & Screenshots (`mrbridge/chatgpt-results-scraper`) Actor

Scrape ChatGPT answers and search results for any question, with no login and no API key. Get cited sources with URLs, images, tables, product cards and a screenshot of each answer, from 20 countries. Export JSON, CSV or Markdown, run via API, schedule runs or integrate with AI workflows.

- **URL**: https://apify.com/mrbridge/chatgpt-results-scraper.md
- **Developed by:** [MrBridge](https://apify.com/mrbridge) (community)
- **Categories:** SEO tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.70 / 1,000 query answereds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## ChatGPT Results Scraper

ChatGPT Results Scraper sends your questions to chatgpt.com as a logged-out visitor and returns what a person would see on screen. You get the answer in Markdown, plain text and HTML, plus the cited sources, the images, the tables, the place and product cards, a screenshot and ready-made files. It needs no OpenAI account, no API key and no browser on your side, because the pages are opened in hosted browsers that exit from the country you choose.

Ask it "best restaurant in the 15th arrondissement of Paris" with country `US` and you get one dataset row with the full answer as Markdown, a `sources` list (title, URL and domain for each cited page), a `status`, the time it took in milliseconds, and links to an `answer-` Markdown file, an `item-` JSON file and a `screenshot-` PNG of that answer. Send 200 questions in one run and you also get `results.md`, `results.json` and `citations.csv` covering the whole batch, which load straight into a spreadsheet.

### What is ChatGPT Results Scraper?

The Actor reads answers to your own prompts. It does not log in, it does not use the OpenAI API, and it does not touch anyone's account. Each query runs in a fresh remote browser that exits from the country you choose, so the answer reflects what a visitor in that country gets.

It is useful for:

- **Answer monitoring**: track how ChatGPT answers the same question over time or from different countries.
- **Source and citation analysis**: see which domains ChatGPT cites for a topic, with `citations.csv` ready for pivot tables.
- **Local and shopping research**: collect the product cards ChatGPT shows next to an answer.
- **Content and brand checks**: compare the answer text with your own pages and with competitors.

#### What data can I extract with ChatGPT Results Scraper?

| Field | What it holds |
|---|---|
| `query`, `country` | The question and the exit country used |
| `status`, `error`, `attempts` | Outcome of the query and how many engine calls it took |
| `answerMarkdown`, `answerText`, `answerHtml` | The answer in three formats |
| `sources[]` | Cited pages: `position`, `title`, `url`, `domain`, `publisher`, `snippet` |
| `products[]` | Product cards: `name`, `price`, `merchant`, `url` |
| `tables[]` | Tables of the answer: `index`, `caption`, `headers`, `rows` |
| `images[]` | Images of the answer: `position`, `imageUrl`, `alt`, `pageTitle`, `publisher`, `context`, `sourcePosition`, `collageCount` |
| `screenshotUrl`, `files` | Links to the screenshot and to the saved files |
| `conversationUrl`, `responseTimeMs`, `fetchedAt` | Shared conversation link, timing and timestamp |
| `provider` | Which browser network served the last attempt: `primary`, `fallback`, or `fixture` (local test runs only), and `null` for `invalid_input` items |

#### How are sources and links handled?

`sources` lists every web page cited in the answer: the links in the text and the pages behind each citation bullet. Pages are numbered in reading order, and each citation bullet in `answerMarkdown` shows the numbers of its pages, so `[2]` is `sources[1]`. A bullet whose pop-up could not be read is written `[?]`. An answer that cites nothing has an empty `sources` list.

`url` is null when the page could not be opened without leaving the answer. `domain`, `publisher` and `title` are always filled for a page behind a citation bullet, with the site name in `publisher` and the excerpt shown in the pop-up in `snippet` (300 characters at most). A link of the text has `publisher` and `snippet` set to null. Pages are merged when they share a URL, and pages without URL when they share a domain and a title.

- Map links, shopping product links, links to chatgpt.com or openai.com and links that only wrap an image are left out of `sources`. They stay links in the answer.
- `answerMarkdown` and `sources[].url` have the `utm_source` tracking parameter removed. `answerHtml` keeps the original links exactly as ChatGPT rendered them, `utm_source` included.
- A shopping answer can have `sources: []`, because its links live in `products[].url`.

#### How are images handled?

`images` lists the pictures ChatGPT shows with the answer, in reading order: the image cards of the text, the pictures of an image mosaic, then the thumbnails of the citation pop-ups. An answer without pictures has an empty `images` list.

- `imageUrl` is an absolute `https` URL. Icons and site favicons are left out, and a URL that appears twice is listed once.
- `context` is `card` for an image card of the text, `collage` for a picture of a mosaic, and `popover` for the thumbnail of a citation pop-up entry.
- `pageTitle` is the title of the page the picture comes from, and `publisher` is the site name when the page gives one. `alt` is the picture's own description, and it can be empty for a pop-up thumbnail.
- `collageCount` is the number shown on the badge of a mosaic, which can be larger than the number of pictures listed. It is `null` for other pictures.
- `sourcePosition` is set for a `popover` picture. It is the `position` of the matching entry in `sources`, or `null` when that entry is not in `sources`.
- `answerMarkdown` shows each `card` and `collage` picture as `![alt](imageUrl)` where it stands in the answer. `answerText` is unchanged, and `answerHtml` keeps `src` on the pictures.

Image URLs point to ChatGPT's image cache. They work outside ChatGPT at the time of the run but may stop working later. Download the images you want to keep. The Actor does not download the files itself.

### How to use ChatGPT Results Scraper

1. Create a free [Apify account](https://apify.com/sign-up?fpr=mrbridge).
2. Open [ChatGPT Results Scraper](https://apify.com/mrbridge/chatgpt-results-scraper?fpr=mrbridge).
3. Type one question per line in **Queries**, and pick a country.
4. Click **Start** and wait for the run to finish.
5. Read the dataset, or open the key-value store to download the files.

### How much will scraping ChatGPT cost you?

ChatGPT Results Scraper uses a **pay-per-event** pricing model. One event is charged for each query that returns an answer. Queries that end in an error status are not charged, and neither are invalid inputs.

See the [Pricing tab](https://apify.com/mrbridge/chatgpt-results-scraper/pricing?fpr=mrbridge) for the current price. Set a maximum cost per run in the run options and the Actor stops cleanly when that limit is reached, leaving the remaining queries unprocessed.

### ⬇️ Input

The input is a JSON object with a list of queries and a few optional settings. See the [Input tab](https://apify.com/mrbridge/chatgpt-results-scraper/input-schema?fpr=mrbridge) for the full schema.

| Field | Type | Default | Description |
|---|---|---|---|
| `queries` | array of strings | required | 1 to 200 questions, each 1 to 2,000 characters |
| `country` | string | `US` | Exit country of the browser, picked from a menu of 20 countries (see below). Lowercase codes are accepted in API calls |
| `saveFiles` | boolean | `true` | Save per-query and per-run files in the key-value store |
| `screenshot` | boolean | `true` | Save a screenshot of each answer |

Every query waits up to 120 seconds for its answer. ChatGPT answers in the language of your question. The former `engine`, `maxWaitSeconds` and `language` fields no longer exist. If an input still contains them, they are ignored and the run log says so.

Supported countries: United States (`US`), Australia (`AU`), Austria (`AT`), Belgium (`BE`), Brazil (`BR`), Canada (`CA`), Denmark (`DK`), France (`FR`), Greece (`GR`), India (`IN`), Italy (`IT`), Japan (`JP`), Mexico (`MX`), Netherlands (`NL`), Poland (`PL`), Spain (`ES`), Sweden (`SE`), Switzerland (`CH`), Turkey (`TR`) and United Kingdom (`GB`). The list only holds countries where the answer was checked to come back localized for that country.

A blank or over-long query does not stop the run. It produces one `invalid_input` item and the other queries go on.

#### ChatGPT Results Scraper input example

```json
{
  "queries": [
    "best restaurant in the 15th arrondissement of Paris",
    "meilleur caviste à Bruxelles"
  ],
  "country": "FR",
  "saveFiles": true,
  "screenshot": true
}
```

#### Calling the Actor from the API

Run it synchronously and receive the dataset items in the response. Replace `YOUR_APIFY_TOKEN` with your own token.

```bash
curl -X POST "https://api.apify.com/v2/acts/mrbridge~chatgpt-results-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"queries": ["best wine shop in Brussels"], "country": "US"}'
```

For long batches, start the run asynchronously and read the dataset when it finishes. See the [Apify API reference](https://docs.apify.com/api/v2?fpr=mrbridge) and the API tab of the Actor.

### ⬆️ Output

Each query produces one dataset item, in the order the queries finish. The item below comes from a local test run on a recorded fixture, with the HTML, the image URL and the file links shortened. The `provider` value is set to `primary` to show what a platform run returns, where the local value is `fixture`. On the platform the file links are `https://api.apify.com/...` URLs of your run's key-value store.

```json
{
  "query": "meilleur caviste à Bruxelles",
  "status": "ok",
  "error": null,
  "provider": "primary",
  "attempts": 1,
  "country": "US",
  "conversationUrl": "https://chatgpt.com/uc/6acf5558-7c34-83ea-8d88-9893243ab1ba",
  "answerMarkdown": "Si je devais recommander les meilleurs cavistes à Bruxelles, je distinguerais les spécialistes du vin naturel, les caves traditionnelles avec de belles bouteilles et les adresses idéales pour trouver un vin original sans se ruiner.\n\n## Mon top des cavistes à Bruxelles\n\n## 1. Cave 1929\n\nRue de Rollebeek 38, 1000 Bruxelles\n\nUne cave familiale historique, avec plus de 1 500 références [...]",
  "answerText": "Si je devais recommander les meilleurs cavistes à Bruxelles [...]",
  "answerHtml": "<p>Si je devais recommander [...]</p>",
  "sources": [],
  "products": [],
  "tables": [],
  "images": [
    {
      "position": 1,
      "imageUrl": "https://images.openai.com/static-rsc-4/[...]?purpose=inline",
      "alt": "CAVE 1929 | caviste indépendant | Rue de Rollebeek 38, Bruxelles, Belgique",
      "pageTitle": "CAVE 1929 | caviste indépendant",
      "publisher": "Rue de Rollebeek 38, Bruxelles, Belgique",
      "context": "card",
      "sourcePosition": null,
      "collageCount": null
    }
  ],
  "screenshotUrl": null,
  "files": {
    "markdownUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/answer-meilleur-caviste-a-bruxelles-bdd9f9.md",
    "jsonUrl": "https://api.apify.com/v2/key-value-stores/STORE_ID/records/item-meilleur-caviste-a-bruxelles-bdd9f9.json",
    "tableCsvUrls": []
  },
  "filesWarning": null,
  "responseTimeMs": 15,
  "fetchedAt": "2026-10-16T09:16:13.265Z"
}
```

The recorded fixture has no cited links, so `sources` is empty here. On a live answer, a link of the text and a page behind a citation bullet look like this:

```json
{ "position": 1, "title": "Time Out Paris", "url": "https://www.timeout.fr/paris/restaurants", "domain": "timeout.fr", "publisher": null, "snippet": null }
{ "position": 2, "title": "Webb Measures Distance to Farthest Fast Radio Burst, Suggesting Origin", "url": null, "domain": "science.nasa.gov", "publisher": "NASA Science", "snippet": "October 8, 2026, First discovered in 2007, fast radio bursts are enigmatic, millisecond-long flashes of radio emission from the distant universe." }
```

Notes on the structured fields:

- `products[]` is filled only when ChatGPT displays shopping cards for the answer.
- `tables[]` holds each table of the answer with its headers and rows, numbered from 1 in reading order.
- `images[]` holds the pictures of the answer, see above. The `publisher` is read from the text after the last `|` of the `alt`, so a page title that itself contains a `|` can be cut at the wrong place, as in the example.
- `provider` is `primary` or `fallback` on the platform and `fixture` for local test runs only. It is `null` for `invalid_input` items. Some countries are served directly by the fallback browser network, usually with a single attempt. `attempts` counts every engine call made for the query.
- `filesWarning` is set when the answer was delivered but one upload to the key-value store failed. The matching link is then `null`.

#### Downloaded files

The `screenshot-<slug>.png` record depends only on `screenshot`, and the other records on `saveFiles`. The Actor writes them to the run's key-value store. Open the store from the **Storage** tab of the run, where each kind of file has its own tab (answers, items, screenshots, tables, and the three run files), or fetch a record at `https://api.apify.com/v2/key-value-stores/STORE_ID/records/KEY`.

| Record | Content |
|---|---|
| `answer-<slug>.md` | The answer in Markdown (`ok` items only) |
| `item-<slug>.json` | The full dataset item for that query (`ok` items only) |
| `table-<slug>-<n>.csv` | One CSV per table, `n` starting at 1 (`ok` items only) |
| `screenshot-<slug>.png` | Screenshot of the answer, when `screenshot` is on |
| `results.md` | All queries of the run, one top-level heading per query, error items included |
| `results.json` | The array of all dataset items, error items included |
| `citations.csv` | One row per source: query, position, title, url, domain, publisher, snippet. An empty cell stands for a null value |

The slug is the query in lowercase with non-alphanumeric characters replaced by `-`, cut to 60 characters, then a dash and six hexadecimal characters that keep similar queries apart. A query with no Latin letter and no digit (for example one written only in Japanese, or only punctuation) has an empty base: the slug is `q-` followed by 6 hexadecimal characters, such as `q-3fa9c1`. Two identical queries in one run share a slug and the later one overwrites the files, though each keeps its own dataset row.

Screenshots exist only as `screenshot-<slug>.png`. The dataset holds the link in `screenshotUrl` and never the image data. A screenshot is also taken on `blocked`, `no_answer` and `timeout` items to help you see what happened. An item in an error status has at most its screenshot: the answer, item and table files are written for `ok` items only, while `results.md` and `results.json` still list the queries that ended in error.

In the CSV files, a cell that starts with `=`, `+`, `-`, `@`, a tab or a carriage return is prefixed with an apostrophe, so a spreadsheet shows it as text instead of running it. Valid negative numbers such as `-12.5` are left as they are.

#### Statuses and billing

| `status` | Meaning | Charged |
|---|---|---|
| `ok` | The answer was read | Yes |
| `invalid_input` | The query was blank or longer than 2,000 characters | No |
| `blocked` | chatgpt.com asked for a login or refused the visit | No |
| `no_answer` | The page loaded but no answer was found | No |
| `timeout` | The answer did not finish within 120 seconds | No |
| `engine_error` | The hosted browsers failed on every attempt | No |

The run log holds one line per failed attempt, with the query number, the attempt number and a short reason. Expect roughly 20 to 40 seconds per question, and longer in some countries.

Error items carry empty answer strings, empty arrays and a short `error` message. The run itself always ends as succeeded, so a bad query never fails your whole batch. If a file upload fails but the answer was read, the item is still `ok` and still charged, because the answer is what you pay for.

### Limits of version 1.1

- The Actor opens at most 20 citation bullets per answer and spends at most 20 seconds on them and on their pages. A bullet left closed is matched to a listed page of the same site when there is one. Otherwise it is written `[?]`.
- The address of a page behind a citation bullet is only known when its opening can be caught without leaving the answer. Otherwise its `url` is null.
- Deep research and some other prompt types can ask for a login. They return `blocked`.
- Shopping answers are normal `ok` items with `products[]` filled. Their `sources` is often `[]`, because their links are merchant links already present in `products[].url`.
- Availability of logged-out answers varies by country and by prompt, and chatgpt.com changes its interface often. A query that worked last week can return `blocked` or `no_answer` today.

### Frequently asked questions

#### How does ChatGPT Results Scraper work?

For each query it opens chatgpt.com in a hosted browser, types the question, waits for the answer to finish, then reads the page and builds the item. Up to three queries run at the same time.

#### Do I need an OpenAI account or API key?

No. The Actor visits chatgpt.com the way a logged-out visitor does. It does not use the OpenAI API, so the answers are those of the public web interface.

#### Is the answer the same as the one I get in my own account?

Not necessarily. Logged-out answers can differ from signed-in ones, and they depend on the country you set.

#### Which country should I choose?

The one whose visitors you want to simulate, among the 20 in the menu. The default is `US`. ChatGPT answers in the language of your question, so there is no language setting.

#### Can I integrate it with other apps?

Yes. Datasets and files can be sent to Make, Zapier, n8n, Google Sheets and webhooks through the [Apify integrations](https://apify.com/integrations?fpr=mrbridge).

#### Can I use ChatGPT Results Scraper as its own API?

Yes. Call it through the Apify API or the `apify-client` packages for Node.js and Python, as in the example above.

#### Can I use ChatGPT Results Scraper via MCP?

Yes. AI assistants such as Claude or ChatGPT can call it through the Apify MCP server. Open the MCP tab of the Actor for setup, or connect to [mcp.apify.com](https://mcp.apify.com?fpr=mrbridge) and add this Actor as a tool.

#### Do the image links keep working?

They point to ChatGPT's image cache and they open outside ChatGPT at the time of the run. They may stop working later, so download the images you want to keep.

#### Why is `sources` empty on a shopping answer?

The links of a shopping answer are product cards, and they are returned in `products[].url` instead.

#### Why did a query end in `engine_error`?

The hosted browsers could not open chatgpt.com from the chosen country after three attempts, or the connection dropped while the answer was being written, or the page did not load after a retry. This happens now and then in some countries. The item is not charged, and running the same query again later usually works. If the main network keeps failing for a country during a run, the remaining queries of that run switch to the second network.

#### Your feedback

We are always working on improving the Actors. If you have technical feedback or found a bug, please open a ticket in the Actor's [Issues tab](https://apify.com/mrbridge/chatgpt-results-scraper/issues?fpr=mrbridge).

More tools, scrapers, MCP servers and data studies from the same team: [mr-bridge.com](https://mr-bridge.com).

### Legal & responsible use

The Actor only reads the answers to the prompts you send. It uses no account, no login and no personal data of other people. Your prompts and the answers are your responsibility, so do not send personal data you have no right to process.

Automated access to chatgpt.com is a matter of OpenAI's terms of service. Read them and decide whether your use is acceptable for you and your organization. Results can contain personal data, which is protected by the [GDPR](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation) in the European Union and by other regulations elsewhere. If you are unsure about your use, consult a lawyer. You can also read the Apify blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/?fpr=mrbridge).

ChatGPT Results Scraper is an independent tool and is not affiliated with or endorsed by OpenAI.

# Changelog

This Actor's version history is a separate document: https://apify.com/mrbridge/chatgpt-results-scraper/changelog.md

# Actor input Schema

## `queries` (type: `array`):

One query per item. Each query is typed into chatgpt.com as a logged-out visitor. 1 to 200 queries, each 1 to 2,000 characters. Blank or over-long queries produce an invalid_input item and are never charged.

## `country` (type: `string`):

Country the requests leave from. The answer is localized as for a visitor in that country.

## `saveFiles` (type: `boolean`):

Save per-query files (Markdown, JSON, table CSVs) and per-run files (results.md, results.json, citations.csv) in the key-value store.

## `screenshot` (type: `boolean`):

Capture a screenshot of each answer and save it in the key-value store.

## Actor input object example

```json
{
  "queries": [
    "best restaurant in the 15th arrondissement of Paris"
  ],
  "country": "US",
  "saveFiles": true,
  "screenshot": true
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `resultsJson` (type: `string`):

No description

## `resultsMarkdown` (type: `string`):

No description

## `citationsCsv` (type: `string`):

No description

## `answersFiles` (type: `string`):

No description

## `itemsFiles` (type: `string`):

No description

## `screenshotsFiles` (type: `string`):

No description

## `tablesFiles` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "queries": [
        "best restaurant in the 15th arrondissement of Paris"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrbridge/chatgpt-results-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "queries": ["best restaurant in the 15th arrondissement of Paris"] }

# Run the Actor and wait for it to finish
run = client.actor("mrbridge/chatgpt-results-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "queries": [
    "best restaurant in the 15th arrondissement of Paris"
  ]
}' |
apify call mrbridge/chatgpt-results-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrbridge/chatgpt-results-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/WJTaMChP7n1qgs560/builds/fEuHTmmu8UinB4o4m/openapi.json
