MYFRESHTOOLS
50% OFF
YouTube › Deleted Video Finder

Detect Deleted and Private Videos in a Playlist With the YouTube Data API

For anyone who'd rather write twenty lines than click through a UI — the exact field to check, batching, quota, and where the API stops being useful.

Updated 27 September 2026 · 8 min read
Quick answer
Call playlistItems.list with part=snippet,status and check snippet.title for the literal strings "Deleted video" or "Private video" — that's the most reliable signal the API gives you for a dead playlist entry. It costs 1 quota unit per call regardless of page size, and it can't recover the original title, since that string has already replaced it. For that last step, either build your own archive cross-reference or paste the playlist into MyFreshTools Deleted Video Finder instead.

If you're maintaining a scheduled check across many playlists, or building this into a larger tool, clicking through a UI one playlist at a time doesn't scale. The YouTube Data API can tell you which entries in a playlist are dead — the trick is knowing which field to actually check, since the API doesn't expose a clean isDeleted boolean.

The field names and exact response shapes below reflect the API as documented at the time of writing — Google does revise these occasionally, so verify against the current playlistItems and videos reference before you hard-code a check into production.

The core trick

The actual signal: title becomes a literal string

When a video referenced by a playlist item is deleted or made private, playlistItems.list doesn't fail or omit the item — it still returns a row, but snippet.title is replaced with the literal text "Deleted video" or "Private video", and the thumbnail set comes back empty. Checking for those two exact strings is simpler and more reliable than trying to infer status from missing fields, which can also happen for other reasons.

snippet.title valueWhat it means
"Deleted video"The video was removed from YouTube entirely.
"Private video"The video still exists but is restricted to its owner or invited viewers.
Any other stringThe video is live and playable as far as this call can tell.
Working example

Scanning a playlist's items

Using google-api-python-client, paginate through every item and flag the dead ones:

from googleapiclient.discovery import build

youtube = build("youtube", "v3", developerKey=API_KEY)

def scan_playlist(playlist_id):
    dead = []
    request = youtube.playlistItems().list(
        part="snippet,status",
        playlistId=playlist_id,
        maxResults=50,
    )
    while request:
        response = request.execute()
        for item in response["items"]:
            title = item["snippet"]["title"]
            if title in ("Deleted video", "Private video"):
                dead.append({
                    "position": item["snippet"]["position"],
                    "videoId": item["snippet"]["resourceId"]["videoId"],
                    "status": title,
                })
        request = youtube.playlistItems().list_next(request, response)
    return dead

list_next handles the nextPageToken chase for you — a 5,000-video playlist takes about 100 calls at 50 items per page.

A second signal

Cross-verifying with videos.list

A video can also be unreachable for reasons that don't produce the literal "Deleted video" string — region-locked licensing being the main one. To double-check a batch of IDs against a second signal, call videos.list and see which ones simply don't come back:

def verify_ids(video_ids):
    resp = youtube.videos().list(
        part="id",
        id=",".join(video_ids[:50]),
    ).execute()
    found = {item["id"] for item in resp["items"]}
    return [vid for vid in video_ids if vid not in found]

An ID that doesn't come back at all from videos.list is gone or blocked from your key's context — that's a useful second confirmation alongside the title-string check, not a replacement for it.

Don't burn your key

Batching and quota, so you don't burn your key

Both playlistItems.list and videos.list cost a flat 1 quota unit per call, regardless of how many items or IDs you request in that call — which is exactly why you should always batch:

  • videos.list accepts up to 50 comma-separated IDs per call. Sending them one at a time turns a 1-unit job into a 50-unit one for no benefit.
  • playlistItems.list already batches by page — always request the maximum maxResults=50 rather than a smaller page size.
  • Standard projects get a default daily quota (Google's console shows your current allocation, and it does change — check it rather than assuming a fixed number) shared across every call your key makes, not just this one.

Poll on a schedule, don't hammer it

There's no push notification for a video's status changing. If you're monitoring the same playlists repeatedly, space out your polling interval — checking a slow-moving playlist every few minutes burns quota for no new information.
Be honest about this

What the API can't tell you

  • The reason. A copyright takedown, a manual deletion and a channel termination all produce the same "Deleted video" string — there's no field that distinguishes them.
  • The original title. Once it's replaced, it's gone from this response. Recovering it means cross-referencing outside records — search caches, metadata archives, anything that indexed the video while it was still live.
  • A truly private video's contents. If it belongs to someone else's account, no API key or public call will ever read it — that's the platform working as intended, not a gap to work around.

The tool

How MyFreshTools helps

What the tool does

The Deleted Video Finder runs the same underlying scan described above — pagination, status detection, all of it — and adds the step the raw API can't do on its own: cross-referencing each dead entry's ID against outside records to recover the original title and channel wherever one survives.

Who it's for

  • Developers who want the answer for one or two playlists without provisioning an API key and quota.
  • Anyone who wrote the scan above and now needs the title-recovery step it doesn't cover.
  • Teams who'd rather not maintain a scheduled job for something they check occasionally.

Requirements and limits

  • A free MyFreshTools account. No card, free credits on signup.
  • Free scans list every hidden entry with position and status, and reveal one recovered title as a sample; a paid plan reveals them all.
  • It recovers metadata only, never the video file, and title recovery is best-effort — the same public-record dependency described above applies here too.

Frequently asked questions

No. Once a video is gone, the API returns the literal string "Deleted video" or "Private video" in place of the title — the original text isn't preserved anywhere in that response.

A plain API key is enough to call playlistItems.list on a public playlist. You only need OAuth if you're reading a private or unlisted playlist that isn't yours, or one belonging to a signed-in user.

About 100, at the maximum 50 items per page, following nextPageToken until it's empty — each call costs 1 quota unit regardless of how many items it returns.

No. It distinguishes deleted from private in the title string, but it can't tell you whether a deletion was voluntary, a copyright takedown, or a channel termination — those all look the same from the outside.

Not through the public Data API. Detecting a change means polling on a schedule and diffing against your last known state yourself.

The takeaway

The Data API gives you exactly one clean signal for a dead playlist entry — the literal title string — and nothing about why it happened or what the video used to be. That's a fine trade for a scheduled automated check; for the "what was it" question, you still need a title-recovery step layered on top, whether you build it or borrow it.

Related MyFreshTools tools