Aditya Sharma

YouTube Analytics API vs Data API: Which to Use for Sheets

On this page, 9 sections

The YouTube Data API and the YouTube Analytics API both return numbers about videos, and they are easy to mix up. The Data API returns resource data, such as the statistics block on a video. The Analytics API returns reports about a channel you own, such as views and estimated minutes watched, broken down by a dimension like day.

In a sheet, the choice decides who has to sign in. Public numbers need an API key from a Google Cloud project. Analytics reports need the channel owner to authorise a scope listed on the Analytics reference page, and the report is requested for that authorised channel.

The existing guide on this site, how to import YouTube video details in Google Sheets, covers the key-based Data API route. This post is the other half: when you need the Analytics API instead, what it asks for, and a script that writes a daily report into a sheet.

The one-line difference

Ask what the question is about. If it is about a video as an object (its title, its public counts), that is the Data API. If it is about how a channel performed over a date range, that is the Analytics API. The Data API reference for the videos resource lists a statistics object with viewCount, likeCount, dislikeCount, favoriteCount and commentCount.

Every one of those is typed as a string in the reference, so a sheet formula or script has to convert them before doing arithmetic. One catch: the Data API revision history says the dislikeCount property became private in December 2021, so do not build a sheet around it.

The Analytics reports.query reference takes an ids parameter. For your own channel you set it to channel==MINE or to channel== followed by your channel ID. The example on that page asks for the metrics views, estimatedMinutesWatched, averageViewDuration, averageViewPercentage and subscribersGained, with a date range.

QuestionAPISign-in neededFields named on the reference page
How many views does this video have right now?Data API, videos.listAPI key (public data)statistics.viewCount, likeCount, commentCount
How many minutes were watched on each day last month?Analytics API, reports.queryOAuth, yt-analytics.readonlyestimatedMinutesWatched with dimension day
What is average view duration for my channel?Analytics API, reports.queryOAuth, yt-analytics.readonlyaverageViewDuration
What did my channel earn?Analytics API, reports.queryOAuth, yt-analytics-monetary.readonlyMonetary metrics (scope description on the page)

What each one asks you to set up

The Data API getting-started page says you need a Google Account, a project in the Google Cloud console, and the API enabled, and it mentions requesting an API key for public requests and OAuth 2.0 for user authorisation. For a public stats import you only need the key, which is why the older post works without any consent screen.

The Analytics reference lists two scopes. yt-analytics.readonly is described as viewing YouTube Analytics reports for your content, with access to activity metrics such as view counts and rating counts. yt-analytics-monetary.readonly adds estimated revenue and ad performance.

If you do not need money figures, ask for the first scope only. A narrower scope is a smaller thing to explain on a consent screen and a smaller thing to lose if the sheet is shared by mistake.

Quotas: two different budgets

The Data API quota page states the defaults. A project that enables the Data API gets 100 search.list calls, 100 videos.insert calls, and 10,000 units per day combined for all other endpoints. Quota resets at midnight Pacific Time. Every request, even an invalid one, costs at least one point, and fetching extra pages of results costs the quota again for each page.

Those numbers decide how you design a sheet. A search.list call is capped at 100 a day on its own, so a sheet that searches on every edit will hit it quickly. A sheet that reads a fixed list of video IDs spends from the 10,000-unit pool instead, and the per-method unit cost is on the quota page.

The quota page lists videos.list at 1 unit per call. I did not find a quota figure for the Analytics API in the pages I read, so check that before sizing a refresh schedule.

A script that writes an Analytics report into a sheet

Apps Script can call the Analytics endpoint with UrlFetchApp and pass its own OAuth token. ScriptApp.getOAuthToken is documented on the ScriptApp reference page.

The scopes the script asks for are set in the manifest, which the Apps Script scopes guide describes through the oauthScopes field. Add the Analytics scope there, along with the scopes for external requests and for the spreadsheet, in the appsscript.json file:

{
  "oauthScopes": [
    "https://www.googleapis.com/auth/yt-analytics.readonly",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/spreadsheets"
  ]
}

