Youtube Grid on Webflow
Youtube Grid on Webflow
This tool automatically pulls the latest videos from any YouTube channel and displays them in a professional grid format. Simply provide a YouTube channel ID and the module handles the rest: fetching video data, thumbnails, titles, descriptions, and publication dates. Features include smart caching to minimize API calls, bot detection to prevent unnecessary requests, Shorts filtering options, multi-language date formatting, and high-quality thumbnail optimization. Perfect for portfolio showcases, content marketing, video galleries and dynamic YouTube integrations without complex coding.

Implement it easier
1
YouTube API Configuration
Get YouTube API Key
Go to Google Cloud Console Create a new project Enable YouTube Data API v3 Create credentials → API Key Copy your API key
Create Cloudflare Account
Go to Cloudflare Create a free account Go to Workers & Pages Click Create application
2
Deploy Worker
Create a worker and put this code inside:
// YouTube API Worker pour bb-contents
// Déployez ce code sur Cloudflare Workers
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
// Gérer les CORS
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
}
})
}
try {
const url = new URL(request.url)
const channelId = url.searchParams.get('channelId')
const maxResults = url.searchParams.get('maxResults') || '10'
const allowShorts = url.searchParams.get('allowShorts') || 'false'
if (!channelId) {
return new Response(JSON.stringify({ error: 'channelId parameter is required' }), {
status: 400,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
})
}
// Remplacez YOUR_YOUTUBE_API_KEY par votre vraie clé API YouTube
const apiKey = 'YOUR_YOUTUBE_API_KEY'
// Déterminer la durée des vidéos selon allowShorts
if (allowShorts === 'true') {
// Récupérer uniquement les vidéos courtes (< 4 minutes)
const apiUrl = `https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=${channelId}&maxResults=${maxResults}&order=date&type=video&videoDuration=short&key=${apiKey}`
const response = await fetch(apiUrl)
if (!response.ok) {
throw new Error(`YouTube API error: ${response.status}`)
}
const data = await response.json()
return new Response(JSON.stringify(data), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'public, max-age=3600'
}
})
} else {
// Récupérer les vidéos moyennes ET longues (exclure les shorts)
const [mediumResponse, longResponse] = await Promise.all([
fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=${channelId}&maxResults=${maxResults}&order=date&type=video&videoDuration=medium&key=${apiKey}`),
fetch(`https://www.googleapis.com/youtube/v3/search?part=snippet&channelId=${channelId}&maxResults=${maxResults}&order=date&type=video&videoDuration=long&key=${apiKey}`)
])
if (!mediumResponse.ok || !longResponse.ok) {
throw new Error(`YouTube API error: ${mediumResponse.status || longResponse.status}`)
}
const [mediumData, longData] = await Promise.all([
mediumResponse.json(),
longResponse.json()
])
// Combiner les résultats et trier par date
const combinedItems = [...(mediumData.items || []), ...(longData.items || [])]
combinedItems.sort((a, b) => new Date(b.snippet.publishedAt) - new Date(a.snippet.publishedAt))
// Limiter au nombre de résultats demandé
const limitedItems = combinedItems.slice(0, parseInt(maxResults))
return new Response(JSON.stringify({
...mediumData,
items: limitedItems
}), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'public, max-age=3600'
}
})
}
} catch (error) {
return new Response(JSON.stringify({
error: 'Internal server error',
message: error.message
}), {
status: 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
})
}
}
NOTE
Do not forget to put your API KEY inside the worker code. Then, copy your worker URL.
3
Webflow Configuration
Add this in your Webflow page Head Code:
<!-- BeBranded Contents -->
<script async src="https://cdn.jsdelivr.net/npm/@bebranded/bb-contents@1/bb-contents.js"></script>
<!-- Youtube Integration by bb-contents -->
<script>
window._bbContentsConfig = {
youtubeEndpoint: 'YOUR CLOUDFLARE WORKER URL HERE'
};
</script>
NOTE
Create a div in Webflow
Add attribute: bb-youtube-channel="UC_YOUR_CHANNEL_ID"
Add template with bb-youtube-item
Use the template page to have the structure in Webflow
Easy to deploy, copy and paste to use it freely in your projects!
4
Module customization
Channel ID
bb-youtube-channel
=
"Channel ID"
Ajouter cet attribut :
Nom
bb-youtube-channel
Valeur
Channel ID
Number of videos in the grid
bb-youtube-video-count
=
"9"
Ajouter cet attribut :
Nom
bb-youtube-video-count
Valeur
9
NOTE
You can put the number you want.
Allowing Youtube Shorts?
bb-youtube-allow-shorts
=
"true"
Ajouter cet attribut :
Nom
bb-youtube-allow-shorts
Valeur
true
NOTE
value are true or false.
Module language
bb-youtube-language
=
"en"
Ajouter cet attribut :
Nom
bb-youtube-language
Valeur
en
NOTE
The module currently supports only 2 languages:
- French (fr) - Default language
- English (en) - Alternative language
1
2
Still need help?