Create Shoppable Videos in Blitz.js

Banner for a MediaJam post

Emadamerho-Atori Nefe

Videos are an integral aspect of success in ecommerce, as they help drive sales and revenue. Shoppable videos is an interactive marketing tool that features products available for purchase.

In this article, we will learn how to add videos in a Blitz app using Cloudinary's Shoppable Video and Video Player.


The completed project is on CodeSandbox. Fork it and run the code.

The source code is also available on GitHub.


Knowledge of React, Blitz, and a Cloudinary account is required to get the most out of this article.

Getting started

Run any of the commands below in the terminal to install Blitz.

1yarn global add blitz
3npm install -g blitz --legacy-peer-deps

Next, scaffold a new Blitz.js project with the command below:

1blitz new brand-visualizer

The command will trigger a command-line interface (CLI) where we can configure the application. The images below show the configuration options the CLI provides:

Next, navigate into the project directory.

1cd blitz-shoppable-app

Then, run the command below to start the application at http://localhost:3000.

1blitz dev

Creating the Shoppable Video component

Next, we need to create the ShoppableVideo component, which will hold the video player. Create a components/ShoppableVideo.js file inside app `` folder and paste the code below.

1import { useEffect } from "react"
2import { Cloudinary } from "cloudinary-core"
3import "cloudinary-video-player/dist/cld-video-player.min.js"
4import "cloudinary-video-player/dist/cld-video-player.min.css"
6const ShoppableVideo = () => {
7 const cld = new Cloudinary({ cloud_name: "nefejames" })
8 useEffect(() => {
9 const videoplayer = cld
10 .videoPlayer("video-player", {
11 controls: true,
12 })
13 .width(600)
14 videoplayer.source(
15 ""
16 )
17 }, [])
18 return (
19 <div className="container">
20 <h1>Blitz.js Shoppable Video</h1>
21 <video controls autoPlay id="video-player"></video>
22 </div>
23 )
25export default ShoppableVideo

The code above does the following:

  • Imports useEffect from React.

  • Imports the required dependencies from blitz, cloudinary-core and react.

  • Imports the video player’s CSS stylesheet and JavaScript bundle.

  • Creates a cld variable and sets it to a new Cloudinary instance.

  • Instantiates the video player using the videoPlayer method. The method takes two parameters; the first is the ID of the video element, and the second is a configuration object.

  • Set the width of the video player to 600px.

  • Pass in the URL of the video we want to play to the cld.source() method.

Integrating the Shoppable Video component

Having created the ShoppableVideo component, let’s integrate it into the app. Update the pages/index.js file with the code below.

1import { Head, dynamic } from "blitz"
3const DynamicShoppableVideo = dynamic(() => import("app/components/ShoppableVideo"), {
4 ssr: false,
6const Home = () => {
7 return (
8 <div className="container">
9 <Head>
10 <title>Blitz App</title>
11 <meta name="viewport" content="initial-scale=1.0, width=device-width" />
12 </Head>
13 <main>
14 <DynamicShoppableVideo />
15 </main>
16 </div>
17 )
19Home.suppressFirstRenderFlicker = true
20export default Home

Here, we import dynamic from Next.js and use that to dynamically import ShoppableVideo with SSR turned off. This is because the Cloudinary video player package works only on the client-side and needs the window object.

With that, the video player renders in the browser.

Adding the Shoppable Video feature

Now, we'll add the shoppable video to the player. To do that, we need to update the components/ShoppableVideo.js file and pass one more parameter to the cld.source() method.

However, we first need to define the data of the product we want to display in the shoppable feature.

Create an app/data/index.js file and update it with the code below.

1const shoppable = {
2 products: [
3 {
4 productId: 1,
5 productName: "A Dog",
6 publicId:
7 "",
8 onClick: {
9 action: "goto",
10 pause: true,
11 args: {
12 url: "/product/1",
13 },
14 },
15 },
16 ],
19export default shoppable

Let's break down the code above:

  • We defined and exported an object called shoppable. The products array contains the configuration for the products we want to display.

  • productId is the ID of the product.

  • productName is the name of the product.

  • publicId is the ID of the product image; in this case, it is the URL of the product image.

  • onClick defines what happens when a user clicks on a product in the products bar.

  • We set the action to goto, which will open a URL in a new tab.

  • pause will pause the video onClick.

  • We define the URL for the action in args.

Next, we'll add the shoppable object we defined to the cld.source() method. Update the components/ShoppableVideo.js file with the code below.

1import { useEffect } from "react"
2import shoppable from "app/data" //added
3import { Cloudinary } from "cloudinary-core"
4import "cloudinary-video-player/dist/cld-video-player.min.js"
5import "cloudinary-video-player/dist/cld-video-player.min.css"
7const ShoppableVideo = () => {
8 const cld = new Cloudinary({ cloud_name: "nefejames" })
9 useEffect(() => {
10 const videoplayer = cld
11 .videoPlayer("video-player", {
12 controls: true,
13 })
14 .width(600)
15 videoplayer.source(
16 "",
17 {
18 shoppable: shoppable, //added
19 }
20 )
21 }, [])
23 return (
24 <div className="container">
25 <h1>Blitz.js Shoppable Video</h1>
26 <video controls autoPlay id="video-player"></video>
27 </div>
28 )
31export default ShoppableVideo

With this, the shoppable video displays on the browser.

Creating the product page

When a user clicks on a product, we want to redirect them to the product’s page, where they can make a purchase. That’s why we defined the action as goto in the shoppable data.

Create a pages/product/[id].js file and paste the code below to make the page.

1import Cart from "app/components/Cart"
2import shoppable from "app/data"
3import { useState } from "react"
5const Product = () => {
6 const [cartItem, setCartItem] = useState(null)
7 const addToCart = () => {
8 setCartItem({
9 imgUrl: shoppable.products[0].publicId,
10 name: shoppable.products[0].productName,
11 })
12 }
13 return (
14 <div className="product-container ">
15 <div className="product">
16 <img src={shoppable.products[0].publicId} alt="a product" />
17 <span>$20:00</span>
18 <span>{shoppable.products[0].productName}</span>
19 <button onClick={addToCart}>Buy</button>
20 </div>
21 <Cart cartItem={cartItem} />
22 </div>
23 )
26export default Product

Above, we did the following:

  • Imported the required dependencies.

  • Created a cartItem state that will hold the data of the product in the cart.

  • Created an addToCart function, which is an object containing the product’s name and image. Then we passed addToCart to the button.

  • Accessed the product’s data from shoppable and displayed it.

  • Passed the cartItem state to the Cart component. The Cart component will show the items the user bought.

Let’s define the Cart component.

1const Cart = ({ cartItem }) => {
2 return (
3 <div className="cart-box">
4 <div className="cart">
5 <h2>Cart</h2>
6 {cartItem ? (
7 <div>
8 <img src={cartItem.imgUrl} alt="a product" />
9 <span>{}</span>
10 </div>
11 ) : (
12 <span>Cart is empty</span>
13 )}
14 </div>
15 </div>
16 )
19export default Cart

Here, we check to ensure an item is in the cart and display that item. With that, we have successfully added the product page.

Here’s a gif of the working demo.


This article demonstrated how to add videos in a Blitz app using Cloudinary's Shoppable Video and Video Player.


Emadamerho-Atori Nefe

Frontend Developer and Technical Writer