YouTube Channel Management
Use the youtube CLI tool to manage your YouTube channel: upload videos, list uploads, edit metadata, schedule/unschedule publication, set thumbnails, download your own videos (including private ones), get transcripts, and generate AI chapter summaries.
Architecture
Three separate systems:
- YouTube Data API v3 + OAuth 2.0 — upload, list, update, schedule, thumbnails
- yt-dlp + browser cookies — download your own videos (including private)
- youtube_transcript_api + Gemini — transcripts (fetches existing captions) and AI chapter generation
The YouTube Data API does not have a download endpoint for uploaded video files. Download is handled separately via yt-dlp with authenticated cookies. Transcripts are fetched from YouTube's existing captions (no AI needed). Chapter generation uses Google Gemini.
Setup
1. OAuth Credentials (Required for API operations)
Create OAuth 2.0 credentials in the Google Cloud Console:
- Create a project (or use an existing one)
- Enable the YouTube Data API v3
- Create OAuth 2.0 Client ID (type: Desktop app)
- Download the client secret JSON
Provide credentials via one of:
# Option A: Place the downloaded JSON file at the default path
cp ~/Downloads/client_secret_*.json ~/.youtube_client_secret.json
# Option B: Set env vars
export YOUTUBE_CLIENT_ID="your_client_id"
export YOUTUBE_CLIENT_SECRET="your_client_secret"
# Option C: Point to your JSON file
export YOUTUBE_CLIENT_SECRETS_FILE="/path/to/client_secret.json"
Then authenticate:
youtube auth
This opens a browser for Google login and saves the token to ~/.youtube_oauth_token.json.
2. yt-dlp (Required for download only)
pip install yt-dlp
# or
brew install yt-dlp
Commands
| Command | Description |
|---|---|
youtube auth |
Authenticate via OAuth 2.0 (opens browser) |
youtube upload |
Upload a video with metadata |
youtube list |
List your uploaded videos |
youtube update |
Edit metadata of an existing video |
youtube schedule |
Schedule a private video for future publication |
youtube unschedule |
Revert a scheduled video to private draft |
youtube reschedule |
Change the scheduled publish time |
youtube set-thumbnail |
Set or replace a video thumbnail |
youtube download |
Download a video using yt-dlp (supports private videos) |
youtube transcribe |
Get transcript of a YouTube video (fetches existing captions) |
youtube chapters |
Generate AI chapter summaries using Gemini |
youtube comment |
Post a top-level comment on a video (API cannot pin — see Chrome playbook below) |
Not supported: youtube delete — deletion is explicitly excluded. Pinning comments is also not supported by the YouTube Data API; it must be done in Studio UI (see the Chrome automation playbook below).
Note:
transcribeandchaptersdo NOT require YouTube OAuth.transcribeworks with any public video.chaptersrequiresGEMINI_API_KEY.
Usage
Upload a Video
# Upload as private (default)
youtube upload --file video.mp4 --title "My Video" --description "Description here"
# Upload with tags and schedule
youtube upload --file video.mp4 --title "My Video" --tags "tag1, tag2" --publish-at 2026-04-10T16:00:00Z
# Upload as public
youtube upload --file video.mp4 --title "My Video" --privacy public -v
List Uploads
# List recent uploads as a table
youtube list
# List more videos
youtube list -n 50
# Output as JSON
youtube list --json
# Verbose mode (shows tags, category)
youtube list -v
Update Metadata
# Update title only
youtube update --id VIDEO_ID --title "New Title"
# Update multiple fields
youtube update --id VIDEO_ID --title "New Title" --description "New desc" --tags "a, b, c"
# Change privacy
youtube update --id VIDEO_ID --privacy unlisted
# Change category
youtube update --id VIDEO_ID --category 28
Safe updates: The tool always fetches the current video first, merges your changes, and sends a complete payload — preserving required fields like
titleandcategoryId.
Schedule / Unschedule / Reschedule
# Schedule a private video
youtube schedule --id VIDEO_ID --publish-at 2026-04-10T16:00:00Z
# Unschedule back to private draft
youtube unschedule --id VIDEO_ID
# Reschedule to a new time
youtube reschedule --id VIDEO_ID --publish-at 2026-04-11T16:00:00Z
Scheduling rules:
publishAtonly works on private videos that have never been published. You cannot reschedule a previously-public video.
Set Thumbnail
youtube set-thumbnail --id VIDEO_ID --file thumbnail.jpg
Download Videos
By default, youtube download automatically extracts cookies from Chrome for authentication.
This means you just need to be logged into YouTube in Chrome — no manual cookie export needed.
# Download a video (auto-extracts Chrome cookies by default)
youtube download --id VIDEO_ID
# Download by URL
youtube download --url "https://youtu.be/VIDEO_ID"
# Save to specific path
youtube download --id VIDEO_ID -o ~/Downloads/video.mp4
# Use Firefox instead of Chrome
youtube download --id VIDEO_ID --cookies-from-browser firefox
# Specify a custom Chrome profile path
youtube download --id VIDEO_ID --cookies-from-browser "chrome:/path/to/profile"
# Use a cookies.txt file instead
youtube download --id VIDEO_ID --cookies ~/cookies.txt
# Skip cookie extraction (public videos only)
youtube download --id VIDEO_ID --no-cookies
# Choose format
youtube download --id VIDEO_ID -f "bestvideo+bestaudio"
How it works: yt-dlp reads cookies directly from Chrome's cookie database on disk. You must be logged into YouTube in Chrome. No browser window is opened — it reads the stored cookies programmatically. For private videos, the Chrome session must be logged into the account that owns the video.
Transcribe Videos
Fetches existing YouTube captions/subtitles — no AI or OAuth needed. For private/unplayable videos, automatically downloads via yt-dlp (with Chrome cookies) and transcribes locally with Whisper.
# Get transcript by URL
youtube transcribe "https://youtu.be/VIDEO_ID"
# Get transcript by video ID
youtube transcribe VIDEO_ID
# Timestamps in seconds format
youtube transcribe "https://youtu.be/VIDEO_ID" --seconds
# Transcribe a local video file (uses Whisper — supports mp4, webm, mkv, etc.)
youtube transcribe video.mp4
# Private videos work too (auto-downloads with Chrome cookies, then transcribes locally)
youtube transcribe "https://youtu.be/PRIVATE_VIDEO_ID"
# Save to file
youtube transcribe "https://youtu.be/VIDEO_ID" > transcript.txt
Post a Comment
Posts a top-level comment on a video as the authenticated channel. Uses commentThreads.insert with the youtube.force-ssl scope (already included in the OAuth token).
youtube comment --id VIDEO_ID --text "Your comment text here"
Prints the Thread ID, Comment ID, and a Studio deep link for pinning.
Pinning is NOT available via the API — it's a Studio-UI-only action. Use the Chrome automation playbook below after posting.
Pin a Comment via Chrome Automation
The YouTube Data API exposes no pin endpoint, so pinning requires driving Studio's UI. This playbook is verified end-to-end — follow it to avoid fishing for selectors.
Prerequisites: claude-in-chrome MCP connected and logged into the target YouTube channel in Chrome.
Steps:
- Navigate to
https://studio.youtube.com/video/<VIDEO_ID>/commentsin a fresh tab (create one withtabs_create_mcp— never clobber an existing tab). - Clear the "Response status: Unresponded" filter chip. Studio hides the channel owner's own comments under this filter by default, so your just-posted comment will NOT appear until you clear it.
findquery:"Response status filter chip with X to clear"— click the returnedreffor the Remove (X) sub-element, not the chip itself.
- Screenshot to confirm your comment from
@<your-handle>is now visible (labeled e.g. "1 minute ago"). - Open the kebab (three-dot) menu on YOUR comment row.
findquery:"three-dot kebab action menu button on the <your-handle> comment row".
- Click "Pin" from the dropdown.
findquery:"Pin menu item in the action menu dropdown".- ⚠️ Known quirk: the
find-based click on the Pin menu item sometimes re-opens the dropdown instead of activating the item. If the confirmation dialog doesn't appear, fall back to a coordinate click on the visible "Pin" text — take a screenshot, read the coords, andcomputer.left_clickthere. This has been the consistent failure mode across multiple runs.
- Click "Pin" in the "Pin this comment?" confirmation dialog.
findquery:"Pin button in the \"Pin this comment?\" confirmation dialog".
- Verify via screenshot — the comment should move to the top and show "📌 Pinned by @<your-handle>".
Parallelization: multiple subagents can pin comments on different videos in parallel. Each agent must create its own fresh tab (tabs_create_mcp) and only operate on that tabId — agents sharing a tab will thrash. Each video has its own independent pinned slot, so there's no cross-video contention.
Generate Chapters
Uses Google Gemini to generate chapter summaries with timestamps.
# Generate chapters for a YouTube video
youtube chapters "https://youtu.be/VIDEO_ID"
# Generate chapters for a local MP4
youtube chapters video.mp4
Requires:
GEMINI_API_KEYenvironment variable. Get one at https://aistudio.google.com/apikey
Options Reference
Global Options
| Option | Short | Description |
|---|---|---|
--verbose |
-v |
Show progress and debug info |
Upload Options
| Option | Short | Description |
|---|---|---|
--file |
-f |
Path to video file (required) |
--title |
-t |
Video title (required) |
--description |
-d |
Video description |
--tags |
Comma-separated tags | |
--category |
YouTube category ID (default: 22) | |
--privacy |
-p |
public, private, unlisted (default: private) |
--publish-at |
ISO 8601 timestamp for scheduling |
Update Options
| Option | Short | Description |
|---|---|---|
--id |
Video ID (required) | |
--title |
-t |
New title |
--description |
-d |
New description |
--tags |
New comma-separated tags (replaces existing) | |
--category |
New category ID | |
--privacy |
-p |
New privacy status |
Comment Options
| Option | Short | Description |
|---|---|---|
--id |
Video ID (required) | |
--text |
-t |
Comment text (required) |
Download Options
| Option | Short | Description |
|---|---|---|
--id |
YouTube video ID | |
--url |
-u |
YouTube video URL |
--output |
-o |
Output file path |
--cookies |
Path to cookies.txt file | |
--cookies-from-browser |
Browser name or path (default: chrome). Examples: chrome, firefox, chrome:/path/to/profile |
|
--format |
-f |
yt-dlp format string |
--no-cookies |
Skip automatic cookie extraction |
Environment Variables
| Variable | Description |
|---|---|
YOUTUBE_CLIENT_ID |
OAuth 2.0 client ID |
YOUTUBE_CLIENT_SECRET |
OAuth 2.0 client secret |
YOUTUBE_CLIENT_SECRETS_FILE |
Path to client secret JSON (default: ~/.youtube_client_secret.json) |
YOUTUBE_TOKEN_FILE |
Path to stored OAuth token (default: ~/.youtube_oauth_token.json) |
GEMINI_API_KEY |
Google Gemini API key (required only for youtube chapters) |
Requirements
- The
hamelpackage must be installed:pip install hamel - For download:
yt-dlpmust be installed separately - For chapters:
GEMINI_API_KEYenvironment variable must be set - For local MP4 transcription:
openai-whisperandffmpegare needed
Troubleshooting
"No OAuth credentials found": Set YOUTUBE_CLIENT_ID and YOUTUBE_CLIENT_SECRET env vars (or place a client_secret JSON file at ~/.youtube_client_secret.json), then run youtube auth.
"Token refresh failed": Your OAuth token has expired. Run youtube auth again to re-authenticate.
"yt-dlp not found": Install with pip install yt-dlp or brew install yt-dlp.
"Video not found or not accessible": Check the video ID is correct and that your authenticated account has access.
"Could not find browser cookies database": Chrome is not at the default location. Specify the profile path: --cookies-from-browser 'chrome:/path/to/profile', or use Firefox: --cookies-from-browser firefox.
"Authentication required for this video": You need to be logged into YouTube in Chrome. Open Chrome, go to youtube.com, sign in, then retry the download.
Scheduling fails: Only private videos that have never been published can be scheduled. If the video was previously public, scheduling will not work.
Complete Setup Walkthrough
If you're starting from scratch on a new machine:
- Install the package:
pip install hamel - Install yt-dlp (for downloads):
pip install yt-dlp - Create OAuth credentials:
- Go to https://console.cloud.google.com/apis/credentials
- Create a project (or use an existing one)
- Enable the YouTube Data API v3 at https://console.cloud.google.com/apis/library/youtube.googleapis.com
- Go to OAuth consent screen → add your email as a test user
- Create an OAuth 2.0 Client ID (type: Desktop app)
- Copy the Client ID and Client Secret
- Set environment variables:
export YOUTUBE_CLIENT_ID='your-client-id.apps.googleusercontent.com' export YOUTUBE_CLIENT_SECRET='your-client-secret' - Authenticate:
youtube auth(opens browser for one-time Google login) - Verify:
youtube list(should show your uploads) - For downloads: Make sure you're logged into YouTube in Chrome, then
youtube download --id VIDEO_ID - For transcripts:
youtube transcribe "https://youtu.be/VIDEO_ID"(no extra setup needed) - For chapters: Set
GEMINI_API_KEYenv var, thenyoutube chapters "https://youtu.be/VIDEO_ID"