Skip to content

RESOURCES / BLOG

Build a Responsive Video Playlist with Next.js

Cloudinary provides various tools for creating, managing, and optimizing visual experiences, including a javascript-based HTML5 video player. In this article, we’ll build a responsive and optimized video playlist application using Next.js and Cloudinary.

We’ll go through getting our video assets from Cloudinary using the Node.js SDK and embedding the Cloudinary video player on a web page. Let’s get started!

Here is a link to the demo on CodeSandbox.

It is assumed you have a basic knowledge of using React and an understanding of how serverless functions.

Run this command in your terminal to create a Next.js application:

    npx create-next-app cloudinary-video-playlist

Run this command to install the required dependencies:

    npm install --save cloudinary axios 

We will use the Cloudinary node SDK to get our video assets from the Cloudinary storage, and axios is the HTTP client we will use to communicate with the serverless function endpoint.

Click here to create an account with Cloudinary or login if you already have one. After a successful onboarding, you should see your dashboard page containing your Cloudinary credentials.

We will be using the Cloud name, API key, and API secret. The API key and API secret are private credentials, so we need to add them to a .env file.

Create a .env file at the root of your project and add the following to it:

    CLOUDINARY_API_KEY = ***Your API key***
    CLOUDINARY_API_SECRET = ***Your API secret***

Now we need to upload some videos to Cloudinary. See this documentation on uploading assets to Cloudinary.

Let’s create a serverless function for fetching our video assets from our Cloudinary media library. In the api folder in your pages directory, create a file named getVideosData.js and add the following to it:

    import cloudinary from 'cloudinary';
    
    cloudinary.v2.config({ 
      cloud_name: 'ifeomaimoh', 
      api_key: process.env.CLOUDINARY_API_KEY, 
      api_secret: process.env.CLOUDINARY_API_SECRET,
      secure: true
    });
    
    export default async function getData(req,res) {
      try {
        const cloudRes = await cloudinary.v2.api.resources({ resource_type: 'video' });
        return res.json(cloudRes.resources)
      } catch (error) {
        return res.json({message:error.message})
      }
    }
Code language: JavaScript (javascript)

In the code shown above, we started by importing an instance of Cloudinary. Then we configure it by passing in an object consisting of the basic Cloudinary credentials.

We create our serverless function, which sends an HTTP request to retrieve all video assets in our Cloudinary media library. The object { resource_type: 'video'} passed as an argument to the resources method tells Cloudinary to return the resources of type video. To see other options that are available for requesting assets, click here.

After successfully creating our serverless function and using it to fetch the video assets, we need to create a way to get our data to the frontend to feed it to the player. To do this, we send an HTTP request to the endpoint /api/getVideosData and then pass the response data to the Player component.

Add the following to your index.js file:

    import React, { useEffect, useState } from "react";
    import styles from "../styles/Home.module.css";
    import axios from "axios";
    import Player from "../components/Player";
    
    export default function Home() {
      const [videosData, setVideosData] = useState([]);
    
      useEffect(() => {
        getVideos();
      }, []);
    
      async function getVideos() {
        try {
          const response = await axios.get("/api/getVideosData");
          setVideosData(response.data);
        } catch (error) {
          console.error(error);
        }
      }
    
      return (
        <div className={styles.container}>
          {videosData.length > 0 ? <Player videosData={videosData} /> : ""}
        </div>
      );
    }
Code language: JavaScript (javascript)

We start by setting up a state, videoData, to store our video data. After the component is rendered to the page, we call getVideos() inside the useEffect hook. The function sends an HTTP request to the endpoint created by the serverless function, stores the result in a response variable that is then used to update the state if successful otherwise, it sends an error to the console.

The Home component returns a component called Player, which receives the videosData as props.

At the root of your project, create a folder called components, and inside it, create another file named Player.js and add the following to it:

    import React, { useEffect } from "react";
    import styles from "../styles/Home.module.css";

    export default function Player({ videosData }) {
      const formattedData = videosData.map((x) => x.public_id);
      useEffect(() => {
        const cld = window.cloudinary.Cloudinary.new({
          cloud_name: "ifeomaimoh",
        });

        if (videosData) {
          const player = cld.videoPlayer("example-player", {
            playlistWidget: {
              direction: "horizontal",
              total: formattedData?.length,
            },
          });

          player.playlist(formattedData, {
            autoAdvance: true,
            repeat: true,
            presentUpcoming: 3,
          });
        }
      }, [videosData, formattedData]);

      return (
        <div className={styles.player}>
          <video
            id="example-player"
            controls
            className="cld-video-player cld-video-player-skin-dark"
          ></video>
        </div>
      );
    }
Code language: JavaScript (javascript)

We instantiate a Cloudinary instance with our Cloudinary configuration, and then we instantiate the Cloudinary videoPlayer method and assign it to the variable player. Because the window object does not exist when Next.js renders on the server, we’re referencing the window object in a useEffect hook. The videoPlayer method takes in the video element id and a playlist widget object.

The playlist method, which takes the source data and other parameters object as an argument, is called on the player object. We specified an autoAdvance key in the parameter object, which indicates whether to auto-advance to the next video and the delay between them. We also set a presetUpcoming key which displays a thumbnail link of the next video on the playlist, 3seconds before the end of the current video.

To embed the video player, we return a video tag that includes the standard HTML5 video player attributes, an id, and a class that adds a dark skin theme. The Player component receives the videos’ data as props from the Home component.

To implement the video player, we can either reference the necessary video player package files directly from UNPKG CDN or install the complete video player package locally and then reference the relevant local files. In this project, we will go with the first option.

Add the following to your _app.js file:

    import "../styles/globals.css";
    import Script from "next/script";
    import Head from "next/head";

    function MyApp({ Component, pageProps }) {
      return (
        <>
          <Head>
            <link
              href="https://unpkg.com/cloudinary-video-player@1.5.9/dist/cld-video-player.min.css"
              rel="stylesheet"
            />
          </Head>
          <Script
            src="https://unpkg.com/cloudinary-core@latest/cloudinary-core-shrinkwrap.min.js"
            type="text/javascript"
            crossOrigin="anonymous"
            strategy="beforeInteractive"
          />
          <Script
            src="https://unpkg.com/cloudinary-video-player@1.5.9/dist/cld-video-player.min.js"
            type="text/javascript"
            crossOrigin="anonymous"
            strategy="beforeInteractive"
          />
          <Component {...pageProps} />
        </>
      );
    }
    export default MyApp;
Code language: JavaScript (javascript)

We used the built-in Next.js Head and Script tags to load the video player resources. We specified a link tag in the Head component, which points to the stylesheet provided by Cloudinary. We specify a strategy prop for the scripts that help load the scripts before the page becomes interactive. See here for more on the Script Component provided by Next.js.

Now replace what’s in your Home.module.css file with the following to give the application a decent look and make it responsive:

    .container {
      width: 1024px;
      max-width: 100%;
      margin: 1.5rem auto;
    }
    .player {
      border: 1px solid rgba(0, 0, 0, 0.1);
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .player > div {
      width: 100%;
      height: 100%;
    }
    .player > div > div:first-of-type > div {
      width: 100%;
      height: 15rem;
    }
    .span {
      text-align: center;
      font-weight: 500;
    }
Code language: CSS (css)

Run this command to start up your development server:

    npm run dev

Head over to your browser; you should have a video player with a playlist of videos from your Cloudinary media library.

Find the complete project here on GitHub.

Resources you may find useful:

Start Using Cloudinary

Sign up for our free plan and start creating stunning visual experiences in minutes.

Sign Up for Free