← All posts
Automation

Automating YouTube Analytics Reports — Daily Email Pipeline

Build a system that pulls channel metrics nightly via YouTube Data API and turns them into a human-readable daily email — no manual dashboard checking.

Fuad Aliyev April 30, 20268 min readAzərbaycanca oxu: Azərbaycanca

A client with a YouTube channel used to spend 15 minutes every morning in YouTube Studio — views, subs, retention, revenue. Often the numbers were forgotten by lunchtime. Now every night at 23:30 they get an email: 'Today's key metrics, what changed vs yesterday, three insights worth noting.' Small system, big time saver.

The layers

  • Auth — Google OAuth for YouTube Data + YouTube Analytics APIs
  • Data fetcher — cron job pulling daily metrics
  • Storage — historical data in Postgres
  • AI summary — GPT-4o-mini turns numbers into prose
  • Email sender — Resend handles delivery

YouTube API — gotchas to know

Two separate APIs: YouTube Data API (video metadata, comments) and YouTube Analytics API (views, retention, revenue). Same OAuth, different scopes. Different quotas too: Data API 10,000 units/day, Analytics 50,000/day. A typical nightly run uses 50-100 units, plenty of headroom.

python
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from datetime import date, timedelta

creds = Credentials.from_authorized_user_file("token.json", [
    "https://www.googleapis.com/auth/youtube.readonly",
    "https://www.googleapis.com/auth/yt-analytics.readonly",
])

analytics = build("youtubeAnalytics", "v2", credentials=creds)
today = date.today() - timedelta(days=1)  # son tam gün

response = analytics.reports().query(
    ids="channel==MINE",
    startDate=str(today),
    endDate=str(today),
    metrics="views,estimatedMinutesWatched,averageViewDuration,subscribersGained,subscribersLost,estimatedRevenue",
).execute()

metrics = dict(zip(
    [h["name"] for h in response["columnHeaders"]],
    response["rows"][0],
))

AI summary — this is where it gets useful

Raw numbers ('1,234 views, $8.40 revenue') aren't useful. I send the AI the last 7 days plus today, with the prompt: 'Owner of a YouTube channel. Review the data and pull out 3 insights worth noticing. Trend direction, anomalies, and one recommendation. Friendly but factual tone.'

python
summary_prompt = f"""
Son 7 günün YouTube metric tarixçəsi (JSON):
{last_7_days_json}

Bugünkü metric-lər:
{today_metrics_json}

Tapşırıq: 3 vacib insight yaz. Qısa, konkret, faktiki.
1. Trend (yaxşıya/pisə doğru hansı metric gedir)
2. Qeyri-adi şey (orta göstəricidən fərqli)
3. Bir tövsiyə (nəyə baxmaq lazımdır)
"""

response = openai.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": summary_prompt}],
    max_tokens=400,
)
insights = response.choices[0].message.content

Email format — the HTML template

Simple but effective layout: 5 key metrics at the top (views, watch time, net subs, revenue, retention), each showing yesterday-vs-today delta in green/red. Then the AI's 3 insights. Then the top-viewed video with a link. Plain HTML, no external CSS, renders fine in every email client.

Schedule and monitoring

Cron on Hetzner: 30 23 * * * /usr/bin/python3 /home/deploy/youtube-report/main.py. Sends a health-check ping at end of a successful run. If no ping arrives within 24 hours, Healthchecks.io alerts me. This simple setup has run for 8 months, failed once (OAuth token expired and the refresh logic threw on a quota error).

This pattern works for other platforms too

  • Instagram — Graph API, same structure
  • TikTok — TikTok Business API (pricey)
  • Twitter/X — basic tweet metrics
  • Google Analytics — email summary instead of Looker Studio
  • Stripe — daily sales digest
Note

AI insights are 90% accurate, 10% hallucinated — sometimes it says 'views are up 50%' when they're up 5%. I parse the AI response, extract numeric claims, and verify against the real data. If they don't match, the AI section gets dropped from the email.

Need help on a project?

If something in this post hits close to a project you're working on, let's hop on a 30-minute call — I'll come back with concrete advice.