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...
For further actions, you may consider blocking this person and/or reporting abuse
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!
Hard to tell without looking at the whole spreadsheet. Are you able to share it with me?
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!
Ah, the issue is that the "IDs" named range is pointing to the old 'Video Stats' sheet.
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?
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.
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!
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.
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.
Two things come to mind:
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!
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
I am facing the same issue. Did you fix this? If yes, please help me on how to fix it.
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
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
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?
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);
}
}
The error is saying that getSheetByName("YT Stats 3.2") is coming up empty. Did you rename it without updating the SHEET_NAME variable?
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
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...
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?
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?
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!
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
Hello Rick, when hitting 50 videos, the script no longer works, is there any way around this?
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?
I noticed the issue is that i was hitting the 50 video limit. Once i reduced the list, it worked.
Awesome awesome awesome! Thank you! How do I capture A 24 hour snapshot and a 7 day snapshot of a video?
Rick, since yesterday I'm receiving this error:
Error: disabled_client
The OAuth client was disabled.
This looks real interesting - will give this a try and see how it goes!
Hi, my name is Fran. Is it possible to use this way to track channel subs instead video statistics? Thanks in advance.
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.
*