|

How to use YouTube Reporting API

The most important thing to understand about the YouTube Reporting API is that it’s asynchronous.

Unlike the Analytics API (where you ask a question and get an answer), the Reporting API works in a multi-step process:

  1. You: Ask YouTube to create a “report job” (e.g., “Please start generating a daily report of my video stats”).
  2. YouTube: Says “Okay” and, over the next 24-48 hours, starts generating these reports as CSV files.
  3. You: Periodically check back and ask, “Are any new reports from my job ready?”
  4. YouTube: “Yes, here is the download URL for yesterday’s report.”
  5. You: Download the CSV file and import it into your database or spreadsheet.

The code is split into two main parts: (1) Creating the job and (2) Downloading the reports.


🐍 Python Code Examples

You’ll need the Google API client library and the authentication library.

Bash

pip install google-api-python-client google-auth-oauthlib requests

You must first have an OAuth 2.0 client_secrets.json file from your Google Cloud project with the YouTube Reporting API enabled.

Part 1: Creating a Reporting Job

This is a one-time setup. You run this script once to tell YouTube what report you want it to start generating.

Python

import os
import google_auth_oauthlib.flow
import googleapiclient.discovery
import googleapiclient.errors

SCOPES = ["https.www.googleapis.com/auth/yt-analytics.readonly"]
API_SERVICE_NAME = "youtubereporting"
API_VERSION = "v1"
CLIENT_SECRETS_FILE = "client_secrets.json" # Your downloaded credentials

def get_authenticated_service():
    """Authenticates the user and returns the YouTube Reporting API service."""
    flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
        CLIENT_SECRETS_FILE, SCOPES)
    credentials = flow.run_local_server(port=0)
    return googleapiclient.discovery.build(
        API_SERVICE_NAME, API_VERSION, credentials=credentials)

def list_report_types(youtube_reporting):
    """Lists available report types."""
    print("Listing available report types...")
    results = youtube_reporting.reportTypes().list().execute()
    report_types = results.get("reportTypes", [])
    
    if not report_types:
        print("No report types found.")
    else:
        for report_type in report_types:
            print(f"  ID: {report_type['id']}, Name: {report_type['name']}")
    return report_types

def create_reporting_job(youtube_reporting, report_type_id, job_name):
    """Creates a new reporting job."""
    print(f"Creating job for report type '{report_type_id}'...")
    reporting_job = {
        "reportTypeId": report_type_id,
        "name": job_name
    }
    
    try:
        job = youtube_reporting.jobs().create(body=reporting_job).execute()
        print("Job created successfully:")
        print(f"  Job ID: {job['id']}")
        print(f"  Report Type ID: {job['reportTypeId']}")
        print(f"  Name: {job['name']}")
        print(f"  Create Time: {job['createTime']}")
    except googleapiclient.errors.HttpError as e:
        print(f"An HTTP error {e.resp.status} occurred: {e.content}")

if __name__ == "__main__":
    # Remove OAUTHLIB_INSECURE_TRANSPORT warning for local testing
    os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
    
    service = get_authenticated_service()
    
    # First, see what reports are available
    list_report_types(service)
    
    # --- Example: Create a "Basic Channel Video Stats" job ---
    # You would get this ID from the list_report_types() output.
    # 'channel_basic_a2' is a common one for daily video stats.
    REPORT_ID_TO_CREATE = "channel_basic_a2"
    JOB_NAME = "Daily Video Stats Job"
    
    create_reporting_job(service, REPORT_ID_TO_CREATE, JOB_NAME)

Part 2: Downloading an Available Report

You would run this script daily (or hourly) to check for and download new report files.

Python

import os
import requests
import google_auth_oauthlib.flow
import googleapiclient.discovery
from io import FileIO

# (Use the same get_authenticated_service() function from Part 1)
# ... (get_authenticated_service code here) ...

