Skip to content

RESOURCES / BLOG

Customizing videos with custom CTAs

Users are now interacting with videos more and more every day. In this article, we explore how to add action points within and after our video has finished playing.

Before we begin, we are going to set up the content we are going to use. This is a video and an image we will use as a banner in the video. We will store these files in Cloudinary a media management platform with a powerful set of APIs and SDKs. If you do not have an account, feel free to create one here.

Proceed to the media library and create a folder called nuxtjs-in-video-cta and add the following files:

free-video-856479

pexels-kelly-lacy-9722139

Here is a screenshot of the resulting folder:

Folder screenshot

The final project can be viewed on Codesandbox.

You can find the full source code on my Github repository.

To build our app, we will be using Nuxt.Js, a Vue.Js framework. To get started, ensure you have either yarn or npm v5.2+/v6.1+ installed. Open the terminal in your preferred working directory and run the following command


yarn create nuxt-app nuxtjs-in-video-cta

# OR

npx create-nuxt-app nuxtjs-in-video-cta

# OR

npm init nuxt-app nuxtjs-in-video-cta

Code language: PHP (php)

This will trigger a set of prompts. Here are our recommended defaults:

Project name: nuxtjs-in-video-cta

Programming language: JavaScript

Package manager: Yarn

UI framework: Tailwind CSS

Nuxt.js modules: N/A

Linting tools: N/A

Testing frameworks: None

Rendering mode: Universal (SSR/SSG)

Deployment target: Server (Node.js hosting)

Development tools: N/A

You may now enter and run the app. The output should be visible on https://localhost:3000


cd nuxtjs-in-video-cta

  

yarn dev

# OR

npm run dev

Code language: PHP (php)

To be able to display custom CTAs, we need to be able to detect and react when the video player state changes. Cloudinary’s video player allows us to receive such events. That is why we will be using it.

First and foremost, we will be adding the video player’s assets to our nuxt.config.js file. This is how simple installation is.


// nuxt.config.js

export  default  {

head:  {

...

link: [

...

{ rel:  'stylesheet', href:  'https://unpkg.com/cloudinary-video-player@1.5.9/dist/cld-video-player.min.css'  }

],

script:  [

{ src:  'https://unpkg.com/cloudinary-core@latest/cloudinary-core-shrinkwrap.min.js'  },

{ src:  'https://unpkg.com/cloudinary-video-player@1.5.9/dist/cld-video-player.min.js'  },

],

},

};

Code language: JavaScript (javascript)

To be able to reference our account from any file, we need to store our Cloudinary cloud name. We will store it as an environmental variable in the global .env file located at the root of the project.


touch .env

Code language: CSS (css)

To get your cloud name, refer to your Dashboard under the Account Details section. Insert it in your .env file.


<!-- .env -->

NUXT_ENV_CLOUDINARY_CLOUD_NAME=<cloudinary-cloud-name-value>

Code language: HTML, XML (xml)

With the above setup, we may now create our video player. This is done first by creating a normal video element and adding the cld-video-player cld-video-player-skin-dark classes.


<template>

<video

id="video-player"

controls

autoplay

muted

class="cld-video-player cld-video-player-skin-dark w-full h-full"

>

</video>

</template>

Code language: HTML, XML (xml)

We will now create a Cloudinary instance in our mounted lifecycle hook and use it to initialize the video player and configure the video source.


// pages/index.vue

<script>

export default {

name: 'IndexPage',

data(){

return {

cld:null,

player:null,

video:  "nuxtjs-in-video-cta/pexels-kelly-lacy-9722139.mp4"

}

},

mounted(){

this.cld  =  cloudinary.Cloudinary.new({

cloud_name:  process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,

secure:  true

});

  

this.player  =  this.cld.videoPlayer(

'video-player'

);

this.player.source(this.video);

  

}

};

</script>

Code language: HTML, XML (xml)

We should now be able to view the video on our webpage.

Video player screenshot

In order to create a call to action based on the percentage played, we need to first receive and store the percentage in the page state. To get this data from the video player, we simply add the percentsplayed analytics event to the configuration together with the playedEventTimes we want to be notified of. We will then add an event listener for the percentsplayed event.


