# YouTube Channel Earnings Estimator: Revenue, CPM & Views (`moggedhq/youtube-earnings-estimator`) Actor

Estimate how much a YouTube channel earns per month from ads, for a list of channels, e.g. MrBeast or a cooking channel. About $0.02 per channel. Monthly earnings range, recent views, Shorts vs long-form, niche RPM, sponsorship value. Money calculator, no login.

- **URL**: https://apify.com/moggedhq/youtube-earnings-estimator.md
- **Developed by:** [mogged](https://apify.com/moggedhq) (community)
- **Categories:** Social media
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $16.00 / 1,000 channel estimates

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## YouTube Channel Earnings Estimator: Revenue, CPM & Views

For creators, agencies and brands comparing the earning potential of YouTube channels before researching a partnership. About **$0.02 per channel**: checking 20 channels costs about **$0.40**, plus Apify's small start charge. Enter a handle or channel link and receive a readable ad-revenue scenario with the public counts and assumptions behind it.

**These are conditional estimates, not verified income.** A channel's monetization status, audience locations and private YouTube Analytics are unavailable. Actual earnings may be zero. Current views on recently uploaded videos are kept separate from estimated monthly traffic. The output does not claim that upload dates reveal when all channel views occurred.

### What you get

One paid row per unique, successful channel estimate, verdict first. Every run has a free summary row, `SUMMARY` record and `REPORT.html`. Export JSON for nested evidence or CSV for selected columns.

| Field | Meaning |
| --- | --- |
| `verdict` | Conditional monthly ad-revenue scenario, currency and recent-upload context |
| `recordType` | `channel_estimate`, free `note`, or free `summary` |
| `channelId`, `channelName`, `channelUrl`, `handle` | Resolved public channel identity |
| `monthlyEarnings.low`, `.mid`, `.high` | Working range and midpoint in the selected currency |
| `scenarioLowUsd`, `scenarioHighUsd`, `extremeScenarios` | Broad sensitivity endpoints in USD and selected currency |
| `workingRangeMethod`, `monthlyViewAllocation` | Planning convention and separate format allocations |
| `yearlyEarnings` | Monthly values multiplied by 12, not a seasonal forecast |
| `estimatedMonthlyViews` | Modelled low/high view scenario and named calculation method |
| `viewsOnUploadsLast30Days` | Current cumulative views on sampled videos published within 30 days |
| `viewsOnUploadsLast90Days` | The corresponding 90-day upload cohort |
| Cohort `.total`, `.longForm`, `.shorts`, `.unknownFormat` | Separate counters; unknown formats remain explicitly unknown |
| `uploadsLast30Days`, `uploadsLast90Days` | Observed upload counts inside each publication window |
| `uploadsPerMonth` | Observed 90-day upload count divided by three |
| `totalViews`, `subscribers` | Public channel counters; subscribers may be rounded |
| `channelCreatedAt`, `channelAgeDays` | Public join date and calculated age |
| `lifetimeAverageViewsPerMonth` | Total channel views divided by age in 30.4375-day months |
| `channelCountry` | Profile country, which is not the audience's country |
| `niche`, `category`, `nicheEvidence` | Keyword inference, available video category and matched terms |
| `rpmAssumptions` | Published benchmark ranges, model adjustments, format shares and sources |
| `sponsorshipValuePerVideo` | Separate planning ranges for a sponsored integration or Short |
| `monetizationStatus`, `monetized` | `unknown` and `null`; subscriber counts do not prove monetization |
| `history` | Baseline, elapsed time and measured net public-counter change when available |
| `coverage` | Checked videos, failed IDs, source and 30/90-day completeness flags |
| `sampledVideos` | Video IDs, links, publication dates, views, category and format used |
| `exchangeRate` | Currency conversion rate, date and source |
| `warnings`, `observedAt` | Material limitations and observation time |

### Start in three steps

1. Add one or more channels, such as `@MrBeast`, an exact channel name, or a full YouTube channel URL. An exact handle or channel ID is the most dependable input.
2. Use at least 512 MB memory. Keep USD or choose another supported currency. Set your maximum charge in Apify before starting. Leave the history group unchanged when you want future runs to compare with previous observations.
3. Read the verdict, coverage flags and warnings together. Open `REPORT.html` for a readable report or export the dataset for your workflow. Filter `recordType == "channel_estimate"` when processing estimates programmatically.

```json
{
  "channels": ["@MrBeast", "@mkbhd"],
  "currency": "USD",
  "historyNamespace": "default"
}
```

| Input | Default | Details |
| --- | --- | --- |
| `channels` | Small prefilled example | List of public handles, channel IDs, exact names or channel/video links |
| `currency` | `USD` | USD needs no rate lookup; other currencies use Frankfurter's latest daily rate |
| `historyNamespace` | `default` | A 1-32 character group using lowercase letters, digits and hyphens |
| `query`, `queries`, `keywords` | Empty | Alternative channel inputs for agents and automation |
| `urls`, `startUrls` | Empty | Optional URL-list aliases; `startUrls` accepts objects containing `url` |

Unknown currencies, ambiguous names, missing channels and malformed inputs become free notes. Duplicate handles are removed before fetching; different addresses resolving to the same channel produce only one charged estimate. A name is accepted only when its resolved channel matches it.

### How the view estimate works

The first run reads public channel data and up to 100 uploads. Exact watch-page dates and views are checked for candidates within roughly 125 days, plus the first ten uploads. Relative upload ages only select candidates. Some watch pages expose dates without times, so window boundaries can vary by a day. Cohorts group videos by publication date; they do not date individual views.

Let `C30` be current views on the observed 30-day upload cohort. Let `L` be lifetime average monthly channel views. Let `W` be the fraction of the public upload count older than the observed 30-day cohort. With complete 30-day coverage, `W = max(0, 1 - recentUploadCount / totalVideoCount)`; otherwise it is one.

- The low monthly-view scenario is `C30`.
- The high scenario is `max(C30, C30 + L * W)`.
- Broad monetary scenarios apply the endpoint RPM assumptions to those view endpoints.
- The headline working range instead uses midpoint views and the 25%-75% interior of the assumed RPM interval. Its midpoint leads the verdict. This creates a range no wider than 3x by construction; it is not an observed percentile distribution, a likely interval, or an accuracy guarantee. Broad endpoints remain in `scenarioLowUsd`, `scenarioHighUsd` and `extremeScenarios`.

The backlog allowance is an unvalidated heuristic. Viral, deleted or inactive content can make it poor. Partial cohort totals are lower bounds; income endpoints are **not** confidence limits or guaranteed bounds.

### History and weekly schedules

The Actor saves public channel totals and timestamps in its own named key-value store, `youtube-earnings-estimator-<historyNamespace>`. It retains at most one observation per UTC day for roughly 120 days. Keep the same namespace and run account for comparisons. Delete this Actor's history store to reset it.

When an observation is between 7 and 100 days old, the baseline nearest 30 days is used. The measured net change is current total views minus that baseline. Dividing by elapsed days gives `history.measuredViewsPerDay`. A nonnegative daily rate multiplied by 30 replaces both monthly-view scenario endpoints; RPM uncertainty still produces an earnings range.

Weekly schedules measure **net public-counter change**; future traffic and income remain estimates. Removals and revisions affect counters. Negative changes trigger the first-run fallback. Avoid overlapping runs for the same namespace because history writes are not transactional.

### RPM, CPM and monetization assumptions

RPM describes creator revenue per thousand views. CPM describes advertiser spend per thousand ad impressions. They are not interchangeable, and this Actor does not observe an advertiser CPM or actual creator RPM. Sponsor integration CPM is a separate planning assumption.

The long-form starting bands are published benchmark ranges from [vidIQ's RPM guide](https://vidiq.com/blog/post/youtube-rpm/): finance 4-12 USD, business 4-9, technology 4-10, education 2-6, health/fitness and food 2-5, travel and gaming 2-4, entertainment 1-2, and children's content 0.5-1. A general fallback uses a deliberately broad 0.5-6. Keyword classification is fallible; matched terms are returned. One isolated keyword cannot override an entertainment or gaming category.

Benchmarks include revenue beyond ads. To construct an ad-only proxy, the lower endpoint uses a modelled 50% ad share and the upper endpoint uses 100%. Geography adjustments are also **model assumptions**, not measured audiences: profile countries in the high-ad-demand group use multipliers 0.7-1.3; India, Indonesia, Philippines, Pakistan and Bangladesh use 0.15-0.5; other or missing countries use 0.25-1.3. They are not claims about actual viewers.

Shorts use country points published by [AIR Media-Tech](https://air.io/en/monetization/what-rpm-can-you-expect-from-shorts-in-2026), with an explicit 0.5-1.5 scenario multiplier. Missing countries use 0.008-0.328 USD. No evidence-backed Shorts niche multiplier is available here, so it remains one. Public Shorts plays are not the engaged views used for Shorts revenue; the model assumes a 25%-100% engaged share, which is unmeasured and can be wrong. Unknown video formats span both formats' rates.

[YouTube explains the revenue denominators](https://support.google.com/youtube/answer/9314357?hl=en), while [its public view-count definition](https://developers.google.com/youtube/v3/docs/videos#statistics.viewCount) changed in August 2026. Old benchmark rates may therefore be less comparable with today's public counts. Ad blocking, eligibility, seasonality, copyrighted material, audience mix and deals can change earnings substantially. Every verdict is conditional on monetization. No positive lower bound on actual earnings is claimed.

### Sponsorship scenario

Median lifetime views from up to ten sampled videos aged 7+ days are multiplied by $20-$40 integration CPM, or $30-$60 for finance, business, technology and education. Shorts use half that value. This reuses the engagement estimator's rate method with a neutral engagement adjustment. Fewer than two videos of a format produces null. Values are planning assumptions, not observed deals.

### Price and spending limits

| Successful channel estimates | Base estimate charge |
| --- | --- |
| 1 | $0.02 |
| 20 | $0.40 |
| 50 | $1.00 |
| 100 | $2.00 |

Bronze is $0.019 per channel, Silver $0.018, and Gold or higher $0.016. Apify's start charge is $0.00005 per GB, with a minimum of one start charge. Platform usage is included in this Actor's price. Notes, failures, duplicates and summaries have no estimate charge. A useful partial estimate is charged and clearly marked as partial. The spending limit is checked before another channel starts, and the row is delivered with its charge. The Actor stops cleanly if the next estimate will not fit.

### Real example

A cloud run on 14 October 2026 returned this result in 18.2 seconds. Counts change over time. Verdict numbers use two significant figures; numeric fields retain precision. The range is conditional.

```json
{
  "verdict": "If monetized, about $230,000 a month from ads (planning range $130,000 to $320,000); 60M views on recent uploads, education niche.",
  "channelName": "Kurzgesagt \u2013 In a Nutshell",
  "currency": "USD",
  "monthlyEarnings": {
    "low": 131948.96,
    "mid": 226602.83,
    "high": 321256.69
  },
  "scenarioLowUsd": 30987.56,
  "scenarioHighUsd": 486251.46,
  "viewsOnUploadsLast30Days": {
    "total": 59818328,
    "longForm": 57125862,
    "shorts": 2692466,
    "unknownFormat": 0
  },
  "niche": "education",
  "monetizationStatus": "unknown"
}
```

### API and integrations

Python with `apify-client`:

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("moggedhq/youtube-earnings-estimator").call(
    run_input={"channels": ["@MrBeast"], "currency": "USD"}
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row.get("recordType") == "channel_estimate":
        print(row["verdict"])
```

For REST clients, POST the input JSON to `/v2/acts/moggedhq~youtube-earnings-estimator/runs`, authenticate with a Bearer token, then retrieve the run's default dataset and key-value records. Prefer asynchronous runs for large batches. Use Sheets, Make, n8n or webhooks; filter out notes and summaries. Keep the namespace unchanged on schedules.

### Use with AI agents (MCP)

Connect an Apify-capable agent to `https://mcp.apify.com`. Ask it to find a YouTube channel earnings estimator, read the input schema, and compare a list of channels. Specify currency and maximum charge. Keep coverage, warnings and the monetization condition beside every number. Public Store discovery requires publication.

### Limits and FAQ

**Are these actual earnings?** No. They are modelled ad scenarios conditional on monetization. Memberships, merchandise, sponsorships and affiliate income are not added to the ad estimate. Sponsor values are a separate output.

**Does a zero recent-upload count mean zero traffic?** No. Older videos can still earn views. The first-run model includes a transparent backlog allowance, and later snapshot measurements can capture net growth without new uploads.

**Does the Actor cover the entire channel?** It reads the first upload page, up to 100 items. Fast uploaders may exceed that inside a month. Missing dates, unavailable videos or a Videos-tab fallback reduce coverage, which is reported explicitly. It does not silently invent the missing uploads.

**Do I need a login or outside API key?** No. The Actor reads public signed-out pages, uses no account cookies, solves no CAPTCHA, and needs no paid outside service. Currency conversion uses Frankfurter's public daily rates. Unsupported currencies produce a free note instead of silently returning the wrong currency.

YouTube channel earnings estimates, YouTube revenue scenarios, and a transparent YouTube money calculator with evidence you can inspect.

# Actor input Schema

## `channels` (type: `array`):

Handles, exact channel names or URLs, for example @mkbhd or https://www.youtube.com/@MrBeast. Returns conditional monthly ad estimates, not verified earnings.

## `currency` (type: `string`):

Three-letter currency code. USD default; EUR, GBP, ZAR, INR and other Frankfurter-supported currencies use the latest daily rate. Unsupported codes produce a free note.

## `historyNamespace` (type: `string`):

Optional snapshot group using lowercase letters, numbers and hyphens, maximum 32 characters. Keep it unchanged for weekly comparisons. History measures net public-view-counter changes, not private Analytics.

## `query` (type: `string`):

Optional alternative to channels. Supply public YouTube channel handles or URLs.

## `queries` (type: `array`):

Optional alternative to channels. Supply public YouTube channel handles or URLs.

## `keywords` (type: `array`):

Optional alternative to channels. Supply public YouTube channel handles or URLs.

## `urls` (type: `array`):

Optional alternative to channels. Supply public YouTube channel handles or URLs.

## `startUrls` (type: `array`):

Optional alternative to channels. Supply public YouTube channel handles or URLs.

## Actor input object example

```json
{
  "channels": [
    "@kurzgesagt"
  ],
  "currency": "USD",
  "historyNamespace": "default"
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `report` (type: `string`):

No description

# 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 = {
    "channels": [
        "@kurzgesagt"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("moggedhq/youtube-earnings-estimator").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 = { "channels": ["@kurzgesagt"] }

# Run the Actor and wait for it to finish
run = client.actor("moggedhq/youtube-earnings-estimator").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 '{
  "channels": [
    "@kurzgesagt"
  ]
}' |
apify call moggedhq/youtube-earnings-estimator --silent --output-dataset

```

## MCP server setup

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

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/FPRqKF6LXvFOX33x8/builds/rFo0abEJoIEB3Kbnr/openapi.json
