The YouTube Data API no longer returns related videos. Google deprecated search.list's relatedToVideoId parameter and removed it from the documentation, so the API has no related-videos filter now. Our YouTube API returns a video's related list, 20 videos a call, and pages further with a cursor.
What the YouTube Data API is for
The YouTube Data API lists videos, channels, playlists and comments, and searches them by keyword. search.list used to take relatedToVideoId and return videos like the one you named. YouTube announced the deprecation in June 2023 and stopped supporting the parameter that August. You can search by the video's title, but that returns search results, not the list YouTube shows next to the video.
Related videos with ToolzerHub
We make ToolzerHub. Our YouTube API returns public YouTube channels, videos and comments as JSON with one API key and no Google project. Two routes cover this, each 1 credit a call:
/v2/youtube/related: a video's related list, about 20 a page, withpage_cursorfor the next page/v2/youtube/video: up to 20 video IDs a call, with exact views
export TOOLZERHUB_API_KEY=your_key
curl -H "x-api-key: $TOOLZERHUB_API_KEY" \
"https://api.toolzerhub.com/v2/youtube/related?video_reference=https://www.youtube.com/watch?v=dQw4w9WgXcQ"
The second related video in data.data, trimmed:
{
"type": "video",
"videoId": "izGwDsrQ1eQ",
"title": "George Michael - Careless Whisper (Official Video)",
"channelId": "UCR1LVH-teuA3-Kfy576TYSw",
"channelTitle": "George Michael",
"publishedTimeText": "17y ago",
"lengthText": "5:01"
}
video_reference takes a watch link or an ID. The response's meta block describes the seed video, with its exact viewCount and channelId. Related items carry no view count, so pass their IDs to the video route. Use publishedTimeText for age; publishDate on related items holds a placeholder date.
Save a video's related list to CSV
The script takes video links, reads the pages you ask for, keeps each video once and adds view counts in batches of 20. It writes one row per related video with its rank, channel, views, length and age, and prints how many channels the list draws from. Install requests (pip install requests) and save it as youtube_related_videos.py.
import csv
import os
import statistics
import sys
import time
import requests
API = "https://api.toolzerhub.com/v2/youtube"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["seed", "rank", "video_id", "title", "channel", "same_channel", "views", "length", "age", "url"]
def get(op, params, tries=3):
# Retry rate limits, server errors and dropped connections.
for attempt in range(tries):
last = attempt == tries - 1
try:
r = requests.get(f"{API}/{op}", headers=HEADERS, params=params, timeout=120)
except requests.RequestException:
if last:
raise
time.sleep(5 * (attempt + 1))
continue
if r.status_code in (429, 500, 502, 503, 504) and not last:
time.sleep(5 * (attempt + 1))
continue
r.raise_for_status()
return r.json()["data"]
def views(ids):
# The video route returns at most 20 videos per call.
counts = {}
for i in range(0, len(ids), 20):
for v in get("video", {"video_references": ",".join(ids[i:i + 20])}) or []:
counts[v["id"]] = int(v["viewCount"]) if v.get("viewCount") else None
return counts
def main(videos, pages="3", out="youtube_related_videos.csv"):
with open(out, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=FIELDS)
writer.writeheader()
for seed in filter(None, (v.strip() for v in videos.split(","))):
related, seen, cursor, meta = [], set(), None, {}
for _ in range(int(pages)):
data = get("related", {"video_reference": seed, **({"page_cursor": cursor} if cursor else {})})
meta = meta or data.get("meta") or {}
for v in data.get("data") or []:
if v.get("type") == "video" and v["videoId"] not in seen:
seen.add(v["videoId"])
related.append(v)
cursor = data.get("page_cursor")
if not cursor:
break
counts = views([v["videoId"] for v in related])
for rank, v in enumerate(related, 1):
writer.writerow({
"seed": meta.get("videoId", seed), "rank": rank, "video_id": v["videoId"], "title": v["title"],
"channel": v.get("channelTitle"), "same_channel": v.get("channelId") == meta.get("channelId"),
"views": counts.get(v["videoId"]), "length": v.get("lengthText"),
"age": v.get("publishedTimeText"), "url": f"https://www.youtube.com/watch?v={v['videoId']}",
})
same = sum(v.get("channelId") == meta.get("channelId") for v in related)
known = [n for n in counts.values() if n]
print(f"{meta.get('title', seed)[:50]}: {len(related)} related videos from "
f"{len({v.get('channelId') for v in related})} channels, {same} from the same channel, "
f"median {statistics.median(known or [0]):,.0f} views")
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit("usage: python youtube_related_videos.py <video links or ids, comma-separated> [pages] [out.csv]")
if not HEADERS["x-api-key"]:
sys.exit("set TOOLZERHUB_API_KEY first")
main(*sys.argv[1:])
What four videos' related lists showed
Three pages each for 3Blue1Brown's neural network video, Steve Jobs's Stanford speech, Tim Urban's TED talk and Rick Astley's Never Gonna Give You Up made 24 calls in 51 seconds and saved 239 related videos:
python youtube_related_videos.py "https://www.youtube.com/watch?v=aircAruvnKk,https://www.youtube.com/watch?v=UF8uR6Z6KLc,https://www.youtube.com/watch?v=arj7oStGLkU,https://www.youtube.com/watch?v=dQw4w9WgXcQ" 3
| Seed video | Related saved | Channels | From the seed's channel | Median views | Under a year old |
|---|---|---|---|---|---|
| 3Blue1Brown, neural networks | 59 | 40 | 10 | 1,327,378 | 43 |
| Stanford, Steve Jobs speech | 60 | 47 | 2 | 3,632,562 | 16 |
| TED, Tim Urban | 60 | 34 | 11 | 4,359,292 | 32 |
| Rick Astley | 60 | 50 | 5 | 74,577,077 | 20 |
Only 2 to 11 of each 60 came from the seed's own channel. 43 of the 59 videos next to the neural network lesson were under a year old, against 16 next to the Jobs speech. Six of Rick Astley's related videos have more views than its 1.83 billion, Gangnam Style at 6.1 billion the largest.
What it costs
A seed video is 6 credits at three pages: three related pages and three view batches. The 100 free credits a month cover 16 videos at that depth; $19 buys 10,000 credits that never expire, and plans for higher volume cover more videos. Set your key and the first related list is a CSV in under a minute.
For a channel's own uploads, see get all videos from a YouTube channel. For keyword results, see the YouTube search API quota, and for search-box suggestions, the YouTube autocomplete API.
We are not affiliated with YouTube or Google.