Perplexity media results
The contract fields for the videos and images Perplexity attaches to answers. They come back empty today.
`videos` and `images` are fields of the Perplexity contract. The answers served today carry the text, sources and citation pills only, so both come back empty.
Returned in result
| Field |
|---|
videos |
images |
Request
curl -X POST "https://api.answerline.dev/v1/monitor/perplexity" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt":"Which project management tools do agencies use?","country":"US"}'
What Perplexity’s media results are
Media results are the videos and images Perplexity attaches to an answer. The API returns them as two arrays, videos and images, with the same item shape: a title, the media URL, a thumbnail, the source platform and dimensions.
A brand can be absent from the text and sources and still be the video a reader watches, or have its product photo shown for a comparison prompt. The media rate per prompt shows where video or image content can earn a slot, the share of items by source shows which platforms supply them, and each item’s url identifies the site behind it, so your own media can be tracked like a citation.
Field reference
result.videos[] and result.images[] share one item schema, MediaItem.
| Field | Type | Meaning |
|---|---|---|
title |
string | Media title. |
url |
string | The page the media comes from. |
thumbnail |
string | The picture Perplexity shows. |
medium |
video or image |
Media type. |
source |
string | Source platform. |
image_width |
number | Original image width. |
image_height |
number | Original image height. |
thumbnail_width |
number | Thumbnail width. |
thumbnail_height |
number | Thumbnail height. |
The contract’s medium enum also has map; Perplexity’s map comes back as places instead, so images holds photos only.
Annotated excerpt
Values are illustrative; field names follow the POST /v1/monitor/perplexity result schema.
{
"success": true,
"result": {
"text": "To replace a bike chain, first measure wear with a chain checker...",
"sources": [
{ "position": 1, "url": "https://www.example-cycling.com/replace-chain", "label": "How to replace a chain", "description": "Step by step..." }
],
"videos": [
{
"title": "Replace a bike chain in 5 minutes",
"url": "https://video.example.com/watch/abc123",
"thumbnail": "https://img.example.com/abc123/thumb.jpg",
"medium": "video",
"source": "video.example.com", // platform string: normalize before counting
"thumbnail_width": 320,
"thumbnail_height": 180
}
],
"images": [
{
"title": "Chain checker tool on a drivetrain",
"url": "https://www.example-cycling.com/images/chain-checker.jpg",
"thumbnail": "https://img.example.com/t/chain-checker.jpg",
"medium": "image",
"source": "example-cycling.com",
"image_width": 1200,
"image_height": 800
}
]
}
}
Cost and include flag
There is no media include flag: videos and images come with every answer that shows them, and the price is the same either way: $0.0015. include.markdown, include.html and include.rawResponse add nothing. A media study pays for every prompt run, including runs that show no media, so budget on prompts times samples.
Example: platform share and media trigger rate
The script samples each prompt, then reports per prompt the fraction of runs that returned videos or images, and across all runs each platform’s share of videos and images and how often your own domain supplied them.
import os
import time
from collections import Counter, defaultdict
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 = [
"how to replace a bike chain",
"best commuter bike under $800",
"what does a worn cassette look like",
]
SAMPLES = 5
DAY = date.today().isoformat()
MY_HOSTS = {"example-cycling.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"]: item["index"] 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"):
index = pending.pop(task_id)
if status == "COMPLETED":
results.append((tasks[index]["payload"]["prompt"], body["response"]["result"]))
return results
def platform(item):
name = item.get("source") or urlparse(item.get("url", "")).hostname or "unknown"
return name.lower().removeprefix("www.")
tasks = [
{
"taskType": "PERPLEXITY",
"payload": {"prompt": prompt, "country": "US"},
"idempotencyKey": f"bike-media-{p}-s{s}-{DAY}",
}
for p, prompt in enumerate(PROMPTS)
for s in range(SAMPLES)
]
runs = run_tasks(tasks)
per_prompt = defaultdict(Counter)
share = {"videos": Counter(), "images": Counter()}
own = Counter()
for prompt, result in runs:
per_prompt[prompt]["runs"] += 1
for kind in ("videos", "images"):
items = result.get(kind) or []
per_prompt[prompt][kind] += bool(items)
share[kind].update(platform(i) for i in items)
own[kind] += sum(platform(i) in MY_HOSTS for i in items)
for prompt, c in per_prompt.items():
print(f"{prompt:40} videos {c['videos'] / c['runs']:5.0%} images {c['images'] / c['runs']:5.0%}")
for kind, counts in share.items():
total = sum(counts.values()) or 1
top = ", ".join(f"{name} {n / total:.0%}" for name, n in counts.most_common(5))
print(f"{kind}: {top} (yours {own[kind] / total:.0%})")
The helper keeps each task’s prompt with its result by mapping the returned task id to the batch index, so rates can be grouped per prompt. The source value is used when present; otherwise the host of url stands in for the platform.
Pitfalls
A prompt can show videos in one run and none in the next. Measure the trigger rate over several samples, with the market fixed, before concluding that a prompt “has” media; see answer volatility.
source is a free-text string. Lower-case it, strip www., and keep a mapping table for platforms that appear under more than one name.
Width and height fields may be missing on an item, so don’t filter on them without a default.
thumbnail is a separate URL from the media itself and may be on a different host. Attribute content by url.
Related
- Perplexity engine guide: sync and async calls, webhooks, geo targeting and billing.
- Perplexity sources for citations and Perplexity shopping for product, place and hotel blocks.
- Monitor Perplexity with an API for the full response walkthrough.
- Prompt set design for choosing prompts that separate how-to, product and local intent.
- Brand protection and AI visibility tracking.
Questions
How do I get the videos and images from a Perplexity answer?
result.images holds the pictures Perplexity shows with its answer, in their order, with no include flag to set. result.videos holds the videos it shows; none appeared on the prompts we checked, so it is often absent.
How much do Perplexity media results cost?
Nothing extra. Every Perplexity request costs $0.0015, whether or not the answer contains media.
What fields does a Perplexity media item have?
title, url (the page the picture comes from), thumbnail (the picture shown), medium (image or video), source (the source platform), and the dimensions image_width, image_height, thumbnail_width and thumbnail_height.
Why are videos or images missing?
The answer showed none: a how-to or local prompt often shows pictures, a definition rarely. A missing list is absent, not empty, so read it with a default.
How do I measure which video platforms Perplexity shows?
Count videos[].source across a fixed prompt set, falling back to the host of videos[].url when source is missing, and divide each platform's count by all videos. Report the share of answers that showed any video next to it.