# YouTube Channel Monitor - Deletions & Retitles (`gganbukim/youtube-channel-monitor`) Actor

Watch channels on a schedule and get only what changed: videos that disappeared, videos that were quietly retitled, new uploads, and how fast views are moving. YouTube keeps no record of a deleted or renamed video, so this is data only a watcher has. Remembers between runs.

- **URL**: https://apify.com/gganbukim/youtube-channel-monitor.md
- **Developed by:** [DONGMIN KIM](https://apify.com/gganbukim) (community)
- **Categories:** Social media, Videos, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 change reporteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## YouTube Channel Monitor — What a Channel Quietly Changed

Every other YouTube Actor sells you a **snapshot**: here is the channel as it looks today.
This one sells the **diff**, and the diff holds facts a snapshot structurally cannot.

- **A video disappeared.** Deleted, made private, or pulled after a claim. YouTube keeps no public record of this — the video is simply not in the listing any more. Only somebody who saw it yesterday knows it existed.
- **A video was retitled.** Creators A/B-test titles and replace the ones that underperform. The new title is public. The old one is gone the second it changes.
- **How fast views are moving.** A snapshot gives a total. Two snapshots give a rate, which is the number that says whether something is actually working.

None of it can be bought back later. It accrues only to whoever was watching.

### What it does well

- **Deletion detection** — the signal nothing else on this store reports.
- **Retitle history** — old title, new title, and how many times that video has been renamed since you started watching.
- **View velocity** — views gained and a per-day rate, normalised so a schedule that drifts does not distort it.
- **First run is quiet by design** — it records a baseline and reports nothing, so you are not billed for a channel's entire back catalogue as "news".
- **Switch off what you do not want** — anything not reported is not billed.

### How it works

Run 1 records what is there. Every later run compares and reports the difference. History
lives in a **named** key-value store so it survives between runs — see the note below,
because getting that wrong turns a monitor into a slower channel scraper.

### Input

```jsonc
{
  "channelUrls": ["@competitor-one", "@competitor-two"],
  "tab": "videos",
  "maxVideosPerChannel": 300,
  "watchDisappearances": true,
  "watchRetitles": true
}
```

#### Every option

The same wording you see in the Apify console, with the JSON key for API and MCP callers.

| Option | What it does | Default |
|---|---|---|
| **Channels to watch** — `channelUrls` *(required)* | @handles, /channel/UC… URLs, or legacy /c/ and /user/ URLs. Each channel's history is tracked separately. | — |
| **Which videos** — `tab` | Long-form uploads, Shorts, past live streams, or everything. Each tab is its own history, so switching starts a fresh baseline. | `"videos"` |
| **Max videos watched per channel** — `maxVideosPerChannel` | How deep into the back catalogue to watch. A video outside this window looks like it disappeared — see the warning below. | `200` |
| **Report videos that disappeared** — `watchDisappearances` | Deleted, private, or pulled. The listing does not say which, and neither does the row. | `true` |
| **Report retitled videos** — `watchRetitles` | Carries both the old and the new title. | `true` |
| **Report view movement** — `watchViewChanges` | One row per video whose views moved. Off by default because almost every video moves. | `false` |
| **Minimum views gained** — `minViewsGained` | Only applies to view movement. 0 disables. Filtered rows are not billed. | `0` |
| **Memory store name** — `memoryStoreName` | Named store holding the history. Different names give independent watchlists. | `"youtube-channel-state"` |
| **Reset memory** — `resetMemory` | Discard the history and make this run a fresh baseline. It reports nothing. | `false` |
| **Concurrency** — `concurrency` | Channels watched in parallel. | `3` |
| **Proxy** — `proxyConfiguration` | Leave the default. Reads listing pages only, so it stays on cheap datacenter proxies. | `{"useApifyProxy":true}` |

### Output

One row per change.

```json
{
  "event": "disappeared",
  "channelId": "UCBJycsmduvYEL83R_U4JriQ",
  "channelName": "Marques Brownlee",
  "channelUrl": "https://www.youtube.com/channel/UCBJycsmduvYEL83R_U4JriQ",
  "tab": "videos",
  "videoId": "wt4p2oalmRY",
  "url": "https://www.youtube.com/watch?v=wt4p2oalmRY",
  "title": "The video that is no longer listed",
  "viewCount": 812004,
  "firstSeenAt": "2026-07-02T09:00:00.000Z",
  "lastSeenAt": "2026-08-19T09:00:00.000Z",
  "daysWatched": 48.0,
  "titleChanges": 2,
  "detectedAt": "2026-08-20T09:00:00.000Z"
}
```

#### Every field

You are billed per change delivered, so here is everything a row can contain.

**On every row**

| Field | What it is |
|---|---|
| `event` | `disappeared`, `retitled`, `published` or `views-changed`. |
| `channelId` / `channelName` / `channelUrl` | The channel being watched. |
| `tab` | Which tab this history belongs to. |
| `videoId` / `url` | The video. |
| `title` | Its title now — or, on a `disappeared` row, the last title we saw. |
| `detectedAt` | When this run saw the change. The change itself happened between runs; YouTube publishes no timestamp for it. |

**On `retitled`**

| Field | What it is |
|---|---|
| `previousTitle` | What it was called before. This is the part that is gone from the public record the moment it changes. |
| `titleChanges` | How many times this video has been renamed since you started watching. A video on its fourth title is a video that is not working. |
| `viewCount` | Views at the time of the rename. |

**On `views-changed`**

| Field | What it is |
|---|---|
| `viewCount` / `previousViewCount` | Now, and at the previous run. |
| `viewsGained` | The difference. |
| `viewsPerDay` | That difference over the actual elapsed time — normalised, because a schedule does not land on exact intervals. |
| `daysSinceLastSeen` | How long the gap was. |

**On `disappeared`**

| Field | What it is |
|---|---|
| `viewCount` | The last view count we ever saw. Everything below is all that will ever be known about it, because the source is gone. |
| `firstSeenAt` / `lastSeenAt` | The window in which we saw it. |
| `daysWatched` | How long it survived under observation. |
| `titleChanges` | Whether it was being retitled before it went. |

**On `published`**

| Field | What it is |
|---|---|
| `viewCount` / `durationSeconds` / `publishedText` / `isShort` | The new video as first seen. |

### Two things that will bite you if nobody says them

**The first run reports nothing, and that is correct.** It records a baseline. If it
reported the whole back catalogue as "published", you would pay for a channel scrape and
call it news. Changes start from run two.

**Set the video window larger than the channel.** The monitor can only miss what it can
see. If a channel has 400 videos and **Max videos watched** is 200, the 201st video is
outside the window — and when the channel publishes something new, the oldest visible
video falls out and is reported as `disappeared` when it is still perfectly public. Leave
generous headroom, or watch a fixed window and accept the edge.

### Why the memory is a named store

Tracking lives in a **named** key-value store, not the default one. Apify's default store
is scoped to a single run: history kept there would be silently discarded every time, and
every run would record a fresh baseline and report nothing forever. That is the failure
mode this Actor is most exposed to, so it is pinned by name and covered by a test.

Use different `memoryStoreName` values for independent watchlists.

### Who this is for

- **Competitive intelligence teams** — what a rival pulled down, and what they renamed after it underperformed. YouTube keeps no record of either.
- **Brand safety owners** — get told when a video you are referenced in disappears.
- **Talent scouts** — `viewsPerDay` finds a channel accelerating before its totals look impressive.
- **Researchers** — a permanent record of videos that no longer exist publicly.

### Common uses

- **Competitor intelligence** — see what a rival pulled down, and what they renamed after it underperformed.
- **Title testing research** — `titleChanges` across a niche shows who is iterating and how hard.
- **Brand safety** — get told when a video you were referenced in disappears.
- **Talent scouting** — `viewsPerDay` finds a channel accelerating before its totals look impressive.
- **Archival** — a permanent record of videos that no longer exist publicly.

### Pricing

Pay per **change delivered**. Reports you switched off, rows removed by your filters, and
the entire first-run baseline **cost nothing**.

Starting a run costs $0.00002 — the platform's $0.00001 minimum, charged once per GB of
memory, and these Actors run on 2 GB. That is two thousandths of a cent per run.

Watching is the expensive part and you are not charged for it: a quiet day on a channel
that published nothing costs the run fee alone.

### Other Actors in this family

Same engines, same billing, no account or API key on any of them.

**YouTube & video**

- [Download YouTube Subtitles in Bulk — SRT, VTT & Text](https://apify.com/gganbukim/youtube-transcript-scraper) — Bulk subtitles from videos, channels or playlists — text, SRT, VTT or RAG chunks.
- [Export YouTube Comments to CSV — Replies and Likes](https://apify.com/gganbukim/youtube-comments-scraper) — Every comment and reply thread, with likes, authors and creator flags.
- [List Every Video on a YouTube Channel — Export to CSV](https://apify.com/gganbukim/youtube-channel-scraper) — A channel's whole back catalogue plus a subscriber and RSS summary row.
- [Find YouTube Sponsors — Brand Deals, Codes & Links](https://apify.com/gganbukim/youtube-sponsorship-finder) — Which brands pay which creators, with the campaign link, the code and the timestamp.
- [YouTube Search API — Bulk Results, No Quota](https://apify.com/gganbukim/youtube-search-scraper) — Many search terms at once, every result as a row, filtered before you are billed.
- [YouTube Creator Email Finder & Sponsor Lookup](https://apify.com/gganbukim/youtube-creator-leads) — A channel list into leads: the published email, audience bands, and who already sponsors them.
- [Export a YouTube Playlist to CSV — Every Video](https://apify.com/gganbukim/youtube-playlist-scraper) — Any playlist as a table, with each video position in it.

**Search demand**

- [AnswerThePublic Alternative — Autocomplete Keyword API](https://apify.com/gganbukim/long-tail-keyword-scraper) — One seed into hundreds of real keywords from Google, YouTube and Amazon autocomplete.
- [Google Trends API — Today's Trending Searches, No Key](https://apify.com/gganbukim/google-trends-scraper) — Today's trending searches by country, with traffic bands and the news behind them.

**E-commerce**

- [Export Any Shopify Store's Products to CSV or JSON](https://apify.com/gganbukim/shopify-product-scraper) — Any Shopify catalogue: variants, SKUs, live prices, stock, images, collections.
- [New Shopify Product Alerts — Competitor Drop Tracker](https://apify.com/gganbukim/shopify-new-arrivals-monitor) — Only what a store launched since the last run. Scanning is free.

**Hiring**

- [Greenhouse, Lever & Ashby Job Scraper — No API Key](https://apify.com/gganbukim/ats-job-scraper) — Paste a company domain, get its open roles from Greenhouse, Ashby, Lever or SmartRecruiters.
- [Ghost Job Detector — Track Reposts, Closures & Edits](https://apify.com/gganbukim/job-lifecycle-monitor) — What changed on a careers page: opened, closed, quietly reposted, or a ghost job.

### FAQ

**Will I get blocked, or my account banned?** There is no account to ban — no login, no cookies. It reads listing pages only, which is what makes daily monitoring cheap enough to be worth doing. YouTube signals throttling with an HTTP 200 and an error body rather than an error code, which is the trap that silently halves most scrapers' results; this one detects it by reason and rotates.

**Is it legal to monitor a YouTube channel?** It reads the same public listing pages a
browser requests, with no login and nothing bypassed. What it adds is your own record of
what changed between two public snapshots — data you created by watching. YouTube's Terms
of Service are a separate contract question. Not legal advice.

**Can it tell me *why* a video disappeared?** No, and it does not guess. Deleted, set to
private, and pulled after a claim look identical from the outside. The row says it is gone
and when it was last seen.

**How often should I run it?** Daily is the sweet spot for deletions and retitles. Hourly
rarely surfaces more and multiplies cost. For view velocity, match the interval to how
fast the channel moves.

**What if a run is interrupted?** State is saved per channel as each one completes, so an
interrupted run re-reads only the channels it had not finished.

**How much does 1,000 changes cost?** $2.00, plus $0.00002 for the run.

**Can I export the results to Excel or Google Sheets?** Yes. Every run's dataset downloads
as CSV, Excel, JSON, XML or RSS from the Storage tab, or straight from the API.

**Can I connect it to Zapier, Make or n8n?** Yes — Apify publishes integrations for all
three, plus webhooks that fire when a run finishes. A schedule here plus a webhook into
Slack is the usual setup.

**Do I need to write code?** No. Fill the form in the console and press Start. It is also
available over MCP so an AI agent can call it directly.

# Actor input Schema

## `channelUrls` (type: `array`):

@handles, /channel/UC… URLs, or legacy /c/ and /user/ URLs. Each channel's history is tracked separately.

## `tab` (type: `string`):

Which tab to watch. Each tab is tracked as its own history, so switching this starts a fresh baseline.

## `maxVideosPerChannel` (type: `integer`):

How deep into the back catalogue to watch. A video outside this window looks like it disappeared, so keep it comfortably larger than the channel.

## `watchDisappearances` (type: `boolean`):

A video that was in the listing and is gone: deleted, made private, or pulled. The listing does not say which, and neither does the row.

## `watchRetitles` (type: `boolean`):

Creators A/B-test titles and replace the ones that underperform. The row carries both the old and the new title.

## `watchViewChanges` (type: `boolean`):

One row per video whose view count moved, with views gained and a per-day rate. Off by default because it is the noisiest signal — almost every video moves.

## `minViewsGained` (type: `integer`):

Only applies to view movement. 0 disables. Filtered rows are not billed.

## `memoryStoreName` (type: `string`):

Named key-value store holding the history. Use different names for independent watchlists.

## `resetMemory` (type: `boolean`):

Discard the stored history and make this run a fresh baseline. It will report nothing.

## `concurrency` (type: `integer`):

Channels watched in parallel.

## `proxyConfiguration` (type: `object`):

Leave the default. This actor only reads listing pages, so it almost always stays on cheap datacenter proxies.

## Actor input object example

```json
{
  "channelUrls": [
    "@mkbhd"
  ],
  "tab": "videos",
  "maxVideosPerChannel": 200,
  "watchDisappearances": true,
  "watchRetitles": true,
  "watchViewChanges": false,
  "minViewsGained": 0,
  "memoryStoreName": "youtube-channel-state",
  "resetMemory": false,
  "concurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One row per change since the last run: a video that disappeared, was retitled, was newly published, or moved in views.

## `runSummary` (type: `string`):

Counts for this run: channels done, baselines recorded, changes delivered, rows filtered, videos being tracked, and failures.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "channelUrls": [
        "@mkbhd"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gganbukim/youtube-channel-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "channelUrls": ["@mkbhd"] }

# Run the Actor and wait for it to finish
run = client.actor("gganbukim/youtube-channel-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "channelUrls": [
    "@mkbhd"
  ]
}' |
apify call gganbukim/youtube-channel-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,gganbukim/youtube-channel-monitor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/yMQvWSZVZ0ywE9cKt/builds/rFJi2CZdGGZQccDzS/openapi.json
