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.
Share this feature
Youtube Grid on Webflow
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?