AnswerLine Start free

Copilot

Copilot sources

The pages Copilot cites in each answer.

`sources` returns the cited pages in order, so citation share is measured the same way as on other engines. `citationPills` records which sources sit behind each inline chip. The searches Copilot ran are coming.

Returned in result

Field
sources
citationPills

Request

curl -X POST "https://api.answerline.dev/v1/monitor/copilot" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"Cheapest way to send money abroad","country":"US"}'

What Copilot’s sources are

A Copilot source is a web page Copilot cites for its answer. Copilot marks cited passages with chips and lists the referenced pages, and when several citations follow one another it groups them into one chip. This API returns the page list as sources and the chip structure as citationPills. Because Copilot searches before it answers, the queries it ran (searchQueries) are coming; they are not returned yet.

Today sources shows which pages Copilot cites in your category and how often your domain is one of them. Once searchQueries ships, one record will hold the prompt, the searches and the cited pages, so you can check whether a domain that is never cited doesn’t rank for the queries Copilot writes. The market changes the answer, so compare markets deliberately; see state-level AI answers.

Field reference

result.sources[]

Field Type Meaning
position number Where the page sits in Copilot’s reference list.
url string The cited page.
label string Title as Copilot shows it.

Copilot sources carry no description. Key on url.

result.citationPills[]

One row per (chip, source) pair, ordered to match the chips in the answer:

Field Type Meaning
citationPillId integer, required Which chip the row belongs to, counting chips from 1. Consecutive citations share a chip and therefore an id.
position integer, required Index into result.sources, counting from 1. This is the join key between the two arrays.
url string, required The cited page, as the chip links to it.
domain string, required Host taken from url.
label string, required Title of the cited page. Present on every row, but can be "".

A chip that groups three citations therefore produces three rows. The whole array is absent from result when the answer shows no chips at all.

result.searchQueries[]

Field Type Meaning
searchQueries[] string One web search query Copilot ran while generating the response.

Coming; not returned yet.

Annotated excerpt

A shortened response. The content is made up; the field names and types are those of the POST /v1/monitor/copilot result schema.

{
  "success": true,
  "result": {
    "text": "For a small team, a password manager with shared vaults and...",
    "sources": [
      {
        "position": 1,
        "url": "https://www.example-security.com/reviews/team-password-managers",
        "label": "Best team password managers"
      },
      {
        "position": 2,
        "url": "https://help.example-vault.com/sharing",
        "label": "Sharing items with your team"
      }
    ],
    "citationPills": [
      { "citationPillId": 1, "position": 1, "url": "https://www.example-security.com/reviews/team-password-managers", "domain": "example-security.com", "label": "Best team password managers" },
      { "citationPillId": 1, "position": 2, "url": "https://help.example-vault.com/sharing", "domain": "help.example-vault.com", "label": "Sharing items with your team" }
    ]
    // searchQueries is coming; not returned yet.
  }
}

Cost and request options

No include flag is needed for sources. A Copilot request costs $0.00274; include.markdown, include.rawResponse and include.rawWire (always null on Copilot) add nothing, and include.html is refused with a 400.

The request takes prompt and country; a request that sends state is refused with a 400. Keep the market fixed within a time series.

Example: citation share by domain

The script runs each prompt several times and computes answer share per domain: the share of answers that cite the domain at least once.

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 password manager for a small team", "1Password vs Bitwarden for business"]
SAMPLES = 5
DAY = date.today().isoformat()
MY_DOMAIN = "example-vault.com"


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 registrable(url):
    parts = (urlparse(url).hostname or "").split(".")
    return ".".join(parts[-2:])


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

answer_hits = Counter()
for result in answers:
    answer_hits.update({registrable(src["url"]) for src in result.get("sources", []) if src.get("url")})

n = len(answers) or 1
print(f"{len(answers)} answers")
for domain, hits in answer_hits.most_common(15):
    print(f"{domain:32} answers {hits / n:5.0%}")
print(f"{MY_DOMAIN} cited in {answer_hits[MY_DOMAIN] / n:.0%} of answers")

registrable here drops everything but the final two host labels. That merges help. and www. into one brand, which is what you want, and mis-groups .co.uk domains, which is not; reach for a public-suffix library if your query set is international.

Pitfalls

sources can be empty. Default it to an empty list. citationPills is absent when the answer shows no chips. searchQueries is not returned yet.

sources[].position is a number. Key on url when merging with other engines’ sources.

Copilot’s answers vary between runs of the same prompt, so measure citation share across many runs (sampling vs census).

Questions

Do I need an include flag to get Copilot sources?

No. sources is part of every Copilot result at the base price: $0.00274. The include flags for Copilot (markdown, rawResponse, rawWire) add nothing, and neither does citationPills.

Does Copilot return the searches it ran?

Not yet. searchQueries, the web search queries Copilot ran while generating the answer, is coming. Today a Copilot result carries the answer text, markdown and its cited sources.

How are Copilot citation pills grouped?

Copilot shows citations that follow one another as a single chip. Each source in a chip is its own citationPills entry, and all entries from one chip share a 1-based citationPillId.

Why is sources[].position a number rather than an integer for Copilot?

sources[].position is a number in the result schema. citationPills[].position is an integer and the 1-based index into sources, the join key between the two.

Can I measure Copilot citations by US state?

No. Copilot takes a country only. A request that sends state is refused with a 400 and not billed.

More Copilot data

All Copilot fields · API reference