Youtube Grid

BeBranded Contents brings powerful, no-code features to your Webflow sites through simple HTML attributes. Add social sharing, dynamic favicons and more with just a single script. Designed in France, built for the global Webflow community.

Designed for Webflow

Easy to implement

youtube grid on webflow for free by bebranded
Obtain a Google API for Youtube
Go to this website: https://console.cloud.google.com/
Create an API key 'YouTube Data API v3'
Copy the key in the worker code below
Create a worker on Cloudflare
And paste this code inside it
// 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': '*'
      }
    })
  }
}
Script to paste into your Webflow project → 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>