A command-line tool for the YouTube Analytics API. It keeps a local copy of your daily numbers, which is what lets it compare one period against another, line several channels up side by side, and flag a day that looks off. The plain API can't do any of that on its own.
The YouTube Analytics API is really one endpoint, reports.query, and it answers with a column-array response that is awkward to read. This CLI wraps that endpoint in named reports (overview, top-videos, traffic, retention, revenue, demographics) and prints clean labeled tables instead. It also syncs your daily rows into a local SQLite database. That local copy is the part that matters: it is what makes period deltas, whatchanged diffs, anomaly checks, and multi-channel rollups work without re-querying the API every time.
Learn more about the API in Google's YouTube Analytics docs.
Built by @RyanCollinsAI.
The recommended path installs both the youtube-analytics-pp-cli binary and the pp-youtube-analytics agent skill (Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, and other agents supported by the upstream skills CLI) in one shot:
npx -y @mvanhorn/printing-press install youtube-analyticsFor the CLI only (no skill):
npx -y @mvanhorn/printing-press install youtube-analytics --cli-onlyFor the skill only (this skips the CLI binary, so use it to update or reinstall just the skill):
npx -y @mvanhorn/printing-press install youtube-analytics --skill-onlyTo limit the skill install to one or more specific agents (repeatable; agent names match the skills CLI):
npx -y @mvanhorn/printing-press install youtube-analytics --agent claude-code
npx -y @mvanhorn/printing-press install youtube-analytics --agent claude-code --agent codexThe generated install path is category-agnostic until this CLI is published. If npx is not available before publish, install Node or use the category-specific Go fallback from the public-library entry after publish.
Download a pre-built binary for your platform from the latest release. On macOS, clear the Gatekeeper quarantine: xattr -d com.apple.quarantine <binary>. On Unix, mark it executable: chmod +x <binary>.
From the Hermes CLI:
hermes skills install mvanhorn/printing-press-library/cli-skills/pp-youtube-analytics --forceInside a Hermes chat session:
/skills install mvanhorn/printing-press-library/cli-skills/pp-youtube-analytics --forceTell your OpenClaw agent (copy this):
Install the pp-youtube-analytics skill from https://github.com/mvanhorn/printing-press-library/tree/main/cli-skills/pp-youtube-analytics. The skill defines how its required CLI can be installed.
This CLI ships an MCPB bundle, which is Claude Desktop's standard format for one-click MCP extension installs (no JSON config required).
To install:
- Download the
.mcpbfor your platform from the latest release. - Double-click the
.mcpbfile. Claude Desktop opens and walks you through the install. - Fill in
YOUTUBE_CLIENT_ID,YOUTUBE_CLIENT_SECRET, andYOUTUBE_REFRESH_TOKENwhen Claude Desktop prompts you.
Requires Claude Desktop 1.0.0 or later. Pre-built bundles ship for macOS Apple Silicon (darwin-arm64) and Windows (amd64, arm64). For other platforms, use the manual config below.
Manual JSON config (advanced)
If you can't use the MCPB bundle (older Claude Desktop, unsupported platform), install the MCP binary and configure it manually.
Install the MCP binary from this CLI's published public-library entry or pre-built release.
Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"youtube-analytics": {
"command": "youtube-analytics-pp-mcp",
"env": {
"YOUTUBE_CLIENT_ID": "<your-oauth-client-id>",
"YOUTUBE_CLIENT_SECRET": "<your-oauth-client-secret>",
"YOUTUBE_REFRESH_TOKEN": "<your-refresh-token>"
}
}
}
}YouTube Analytics is private, per-channel data, so there is no API-key path. The CLI authenticates with an OAuth 2.0 refresh token. You give it a client ID, a client secret, and a refresh token, and it trades the refresh token for a short-lived access token on every run. There is no browser step at runtime and no token file to keep track of.
Recommended: environment variables. Create an OAuth 2.0 client in a Google Cloud project, then export three variables:
export YOUTUBE_CLIENT_ID=<your-oauth-client-id>
export YOUTUBE_CLIENT_SECRET=<your-oauth-client-secret>
export YOUTUBE_REFRESH_TOKEN=<your-refresh-token>Scope the refresh token to https://www.googleapis.com/auth/yt-analytics.readonly. Add https://www.googleapis.com/auth/yt-analytics-monetary.readonly if you want revenue metrics.
Interactive alternative: auth login. If you would rather not mint a refresh token by hand, run the browser OAuth flow and let the CLI store the tokens in its config file:
youtube-analytics-pp-cli auth login --client-id <id> --client-secret <secret>The auth subcommands:
youtube-analytics-pp-cli auth setupprints the steps for registering a Google Cloud OAuth app (add--launchto open the page).youtube-analytics-pp-cli auth login --client-id <id> --client-secret <secret>runs the browser OAuth flow and saves the tokens.youtube-analytics-pp-cli auth statusshows the current credential state.youtube-analytics-pp-cli auth logoutclears the stored tokens.
YOUTUBE_ANALYTICS_OAUTH2C (a raw, pre-minted access token) is also accepted as a fallback, but it is not the path to use day to day. It expires fast and the CLI cannot refresh it.
# Confirm credentials are loaded and the API is reachable before anything else.
youtube-analytics-pp-cli doctor
# Register a channel under a friendly name so later commands take --channel MyChannel.
youtube-analytics-pp-cli channels add --name MyChannel --channel-id UCxxxxxxxxxxxxxxxxxxxxxx
# Build the local archive. Every trend and comparison reads from it.
youtube-analytics-pp-cli sync --channel MyChannel
# The headline answer: last week's numbers, with the change vs the prior week.
youtube-analytics-pp-cli report --channel MyChannel --last 7d
# All registered channels side by side, sorted by revenue.
youtube-analytics-pp-cli rollup --last 28d --sort revenue
No other tool for this API does these.
-
syncpulls your daily YouTube Analytics rows into a local SQLite archive, so trends and comparisons work offline.Run this first. Every report, comparison, and anomaly command reads the archive it builds.
youtube-analytics-pp-cli sync --channel MyChannel
-
reportshows views, watch time, subscribers, and revenue for a period, with the prior equal period and the change next to each metric.The fastest way to see how a channel did and whether it is up or down. The deltas are already computed.
youtube-analytics-pp-cli report --channel MyChannel --last 7d
-
whatchangedcompares two periods across every synced dimension and ranks the biggest movers: traffic sources, videos, revenue.Tells you whether a dip is real and what moved, without diffing two dashboards by eye.
youtube-analytics-pp-cli whatchanged --channel MyChannel --period last-week
-
anomalyflags any metric in the latest finalized period that falls outside its trailing mean and standard deviation.Catches an RPM or view collapse early, before it eats a month of income.
youtube-analytics-pp-cli anomaly --channel MyChannel
-
rpmreports monthly RPM, CPM, and monetized playbacks as a stable series, after the trailing re-sync settles late revenue adjustments.Answers "what was my RPM in February" with a number that has stopped moving.
youtube-analytics-pp-cli rpm --channel MyChannel --by month
-
moversranks videos by week-over-week change in views, showing both the ones gaining and the ones fading.Tells you which videos have momentum, not just which ones are biggest.
youtube-analytics-pp-cli movers --channel MyChannel --period last-week
-
rollupshows every registered channel side by side for one period, one row per channel, sorted by views or revenue.Replaces logging into YouTube Studio once per channel. The whole portfolio in one table.
youtube-analytics-pp-cli rollup --last 28d --sort revenue
-
channelsmaps friendly names like MyChannel to channel IDs, so every command can take--channelby name.Register a channel once, then use its name instead of a UC... ID everywhere.
youtube-analytics-pp-cli channels list
-
sqlruns read-only SQL straight against the local analytics archive, for any aggregation the presets do not cover.Reach for this when a question does not match a preset. Arbitrary slicing, no extra API call.
youtube-analytics-pp-cli sql "SELECT day, views FROM report_rows ORDER BY day DESC LIMIT 7"
Run youtube-analytics-pp-cli --help for the full command reference and flag list.
Manage group items
youtube-analytics-pp-cli group-items delete- Removes an item from a group.youtube-analytics-pp-cli group-items insert- Creates a group item.youtube-analytics-pp-cli group-items list- Returns a collection of group items that match the API request parameters.
Manage groups
youtube-analytics-pp-cli groups delete- Deletes a group.youtube-analytics-pp-cli groups insert- Creates a group.youtube-analytics-pp-cli groups list- Returns a collection of groups that match the API request parameters. For example, you can retrieve all groups that the authenticated user owns, or you can retrieve one or more groups by their unique IDs.youtube-analytics-pp-cli groups update- Modifies a group. For example, you could change a group's title.
Manage reports
youtube-analytics-pp-cli reports- Retrieve your YouTube Analytics reports.
# Human-readable table (default in terminal, JSON when piped)
youtube-analytics-pp-cli group-items list
# JSON for scripting and agents
youtube-analytics-pp-cli group-items list --json
# Filter to specific fields
youtube-analytics-pp-cli group-items list --json --select id,name,status
# Dry run: show the request without sending it
youtube-analytics-pp-cli group-items list --dry-run
# Agent mode: JSON, compact, and no prompts in one flag
youtube-analytics-pp-cli group-items list --agentThis CLI is built for AI agents to call:
- Non-interactive: it never prompts; every input is a flag.
- Pipeable:
--jsonoutput to stdout, errors to stderr. - Filterable:
--select id,namereturns only the fields you ask for. - Previewable:
--dry-runshows the request without sending it. - Explicit retries: add
--idempotentto create retries and--ignore-missingto delete retries when a no-op should count as success. - Confirmable:
--yesconfirms a destructive action explicitly. - Offline-friendly: sync and search commands use the local SQLite store when it is available.
- Agent-safe by default: no colors or formatting unless you pass
--human-friendly.
Exit codes: 0 success, 2 usage error, 3 not found, 4 auth error, 5 API error, 7 rate limited, 10 config error.
youtube-analytics-pp-cli doctorVerifies configuration, credentials, and connectivity to the API.
Config file: ~/.config/youtube-analytics-pp-cli/config.toml
Static request headers can be configured under headers; per-command header overrides take precedence.
Environment variables:
| Name | Required | Description |
|---|---|---|
YOUTUBE_CLIENT_ID |
Yes (recommended path) | OAuth 2.0 client ID from your Google Cloud project. |
YOUTUBE_CLIENT_SECRET |
Yes (recommended path) | OAuth 2.0 client secret paired with the client ID. |
YOUTUBE_REFRESH_TOKEN |
Yes (recommended path) | Refresh token scoped yt-analytics.readonly (add yt-analytics-monetary.readonly for revenue). The CLI exchanges it for an access token automatically. |
YOUTUBE_ACCESS_TOKEN |
No | Pre-minted short-lived access token; used as-is when present. |
YOUTUBE_ANALYTICS_OAUTH2C |
No (advanced fallback) | A raw pre-minted access token. Not the recommended path: it expires fast and cannot be refreshed. |
Instead of environment variables you can run youtube-analytics-pp-cli auth login --client-id <id> --client-secret <secret> once; the CLI stores the resulting tokens in config.toml.
Authentication errors (exit code 4)
- Run
youtube-analytics-pp-cli doctorto check credentials. - Verify the OAuth variables are set:
echo $YOUTUBE_CLIENT_ID $YOUTUBE_CLIENT_SECRET, or runyoutube-analytics-pp-cli auth status. - If you have not set up credentials yet, run
youtube-analytics-pp-cli auth login --client-id <id> --client-secret <secret>.
Not found errors (exit code 3)
- Check that the resource ID is correct.
- Run the
listcommand to see available items.
- Revenue metrics return 403 insufficient scope. Re-issue the refresh token with the
yt-analytics-monetary.readonlyscope, not justyt-analytics.readonly. - The last 2-3 days show zero or are missing. This is expected. YouTube finalizes data on a 2-3 day lag, so date presets like
--last 7dalready end the window 3 days back. Pass--include-partialto override that. - HTTP 400 with an unknown metric or dimension error. That metric and dimension combination is not a valid report. Use a named preset, or check that the metric is allowed with that dimension.
- 401 Unauthorized on every call. The refresh token is expired or revoked. Generate a new one in the Google Cloud console and update
YOUTUBE_REFRESH_TOKEN.
Two bugs in the initial OAuth implementation caused authentication to fail silently.
First, the token exchange endpoint was set to accounts.google.com/o/oauth2/token, which Google shut down in favor of oauth2.googleapis.com/token. Any attempt to trade an authorization code for tokens returned an error from the dead endpoint.
Second, the authorization URL was missing the access_type=offline and prompt=consent query parameters. Without access_type=offline, Google does not issue a refresh token, so the CLI could only make API calls until the short-lived access token expired (about one hour) with no way to renew it. Without prompt=consent, users who had already granted access would not see the consent screen on subsequent logins and would not receive a fresh refresh token.
Both issues are fixed in internal/cli/auth.go (authorization URL params and initial token exchange endpoint) and internal/client/client.go (token-refresh endpoint used when an access token expires). The config-file token_url field, loaded in internal/config/config.go, now also defaults to the correct endpoint and can be overridden for non-standard deployments.
This CLI was built by studying these projects and resources:
- googleapis/google-api-go-client (Go, 4200 stars)
- dogfrogfog/youtube-analytics-mcp (TypeScript, 3 stars)
Generated by CLI Printing Press.