AnswerLine Start free

ChatGPT

ChatGPT sources

Every page ChatGPT cited in its answer, in order, with the inline chips that group them.

The `sources` array lists each cited page with position, URL, label and description. `citationPills` records which sources sit behind each inline chip, one entry per chip and source.

Together they show which pages feed an answer, how often a domain is cited, and which competitors' pages are cited instead of yours.

Returned in result

Field
sources
citationPills

Request

curl -X POST "https://api.answerline.dev/v1/monitor/chatgpt" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"What are the best running shoes for flat feet?","country":"US","include":{"markdown":true}}'

What ChatGPT’s sources are

A ChatGPT source is a web page the answer cites. When ChatGPT searches the web, it shows citation chips next to the sentences they support and a sources list that opens below the answer. This API returns both: sources is the full ordered list, and citationPills records which pages sit behind each inline chip.

A mention says ChatGPT named your brand; a citation says which page it relied on, and that page is something you can update, earn coverage on or outrank. Citation data tells you which pages feed the answers in your category and what share of citations goes to your domain versus competitors, the AI counterpart of organic share of voice. sources[].footnote would mark a page listed but cited by no chip; it is false on every answer served today, since every listed source is cited by a chip.

Field reference

result.sources[]

Field Type Meaning
position number Position of the source in the response.
url string URL of the cited page.
label string Article title of the source.
description string Snippet or summary of the page.
footnote boolean true when the source is listed but cited by no chip. false on every answer served today.
datePublished string Publication date. Omitted when the page has no publish date; never null.

sources is always an array; it is empty when the answer has no sources. It lists each page once, in the order the answer first cites it.

result.citationPills[]

Field Type Meaning
url string, required URL of the citation.
label string, required Per-source title. Always present, may be an empty string; use domain or url for identity then.
description string Snippet. Only on searchResult entries; omitted when there is none.
domain string, required Domain of the cited source.
datePublished string ISO 8601 publication date. Omitted when unknown.
citationPillId integer, required 0-based ID shared by every entry from the same chip.
type searchResult or groupedWebpage, required searchResult for a chip citing one page, groupedWebpage for a chip citing several.
position integer, required 1-based position of this source in result.sources.

Each citationPills entry is one (chip, page) pair. A chip that cites three pages produces three entries with the same citationPillId. A page cited by several chips appears under each, so repeat citations count. citationPills is absent when the answer has no chips.

Annotated excerpt

Values are illustrative; field names and types follow the POST /v1/monitor/chatgpt result schema.

{
  "success": true,
  "result": {
    "text": "For a small sales team, a CRM with built-in email sequencing...",
    "sources": [
      {
        "position": 1,
        "url": "https://www.example-reviews.com/best-crm-small-business",
        "label": "The Best CRM Software for Small Businesses",
        "description": "We compared pricing, automation and onboarding...",
        "footnote": false,
        "datePublished": "2026-07-28"
      },
      {
        "position": 2,
        "url": "https://docs.example-crm.com/sequences",
        "label": "Email sequences",
        "description": "Automate follow-ups from the pipeline view...",
        "footnote": false
        // No datePublished: the page has none, so the key is omitted.
      }
    ],
    "citationPills": [
      {
        "url": "https://www.example-reviews.com/best-crm-small-business",
        "label": "The Best CRM Software for Small Businesses",
        "domain": "example-reviews.com",
        "description": "We compared pricing, automation and onboarding...",
        "citationPillId": 0,          // ChatGPT counts chips from 0
        "type": "searchResult",       // this chip cites one page
        "position": 1                 // points to result.sources[0]
      },
      // Chip 1 cites two pages: a groupedWebpage, no description.
      {
        "url": "https://www.example-reviews.com/best-crm-small-business",
        "label": "The Best CRM Software for Small Businesses",
        "domain": "example-reviews.com",
        "citationPillId": 1,
        "type": "groupedWebpage",
        "position": 1                 // cited again: listed once in sources
      },
      {
        "url": "https://docs.example-crm.com/sequences",
        "label": "Email sequences",
        "domain": "docs.example-crm.com",
        "citationPillId": 1,
        "type": "groupedWebpage",
        "position": 2
      }
    ]
  }
}

Cost and request options

sources and citationPills come with every ChatGPT result: $0.0006 at the Starter tier. Every include flag but include.html is free. include.searchQueries is empty on the answers served today; see query fan-out.

