DEV Community

Using Sheets and the YouTube API to track video analytics

Rick Viscomi on October 24, 2018

I host a biweekly video series on YouTube called The State of the Web and being the data nerd that I am, I wanted a way to monitor the public stats...
Collapse
 
sorinamzu profile image
Sorin Amzu

Rick, this works great.
Problem is: I'm toying around with the idea of having multiple sheets. I created a new one, renamed it something else, replaced that name in your YouTube Analytics scripts, but it doesn't work on this new sheet.
It seems to copy existing values from the original Sheet1.

Any way around this?

Thanks a million!

Collapse
 
rick_viscomi profile image
Rick Viscomi

Hard to tell without looking at the whole spreadsheet. Are you able to share it with me?

Collapse
 
sorinamzu profile image
Sorin Amzu

Here is the sheet: docs.google.com/spreadsheets/d/1kj...

Here is the modified script, trying to get data for the first sheet (Stats For Video): script.google.com/d/1fkQ6lOM3fNnH7...

Cheers!

Thread Thread
 
rick_viscomi profile image
Rick Viscomi

Ah, the issue is that the "IDs" named range is pointing to the old 'Video Stats' sheet.

Thread Thread
 
sorinamzu profile image
Sorin Amzu

Now I don't know what to think any more :(
I've renamed the sheet back to the original name. I've copy-pasted your script again.
docs.google.com/spreadsheets/d/1kj...
I get this error: TypeError: Cannot call method "getValues" of null. at getVideoIds(Code:35) at updateStats(Code:26)

What am I doing wrong?

Thread Thread
 
rick_viscomi profile image
Rick Viscomi • Edited

Go to "Data > Named ranges..." to define a range of cells. There should be one named "IDs" spanning B2:B1000. This corresponds to the VIDEO_ID_RANGE_NAME variable in the script.

Thread Thread
 
sorinamzu profile image
Sorin Amzu

Yup. Works like a charm now.
Can this be modified to track several sheets? Or would I need to create a script for each sheet?

Thanks again!

Thread Thread
 
rick_viscomi profile image
Rick Viscomi

The script needs to know which video IDs to look up, so if you want to spread the IDs over multiple sheets, you can create multiple named ranges and iterate through each one. No need for multiple scripts.

Collapse
 
ruesseltier profile image
René Kurfürst

Thanks for the very detailed and nice structured post. I have done it that way and it worked fine, until I came to the 51st row of my table. Is there a limitation by 50? I tried to find a break point in the code but didn't found one.

Collapse
 
rick_viscomi profile image
Rick Viscomi

Two things come to mind:

  1. The named range may be ending on B50 rather than B1000.
  2. The YouTube API may have limitations on the number of video IDs in a single request. I can't find the definitive answer, but the docs have more info on quota: developers.google.com/youtube/v3/g...
Collapse
 
joeallam profile image
Joe Allam

Hey Rick, thanks for a fantastic article — I've got mine all set up looking beautiful! I've also run into the 50 API calls limit and upon research found that it definitely is the ID call with a specific limit, which can't be changed.

To get around this, I've decided to create different sheets for each year's video uploads. However, it seems overkill to duplicate the script for each sheet. I noticed in another reply you mentioned iterating through multiple named ranges. How would I go about referencing either multiple named ranges, or triggering the script multiple times (in the event all named ranges combined are over 50)?

Thanks!

Collapse
 
pranay profile image
pranay

Hi Rick,

thank you for this article. However, I'm experiencing a problem with the code and I'm utterly new to coding. When I'm trying to run the code, it is not happening and an error message pops up TypeError: Cannot call method "getValues" of null.

Please tell me where I could have gone wrong and also how to rectify it. Thanks a ton.

Pranay

Collapse
 
aakankshadp profile image
aakanksha-dp

I am facing the same issue. Did you fix this? If yes, please help me on how to fix it.

Collapse
 
f97c621c553743a profile image
Shiva Kumar

Hey I am trying to track my youtube usage across the computer and phone. Given this approach is awesome and works well, it is very cumbersome to manually input the video titles and the Vid IDs. I do have the YouTube history enabled, I want only a suggestion from you about the approach I can take to be able to log the Videos I have watched and also on which dates based on my history.

Thank you

Collapse
 
nosim12 profile image
norman simon

Hi Rick,
First of all thank you very much for this post.

I have an issue with the code, it looks like when a video ID is wrong in the list (for example if the video has been deleted from youtube), the script assigns to this wrong ID the data of the following ID.
I think that the function GetVideoIds builds the list skipping this kind of wrong ID. This results in a list of Ids smaller than my column of Ids.
Then, when we get data with others functions, the data is pasted in front of the wrong video.
I would like to add a condition "If the ID doesn't correpond to a valid video --> Do not just skip it but addd a message or a 0"
Unfortunately, I am not good enough in this language to do so.
Could you please assist me with this ?

Thank you very much !

Norman

Collapse
 
dickeytyler profile image
Tyler Dickey

Hey Rick! I'm having some issues setting up the triggers for this sheet. Once I set the trigger up as shown in your article I get caught in this endless loop of having to log into my google account and give the script permission to get data from YouTube. Any tips?

Collapse
 
ms86uk profile image
Marco Scarpa • Edited

Hi Rick, I'm getting this error:

TypeError: Cannot call method "setActiveCell" of null.

This is all the script. I've just changed the column names. Name range "IDs" start from row 7 to 200 and on N7 I've my first YT ID...

// This is "Sheet1" by default. Keep it in sync after any renames.
var SHEET_NAME = 'YT Stats 3.2';

// This is the named range containing all video IDs.
var VIDEO_ID_RANGE_NAME = 'IDs';