// pages/index.vue

<script>

export default {

data(){

return {

...

percentage:null

}

},

mounted(){

...

this.player  =  this.cld.videoPlayer(

'video-player',

{

playedEventTimes:  [10,20,30,40,50,60,70,80,90],

analytics:  {

events:  [

'play',

'pause',

'`',

'start',

'ended',

]

}

}

);

this.player.source(this.video);

  

this.player.on('percentsplayed',  (event)  =>  {

this.percentage  =  event.eventData.percent;

});

  

}

};

</script>

Code language: HTML, XML (xml)

We can now render an element such as a button based on the percentage. To ensure that the element is placed above the video player, we need to position it absolutely in a relatively positioned parent.


<!-- pages/index.vue -->

<template>

<div>

...

<div class="w-2/3 h-96 my-10 mx-auto relative">

  

<video

id="video-player"

controls

autoplay

muted

class="cld-video-player cld-video-player-skin-dark w-full h-full"

>

</video>

<a

v-if="percentage > 20 && percentage < 70"

href="https://www.pexels.com/video/aerial-view-on-city-during-dawn-9722139/"

target="_blank"

class="inline-flex items-center px-4 py-2 opacity-50 hover:opacity-70 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-white bg-transparent hover:text-black hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 absolute top-10 right-10"

>

View on Pexels

</a>

</div>

</div>

</template>

Code language: HTML, XML (xml)

Now we should see the button when the percentage is greater than 20 but less than 70.

CTA button visible

The next call to action we want to display is one that is visible when the video is either paused or it has ended. We do this by simply adding the events to the event. analytics setting in the video player initialization. We then add event listeners to store the video state in the page state.


// pages/index.vue

<script>

export default {

name: 'IndexPage',

data(){

return {

cld:null,

player:null,

video:  "nuxtjs-in-video-cta/pexels-kelly-lacy-9722139.mp4",

percentage:null,

paused:null,

ended:null

}

},

mounted(){

this.cld  =  cloudinary.Cloudinary.new({

cloud_name:  process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,

secure:  true

});

  

this.player  =  this.cld.videoPlayer(

'video-player',

{

playedEventTimes:  [10,20,30,40,50,60,70,80,90],

analytics:  {

events:  [

'play',

'pause',

'percentsplayed',

'start',

'ended',

]

}

}

);

this.player.source(this.video);

  

this.player.on('percentsplayed',  (event)  =>  {

this.percentage  =  event.eventData.percent;

});

  

this.player.on('play',  ()  =>  {

this.paused  =  false;

this.ended  =  false;

});

  

this.player.on('pause',  ()  =>  {

this.paused  =  true;

});

  

this.player.on('start',  ()  =>  {

this.paused  =  false;

this.ended  =  false;

});

  

this.player.on('ended',  ()  =>  {

this.ended  =  true;

});

  

}

};

</script>

Code language: HTML, XML (xml)

Now we can simply show the CTA when paused or ended is true.


<!-- pages/index.vue -->

<template>

<div>

<div class="w-2/3 h-96 my-10 mx-auto relative">

  

<video

id="video-player"

controls

autoplay

muted

class="cld-video-player cld-video-player-skin-dark w-full h-full"

>

</video>

<a

v-if="percentage > 20 && percentage < 70"

href="https://www.pexels.com/video/aerial-view-on-city-during-dawn-9722139/"

target="_blank"

class="inline-flex items-center px-4 py-2 opacity-50 hover:opacity-70 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-white bg-transparent hover:text-black hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 absolute top-10 right-10"

>

View on Pexels

</a>

<img

v-if="paused || ended"

src="https://res.cloudinary.com/hackit-africa/image/upload/v1639495990/nuxtjs-in-video-cta/free-video-856479.jpg"

class="absolute w-96 top-16 left-72"

/>

</div>

</div>

</template>

Code language: HTML, XML (xml)

With the above setup, we should see the image when the video is paused.

CTA Banner

To read more about the Video player events and its comprehensive API, feel free to review the extensive documentation.

Start Using Cloudinary

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

Sign Up for Free