ChatGPT decides on its own whether to search; disableWebSearch changes nothing today. provenance.webSearchTriggered is true when ChatGPT was seen searching, even if it then cited nothing. Compute citation metrics over answers that searched and report the share without.

Example: citation share by domain

The script runs each prompt several times as async tasks, polls until they finish, and computes two numbers per domain. Answer share is the fraction of answers that cite the domain at least once; report this one (“cited in 7 of 10 answers”). Citation share is the domain’s share of all inline citations, which rewards domains cited repeatedly within an answer.

import os
import time
from collections import Counter
from datetime import date
from urllib.parse import urlparse

import requests

API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
PROMPTS = ["best CRM for a 10-person sales team", "HubSpot vs Pipedrive for small business"]
SAMPLES = 5
DAY = date.today().isoformat()


def run_tasks(tasks):
    resp = requests.post(f"{API}/v1/async/task/batch", headers=HEADERS, json=tasks, timeout=60)
    resp.raise_for_status()
    pending = {item["task"]["id"] for item in resp.json()["results"] if item["success"]}
    results = []
    while pending:
        time.sleep(10)
        for task_id in list(pending):
            body = requests.get(f"{API}/v1/async/task/{task_id}", headers=HEADERS, timeout=30).json()
            status = body["task"]["status"]
            if status in ("COMPLETED", "FAILED"):
                pending.discard(task_id)
                if status == "COMPLETED":
                    results.append(body["response"]["result"])
    return results


def host(url):
    name = urlparse(url).hostname or ""
    return name.removeprefix("www.")


tasks = [
    {
        "taskType": "CHATGPT",
        "payload": {"prompt": prompt, "country": "US"},
        "idempotencyKey": f"crm-sources-{p}-s{s}-{DAY}",
    }
    for p, prompt in enumerate(PROMPTS)
    for s in range(SAMPLES)
]
answers = run_tasks(tasks)

answer_hits = Counter()
inline = Counter()
for result in answers:
    answer_hits.update({host(src["url"]) for src in result.get("sources", [])})
    inline.update(host(pill["url"]) for pill in result.get("citationPills", []))

total_inline = sum(inline.values()) or 1
print(f"{len(answers)} answers")
for domain, hits in answer_hits.most_common(15):
    print(f"{domain:40} answers {hits / len(answers):5.0%}   inline {inline[domain] / total_inline:5.0%}")

Hosts are taken from URLs with www. stripped so sources and citationPills count the same way. Store the raw results as well, so you can recompute share for a different domain grouping (for example, rolling subdomains into one brand) without paying for the runs again.

Pitfalls

A chip citing three pages is three citationPills entries. To count visible chips, count distinct citationPillId values per answer.

ChatGPT’s citationPillId starts at 0 and the other engines’ at 1. position is 1-based everywhere and is the safer join key into sources.

datePublished and description are omitted when missing, never null, and a pill can carry label: "". Read optional keys with .get() and group by domain or url, not title.

footnote is false on every answer served today, so every source in sources is also cited by a chip. Keep a filter on it if your metric must count only chip-cited pages.

Cited pages change between runs and between markets. Keep the market fixed within a series and report rates with the sample size; answer volatility covers how many samples to take.

Questions

Do I need an include flag to get ChatGPT sources?

No. sources and citationPills are part of every ChatGPT result at the base price: $0.0006 at the Starter tier.

What is the difference between sources and citationPills?

sources lists each cited page once, where it is first cited. citationPills has one entry per chip and page pair for the citations shown inline in the answer text, so a page cited by several chips appears under each. citationPillId regroups chips and position points back into sources.

Why do ChatGPT citationPillId values start at 0?

ChatGPT's citationPillId is 0-based, while Google AI Overview, AI Mode, Copilot, Perplexity and Gemini use 1-based IDs. Normalize before comparing engines, or join on position, which is 1-based everywhere.

Why are sources empty on some ChatGPT answers?

ChatGPT decides on its own whether to search the web, and a search can end with nothing cited. disableWebSearch changes nothing today. provenance.webSearchTriggered is true when ChatGPT was seen searching or the answer cites sources.

Should citation share be counted by domain or by URL?

Both are useful, but not in the same metric. Use citationPills[].domain, or the host of sources[].url, for domain share, and the full sources[].url for page-level share.

More ChatGPT data

All ChatGPT fields · API reference