I’ve made this small web app that shows YouTube account data. The key component of the application is interacting with the YouTube API using the key I’ve generated on https://console.cloud.google.com/. The app worked perfectly for about a day; I tested it multiple times. Suddenly, I started receiving the 403 error just as I clicked the button that started interacting with the third-party source (YouTube API).
Steps to reproduce the issue:
- Type in the search bar some YouTube account username or ID
(@kurcovizija) - Click on the Get Channel Info button.
- I my case, I receive the 403 error after this. It should regularly load the page with info about the requested channel.
Here is the JavaScript code that I’m using:
const API_KEY = 'AIzaSyD8Xi7C_6dow9y11i20ZQWnlC12b17FlXc'; // Replace with your actual API key
const userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15',
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
'Mozilla/5.0 (Linux; Android 11; SM-G991U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36',
// Add more user agents as needed
];
function getRandomUserAgent() {
return userAgents[Math.floor(Math.random() * userAgents.length)];
}
async function fetchYouTubeData() {
let input = document.getElementById('channelId').value.trim();
if (!input) {
alert('Please enter a YouTube Channel ID or Username');
return;
}
let channelId = input;
if (input.startsWith('@')) {
// If the input starts with @, it's a username
const username = input.substring(1);
try {
const searchResponse = await fetch(`https://www.googleapis.com/youtube/v3/search?part=id&type=channel&q=${username}&key=${API_KEY}`, {
headers: {
'User-Agent': getRandomUserAgent(),
'Referer': 'https://www.youtube.com/',
'Origin': 'https://www.youtube.com'
}
});
if (!searchResponse.ok) {
throw new Error(`HTTP error! status: ${searchResponse.status}`);
}
const searchData = await searchResponse.json();
if (!searchData.items || searchData.items.length === 0) {
alert('No channel found for this username');
return;
}
channelId = searchData.items[0].id.channelId; // Extract the channel ID directly
} catch (error) {
console.error('Error fetching YouTube data:', error);
alert(`Failed to fetch YouTube data: ${error.message}`);
return;
}
}
try {
// Fetch channel information
const channelResponse = await fetch(`https://www.googleapis.com/youtube/v3/channels?part=snippet,contentDetails,statistics&id=${channelId}&key=${API_KEY}`, {
headers: {
'User-Agent': getRandomUserAgent(),
'Referer': 'https://www.youtube.com/',
'Origin': 'https://www.youtube.com'
}
});
if (!channelResponse.ok) {
throw new Error(`HTTP error! status: ${channelResponse.status}`);
}
const channelData = await channelResponse.json();
if (!channelData.items || channelData.items.length === 0) {
alert('No data found for this Channel ID');
return;
}
const channel = channelData.items[0];
// Fetch latest video from the channel
const videoResponse = await fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=${channelId}&type=video&order=date&maxResults=1&key=${API_KEY}`, {
headers: {
'User-Agent': getRandomUserAgent(),
'Referer': 'https://www.youtube.com/',
'Origin': 'https://www.youtube.com'
}
});
if (!videoResponse.ok) {
throw new Error(`HTTP error! status: ${videoResponse.status}`);
}
const videoData = await videoResponse.json();
if (!videoData.items || videoData.items.length === 0) {
alert('No videos found for this Channel');
return;
}
const latestVideo = videoData.items[0];
const videoInfo = {
title: latestVideo.snippet.title,
publishedAt: new Date(latestVideo.snippet.publishedAt).toLocaleDateString(),
thumbnail: latestVideo.snippet.thumbnails.medium.url
};
// Display channel and video information
const channelInfo = `
<div>
<img src="${channel.snippet.thumbnails.medium.url}" alt="Channel Thumbnail">
<div>
<h2>${channel.snippet.title}</h2>
<p><strong>Description:</strong> ${channel.snippet.description}</p>
<p><strong>Total Views:</strong> ${channel.statistics.viewCount}</p>
<p><strong>Number of Videos:</strong> ${channel.statistics.videoCount}</p>
<p><strong>Subscribers:</strong> ${channel.statistics.subscriberCount}</p>
<p><strong>Last Video Published At:</strong> ${videoInfo.publishedAt}</p>
<p><strong>Latest Video:</strong> ${videoInfo.title}</p>
<img src="${videoInfo.thumbnail}" alt="Latest Video Thumbnail">
</div>
</div>
`;
document.getElementById('channelData').innerHTML = channelInfo;
} catch (error) {
console.error('Error fetching YouTube data:', error);
alert(`Failed to fetch YouTube data: ${error.message}`);
}
}
body {
font-family: 'Times New Roman', Times, serif;
background-color: #f9f9f9;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
max-width: 600px;
padding: 20px;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
text-align: center;
}
.title {
font-size: 28px;
line-height: 1.2;
margin-bottom: 20px;
}
.subtitle-container {
position: relative;
}
.subtitle {
font-size: 16px;
color: transparent;
background-image: linear-gradient(to right, violet, indigo, blue, green, yellow, orange, red);
-webkit-background-clip: text;
margin-bottom: 20px;
display: inline-block;
padding: 10px 20px;
border-radius: 4px;
text-align: center;
background-color: #333; /* Dark grey background color */
width: fit-content; /* Ensures the background spans only as wide as the text */
margin: 0 auto; /* Centers the subtitle */
}
.line {
width: 80%;
height: 2px;
background-color: #333;
margin: 0 auto 20px auto; /* Centered and spaced below subtitle */
}
.search-container {
margin-bottom: 40px;
}
input[type="text"] {
padding: 10px;
width: 60%;
margin-right: 10px;
font-family: 'Times New Roman', Times, serif;
border: 1px solid #ccc;
border-radius: 4px;
}
button {
padding: 10px 20px;
font-size: 16px;
font-family: 'Times New Roman', Times, serif;
border: none;
background-color: #007bff;
color: white;
cursor: pointer;
border-radius: 4px;
}
button:hover {
background-color: #0056b3;
}
.channel-info {
margin-top: 40px;
text-align: left;
}
.channel-info img {
max-width: 100px;
border-radius: 50%;
margin-right: 20px;
float: left;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Peter's YouTube Data Checker</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h1 class="title">Peter's<br>YouTube<br>Data Checker</h1>
<div class="subtitle-container">
<p class="subtitle">Check every YouTube channel's most recent data fast and easy</p>
<div class="line"></div>
</div>
<div class="search-container">
<input type="text" id="channelId" placeholder="Enter YouTube Channel ID">
<button onclick="fetchYouTubeData()">Get Channel Info</button>
</div>
<div id="channelData" class="channel-info"></div>
</div>
<script src="script.js"></script>
</body>
</html>