// Update these values after adding/removing columns.
var Column = {
VIEWS: 'V',
LIKES: 'Y',
DISLIKES: 'Z',
COMMENTS: 'X',
DURATION: 'O'
};

// Adds a "YouTube" context menu to manually update stats.
function onOpen() {
var spreadsheet = SpreadsheetApp.getActive();
var entries = [{name: "Update Stats", functionName: "updateStats"}];

spreadsheet.addMenu("YouTube", entries);
};

function updateStats() {
var spreadsheet = SpreadsheetApp.getActive();
var videoIds = getVideoIds();
var stats = getStats(videoIds.join(','));
writeStats(stats);
}

// Gets all video IDs from the range and ignores empty values.
function getVideoIds() {
var spreadsheet = SpreadsheetApp.getActive();
var range = spreadsheet.getRangeByName(VIDEO_ID_RANGE_NAME);
var values = range.getValues();
var videoIds = [];
for (var i = 0; i < values.length; i++) {
var value = values[i][0];
if (!value) {
return videoIds;
}
videoIds.push(value);
}
return videoIds;
}

// Queries the YouTube API to get stats for all videos.
function getStats(videoIds) {
return YouTube.Videos.list('contentDetails,statistics', {'id': videoIds}).items;
}

// Converts the API results to cells in the sheet.
function writeStats(stats) {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getSheetByName(SHEET_NAME);
var durationPattern = new RegExp(/PT((\d+)M)?(\d+)S/);
for (var i = 0; i < stats.length; i++) {
var cell = sheet.setActiveCell(Column.VIEWS + (2+i));
cell.setValue(stats[i].statistics.viewCount);
cell = sheet.setActiveCell(Column.LIKES + (2+i));
cell.setValue(stats[i].statistics.likeCount);
cell = sheet.setActiveCell(Column.DISLIKES + (2+i));
cell.setValue(stats[i].statistics.dislikeCount);
cell = sheet.setActiveCell(Column.COMMENTS + (2+i));
cell.setValue(stats[i].statistics.commentCount);
cell = sheet.setActiveCell(Column.DURATION + (2+i));
var duration = stats[i].contentDetails.duration;
var result = durationPattern.exec(duration);
var min = result && result[2] || '00';
var sec = result && result[3] || '00';
cell.setValue('00:' + min + ':' + sec);
}
}

Collapse
 
rick_viscomi profile image
Rick Viscomi

The error is saying that getSheetByName("YT Stats 3.2") is coming up empty. Did you rename it without updating the SHEET_NAME variable?

Collapse
 
chan_kuris profile image
KurisC

docs.google.com/spreadsheets/d/1ui...

If you check through the videos yourself, you will notice that at "Our Summer" and below, the views are aligned with the wrong video ID, but I am not sure what is causing this?

Thank You :D

Collapse
 
olekstomek profile image
olekstomek

Hi, thanks for showing us the use of Google Apps Script. ;)
I use your code and spreadsheet and adapted it in my solution which allows you to check the statistics of videos in the given YouTube playlist. This is the link to the repository: github.com/olekstomek/gscript-trac...

Collapse
 
dakotageek profile image
DakotaGeek

Hi Rick, I'm following your instructions and although everything appears correct, I'm getting the following error when running the script.
"API call to youtube.videos.list failed with error: No filter selected. Expected one of: chart, id, myRated, idParam (line 49, file "Code")"

Line 49 in the script is an exact copy-paste from your article as follows:
"return YouTube.Videos.list('contentDetails,statistics', {'id': videoIds}).items;"

Any thoughts on why this error would occur?

Collapse
 
dakotageek profile image
DakotaGeek

Some of the other posts here answered my question. This is an example of hitting the limit of 50 requests to the API.

Since the Named Range is 999 entries long, perhaps Rick could update his script to iterate through 999 entries in chunks of 50?

Collapse
 
retrojammed profile image
Jeremy Jamm

Hello! Everything in this guide worked perfectly. I do have a question, however. Is it possible to implement lines of code to automatically extract the last X amount of videos from the channel? Would be very helpful. Thanks!

Collapse
 
jonesadamd profile image
Adam J.

Hi Rick,
Great article and example of tracking YouTube video's with the API, but any chance you can update it to include pagetokens for more than 50 lines.

Or can we create code to split the getVideoIds() and writeStats(stats) for a maximum of 50 then continue down the range?

Thank you

Collapse
 
chan_kuris profile image
KurisC

Hello Rick, when hitting 50 videos, the script no longer works, is there any way around this?

Collapse
 
pixelgroove profile image
Udi Sabach

Hi. I had this working, and now getting an error "API call to youtube.videos.list failed with error: The request specifies an invalid filter parameter. (line 49, file "Code")".

Any how to fix this?

Collapse
 
pixelgroove profile image
Udi Sabach

I noticed the issue is that i was hitting the 50 video limit. Once i reduced the list, it worked.

Collapse
 
max_alexander_ profile image
Max🔥Alexander

Awesome awesome awesome! Thank you! How do I capture A 24 hour snapshot and a 7 day snapshot of a video?

Collapse
 
ms86uk profile image
Marco Scarpa

Rick, since yesterday I'm receiving this error:

  1. That’s an error.

Error: disabled_client

The OAuth client was disabled.

Collapse
 
wrldwzrd89 profile image
Eric Ahnell

This looks real interesting - will give this a try and see how it goes!

Collapse
 
_lobeira_today profile image
A Lobeira today

Hi, my name is Fran. Is it possible to use this way to track channel subs instead video statistics? Thanks in advance.

Collapse
 
bhagiradh1993 profile image
bhagiradh akuthota

I'm facing this particular issue. Can anyone please help me

*GoogleJsonResponseException: API call to youtube.videos.list failed with error: The request specifies an invalid filter parameter.
*