library(httr)
library(jsonlite)
library(tidyverse)
library(magrittr)Assignment 6: Learning a new API
Assignment 6: YouTube API Tutorial
YouTube API Services
With the YouTube API you can search for videos, channels, and playlists by keyword, date, location, and other filters. It can also be used to retrieve comments, playlist information and desricptions. Researchers and data scientists can use this API to pull these thousands of comments, view counts, likes, and upload dates to study things like public opinion around an event or product, trends in what content gets engagement, and overall cultural trends. Companies and creators can track also track indiviually how their videos and channels perform, monitor comments about their brand, compare against competitors, and spot which topics or formats get the most clicks.
How to Receive A YouTube API Key
Sign in at console.cloud.google.com with a Google account.
Create a project by clicking the project dropdown at the top and choose “New Project”
Go to APIs & Services, then Library, and search for “YouTube Data API v3”, open that and click “Enable”
Go to APIs & Services, then Credentials, click Create Credentials, and choose the “YouTube Data API v3” API, click create, and finally copy that key.
How to Set Up the API Key in R
Make sure to install and load all the required packages
Create the API Key object
api_key <-"Your_API_KEY"Using the API to Pull Comments from Videos
Once the API key is saved, the first thing to do is to create a function that creates YT_api_Get_url request. You can do this by building the URL by saving these essential parts of search as objects. The endpoint commentThreads which is the kind of data you need. Here it’s the top comments on a video. The API key, which tells YouTube who is making the request. “part=snippet”, YouTube requires this parameter. Set maxresults=100 to get 100 comments per request. Finally, you have to set the videoid
YT_api_GET_url_3 <-
function(api_key, video_id){
YT_endpoint <- "https://www.googleapis.com/youtube/v3/commentThreads"
api_key <- paste("?key=", api_key, sep = "")
part <- "&part=snippet&maxResults=100"
video_id <- paste("&videoId=", video_id, sep = "")
YT_api_GET <-
paste(YT_endpoint, api_key, part, video_id, sep = "")
return(YT_api_GET)
}The second function sends the request and turns the response into a data frame. GET() sends the request, content() reads the response as text, and fromJSON() converts that text into R objects. I used flatten = TRUE because YouTube’s response has layers inside layers, and flattening turns each layer into its own column, joined with dots. The comments are stored in the items part of the response, so use_series(items) extracts them.
YT_api_GET_df_3 <-
function(api_key, video_id){
YT_api_url <- YT_api_GET_url_3(api_key, video_id)
YT_df <-
YT_api_url %>%
GET() %>%
content(as = "text",
encoding = "UTF-8") %>%
fromJSON(flatten = TRUE) %>%
use_series(items)
return(YT_df)
}I ran this call in a separate R script and saved the results to a CSV file. I don’t run it when I knit this document, because API results can change over time and requests use up my daily quota. The code is shown here so readers can see how it works.
comments <- YT_api_GET_df_3(api_key, "dQw4w9WgXcQ")write_csv(comments, "comments.csv")The table shows the first few comments from the video, along with their likes, number of replies, and the date posted. Each row is one comment, and this is just one page of up to 100 comments. I used the select command to get rid of any columns I did not want to display.
comments_clean <- read_csv("comments.csv") %>%
select(comment_id = snippet.topLevelComment.id,
author = snippet.topLevelComment.snippet.authorDisplayName,
text = snippet.topLevelComment.snippet.textOriginal,
likes = snippet.topLevelComment.snippet.likeCount,
replies = snippet.totalReplyCount,
posted = snippet.topLevelComment.snippet.publishedAt)Rows: 100 Columns: 24
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (17): kind, etag, id, snippet.channelId, snippet.videoId, snippet.topLe...
dbl (2): snippet.totalReplyCount, snippet.topLevelComment.snippet.likeCount
lgl (3): snippet.canReply, snippet.isPublic, snippet.topLevelComment.snipp...
dttm (2): snippet.topLevelComment.snippet.publishedAt, snippet.topLevelComm...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
comments_clean# A tibble: 100 × 6
comment_id author text likes replies posted
<chr> <chr> <chr> <dbl> <dbl> <dttm>
1 Ugym7QvIAl3AU7xoyMt4AaABAg @shahinnf… "Yoo… 0 0 2026-11-03 03:42:47
2 Ugzi3LQU-H4OQXDy5L14AaABAg @JoyRecz "OMG… 0 0 2026-11-03 03:36:49
3 Ugzize9QDisN3fqtFeh4AaABAg @iyenkiye… "No … 0 0 2026-11-03 03:28:47
4 UgxaOTxgVBtnkSbHNJ54AaABAg @francisc… "I w… 0 0 2026-11-03 03:20:29
5 Ugyrt1Dtr-FB7K9d76F4AaABAg @edgardoh… "Yo,… 0 0 2026-11-03 03:14:32
6 Ugw0E61myA3Hgyv859d4AaABAg @Minecraf… "Peo… 1 0 2026-11-03 02:40:18
7 UgzZU6SoBqySCWeBZwR4AaABAg @DaniMerc… "I c… 0 0 2026-11-03 01:41:13
8 UgzIMRmMu2R0dbxrng94AaABAg @zacbrown… "Got… 0 0 2026-11-03 01:40:49
9 Ugzwo7raikPRXKvtc-p4AaABAg @Core2Kei… "dis… 0 0 2026-11-03 01:07:24
10 UgyeuJ-43GeHGwOq-xd4AaABAg @minutemi… "got… 1 0 2026-11-03 01:06:26
# ℹ 90 more rows
head(comments_clean)# A tibble: 6 × 6
comment_id author text likes replies posted
<chr> <chr> <chr> <dbl> <dbl> <dttm>
1 Ugym7QvIAl3AU7xoyMt4AaABAg @shahinnfff "Yoo… 0 0 2026-11-03 03:42:47
2 Ugzi3LQU-H4OQXDy5L14AaABAg @JoyRecz "OMG… 0 0 2026-11-03 03:36:49
3 Ugzize9QDisN3fqtFeh4AaABAg @iyenkiyen… "No … 0 0 2026-11-03 03:28:47
4 UgxaOTxgVBtnkSbHNJ54AaABAg @francisco… "I w… 0 0 2026-11-03 03:20:29
5 Ugyrt1Dtr-FB7K9d76F4AaABAg @edgardohe… "Yo,… 0 0 2026-11-03 03:14:32
6 Ugw0E61myA3Hgyv859d4AaABAg @Minecraft… "Peo… 1 0 2026-11-03 02:40:18