When using the web search API, I want to get Citations so i can parse them out into my web app. however, whe i make a request to the API, the Annotations array is always empty.
for example, this prompt will not return any citations:
Please give me a short summary of the alcohol laws in ${userQuery}? Try to include regulatory bodies if you can find them.
this prompt WILL
Please give me a short summary of the alcohol laws in ${userQuery}? Try to include regulatory bodies if you can find them. please include citations
the problem is that the citations, when requested in the prompt, will appear both in the annotations array AND in the text response from the model. The citations in the text response are really messy and verbose. I’d rather have them just in the citations array so i can parse them out myself.
is this a bug or am I dont something wrong?
4 Likes
I have similar problem
I tested about 400 different prompts in web_search_preview Responses API and results are mostly without annotations (citations),
while the same prompts in UI get citations (in text + explicit in sources list) .
This seems to be a bug for me - but I’m not sure because sometimes , very rarely I see some annotations (in last attempt it was 1 out of 50 prompts).
Example prompt:
What are the best practices for selecting and negotiating terms with logistics service providers in emerging markets?
For such case when we add to prompt text:
“… please enchance results with citations and links”
it will fill the “annotations” response field.
It appeared to not be working for me at first but I managed to get some consistent results with this code:
# Define a basic prompt.
prompt = (
"Give me the first paragraph of one recent article about the US economy."
)
# Create the streaming response.
response = client.responses.create(
model="gpt-4o",
tools=[{"type": "web_search_preview"}],
input=prompt,
stream=True,
)
story_text = ""
annotations = [] # We'll collect raw annotation objects here.
# Process each event from the response.
for event in response:
# For text delta events (which deliver parts of the story text)
if event.type == "response.output_text.delta":
delta = event.delta
# If delta is a dict, it may contain text and annotations.
if isinstance(delta, dict):
story_text += delta.get("text", "")
# If the delta includes annotations, add them.
if "annotations" in delta:
annotations.extend(delta["annotations"])
else:
story_text += delta
# Some annotation events come separately.
elif event.type == "response.output_text.annotation.added":
# These events include an 'annotation' attribute.
annotations.append(event.annotation)
# Optionally, sort annotations by their starting index.
annotations.sort(key=lambda ann: ann.start_index if hasattr(ann, 'start_index') else 0)
# Print the final raw story text.
print("Story Summary:\n")
print(story_text.strip())
# Print the raw annotation objects.
print("\nRaw Annotations:")
for ann in annotations:
# Print the entire annotation as a Python dictionary.
print(ann)