def list_jobs(youtube_reporting):
    """Lists all created reporting jobs."""
    print("Listing all reporting jobs...")
    results = youtube_reporting.jobs().list().execute()
    jobs = results.get("jobs", [])
    
    if not jobs:
        print("No jobs found.")
    else:
        for job in jobs:
            print(f"  Job ID: {job['id']}, Name: {job['name']}, Report Type: {job['reportTypeId']}")
    return jobs

def get_latest_report_url(youtube_reporting, job_id):
    """Gets the download URL for the most recent report from a job."""
    print(f"Finding reports for job ID: {job_id}...")
    results = youtube_reporting.jobs().reports().list(jobId=job_id).execute()
    reports = results.get("reports", [])
    
    if not reports:
        print("No reports found for this job yet. (It can take 24-48 hours to generate the first one)")
        return None
        
    # Reports are listed newest-first, so index 0 is the latest
    latest_report = reports[0]
    print(f"Found report: {latest_report['id']}")
    print(f"  Covers period: {latest_report['startTime']} to {latest_report['endTime']}")
    print(f"  Download URL: {latest_report['downloadUrl']}")
    return latest_report['downloadUrl']

def download_report_file(report_url, local_file_name):
    """Downloads the report file from the given URL."""
    print(f"Downloading report to '{local_file_name}'...")
    
    # Note: The download URL requires the same OAuth credentials
    # For simplicity, this example uses 'requests', but a real app
    # would add the auth headers from the 'credentials' object.
    # A simple GET request often works for testing.
    response = requests.get(report_url)
    
    if response.status_code == 200:
        with open(local_file_name, "wb") as f:
            f.write(response.content)
        print("Download complete.")
    else:
        print(f"Download failed with status code: {response.status_code}")
        print(response.text)

if __name__ == "__main__":
    os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
    service = get_authenticated_service()
    
    # First, list your jobs to find the ID you want
    jobs = list_jobs(service)
    
    if jobs:
        # Use the ID of the job you created in Part 1
        JOB_ID_TO_DOWNLOAD = jobs[0]['id'] # Just using the first job for this example
        
        report_url = get_latest_report_url(service, JOB_ID_TO_DOWNLOAD)
        
        if report_url:
            download_report_file(report_url, "my_youtube_report.csv")


📊 Typical Output (The CSV File)

The API calls themselves just return JSON about the jobs and reports (like the text you see in the console output). The real output is the .csv file you download.

Here is a sample of what the channel_basic_a2 report (a common one) looks like:

코드 스니펫

date,channel_id,video_id,views,red_views,comments,likes,dislikes,shares,estimated_minutes_watched,average_view_duration,average_view_percentage,subscribers_gained,subscribers_lost,videos_added_to_playlists,videos_removed_from_playlists,annotation_click_through_rate,annotation_close_rate
2025-10-24,UCxxxxxxxxxxxxxxxxxA,VIDEO_ID_ONE,1025,150,5,25,1,3,2840,166,45.2,12,1,3,0,0,0
2025-10-24,UCxxxxxxxxxxxxxxxxxA,VIDEO_ID_TWO,5034,780,42,150,8,15,19870,236,52.1,45,3,10,2,0,0
2025-10-24,UCxxxxxxxxxxxxxxxxxA,VIDEO_ID_THREE,890,40,1,12,0,1,1500,101,30.9,3,0,0,1,0,0

Key takeaways from the output:

  • It’s a standard CSV file.
  • Each row represents one video for one day.
  • It’s incredibly detailed, providing metrics like views, estimated_minutes_watched, subscribers_gained, and shares all broken down by video_id.
  • This format is designed to be loaded directly into a database (like Google BigQuery, PostgreSQL, etc.) for analysis.

https://developers.google.com/youtube/reporting/v1/reference/rest/v1/jobs/create#python

Our Score
Click to rate this post!
[Total: 0 Average: 0]
Visited 2 times, 1 visit(s) today

Leave a Comment

Your email address will not be published. Required fields are marked *