Then the function. It builds the query string from a params object, calls reports.query for the authorised channel, throws with the response body if the status is not 200, and writes the column headers from the response followed by the rows.

function fetchAnalytics() {
  const base = "https://youtubeanalytics.googleapis.com/v2/reports";
  const params = {
    ids: "channel==MINE",
    startDate: "2026-09-01",
    endDate: "2026-09-30",
    metrics: "views,estimatedMinutesWatched,averageViewDuration",
    dimensions: "day",
    sort: "day"
  };
  const query = Object.keys(params)
    .map(k => k + "=" + encodeURIComponent(params[k]))
    .join("&");
  const res = UrlFetchApp.fetch(base + "?" + query, {
    headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() },
    muteHttpExceptions: true
  });
  if (res.getResponseCode() !== 200) {
    throw new Error("HTTP " + res.getResponseCode() + " " + res.getContentText());
  }
  const data = JSON.parse(res.getContentText());
  const header = data.columnHeaders.map(c => c.name);
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.clearContents();
  sheet.getRange(1, 1, 1, header.length).setValues([header]);
  if (data.rows && data.rows.length) {
    sheet.getRange(2, 1, data.rows.length, header.length).setValues(data.rows);
  }
}

What I ran, and what I did not

I ran node –check on the script, then executed it in Node with mocked ScriptApp, UrlFetchApp and SpreadsheetApp, using a two-row fixture shaped like the documented response (columnHeaders and rows).

The request URL came out as the reports endpoint with ids=channel%3D%3DMINE, the date range, the three metrics and dimensions=day. The Authorization header carried the mocked token. The mock received a 4-column header write and a 2-row data write. The manifest parsed as valid JSON.

I did not run it against the live API, because that needs a consent screen on a real channel. Treat the first run in your account as the real test. If it returns an error, the script throws the HTTP status and body into the execution log, which is where the cause will be.

When to use which in a sheet

  • Public counts for a known list of videos, refreshed daily: the Data API with a key, as in the earlier post.
  • Anything over a date range, by day, or about audience behaviour on your own channel: the Analytics API with OAuth.
  • Revenue: the Analytics API with the monetary scope, and only for a channel you own.
  • Finding videos by keyword: search.list, which has its own cap of 100 calls a day by default.

If the sheet will be shared, remember the script runs as whoever authorised it. Putting an owner-authorised Analytics script in a sheet that others can edit hands them a way to pull that owner’s report data. Keep the script in a copy only you can open, or paste the output as values into the shared sheet.

Why Apps Script limits matter here too

The Apps Script quotas page lists the ceilings that apply around the API call: URL Fetch calls per day, 20,000 on a consumer account and 100,000 on Workspace, and a 6 minute limit on a script run. A daily Analytics report is one request, so these are nowhere near. They start to matter if you loop over many channels or many video IDs in one run.

Reading the response in a sheet

Both APIs return JSON, and the shapes differ. The Analytics response carries columnHeaders and rows, which is why the script above can write the header row straight from the response without hard-coding column names. The Data API returns items, each with a statistics object.

If you want to pull either kind of JSON into a sheet without a script per API, the importer in getting data from a website into Google Sheets shows a generic pattern for flattening JSON into rows.

Whichever API you use, keep the date range in cells, not in the code. Put startDate and endDate in two cells, read them at the top of the function, and a refresh becomes a matter of changing a date. Keep one tab per report, so a change in one metric list never overwrites another report’s columns.

One more caution on the Data API side: because its counts are strings, a sum over a column of them returns zero in Sheets until you convert the values. Wrap the cell in VALUE() or convert in the script before writing. This is a consequence of the string types in the reference, and I did not test it against a live response.

Do this today

  1. Write down the question your sheet answers and pick the API from the table above.
  2. If you picked Analytics, add only yt-analytics.readonly to the manifest.
  3. Paste the script, set startDate and endDate, and run it once from the editor.
  4. Read the execution log if it throws; the response body is printed in the error.
  5. Check the quota page for the cost of the method you call before you schedule it.

Resources

Tell me where I am wrong

Your email is not published and I do not add it to any list. Corrections with a source are the ones I act on fastest.