Simply copy and paste the following command line in your terminal to create your first Strapi project.
npx create-strapi-app
my-project
This guide will walk you through creating a Strapi plugin that fetches YouTube video transcripts. If you are wondering how to get a transcript of a YouTube video and learn how to build a Strapi plugin, then this tutorial is for you.
Here is a demo of what we will be building.
We will start by setting up a new Strapi CMS project. Let's follow the following steps:
npx create-strapi-app@latest get-yt-summary
➜ temp npx create-strapi-app@latest get-yt-summary
Need to install the following packages:
create-strapi-app@5.0.5
Ok to proceed? (y) y
Strapi v5.0.5 🚀 Let's create your new project
We can't find any auth credentials in your Strapi config.
Create a free account on Strapi Cloud and benefit from:
- ✦ Blazing-fast ✦ deployment for your projects
- ✦ Exclusive ✦ access to resources to make your project successful
- An ✦ Awesome ✦ community and full enjoyment of Strapi's ecosystem
Start your 14-day free trial now!
? Please log in or sign up. Skip
? Do you want to use the default database (sqlite) ? Yes
? Start with an example structure & data? No
? Start with Typescript? Yes
? Install dependencies with npm? Yes
? Initialize a git repository? Yes
cd get-yt-summary
yarn develop
After creating the user, you will be redirected to the admin page:
We are now ready to start building our Strapi plugin.
To help us get started with our YouTube transcript generator plugin, we will use the Strapi Plugin CLI SDK. You can learn more about it here.
npx @strapi/sdk-plugin@latest init get-yt-transcript-plugin
[INFO] Creating a new package at: src/plugins/get-yt-transcript-plugin
✔ plugin name … get-yt-transcript-plugin
✔ plugin display name … YT Transcript
✔ plugin description … Get YT transcript.
✔ plugin author name … Paul Brats
✔ plugin author email … paul.bratslavsky@strapi.io
✔ git url …
✔ plugin license … MIT
✔ register with the admin panel? … no
✔ register with the server? … yes
✔ use editorconfig? … yes
✔ use eslint? … yes
✔ use prettier? … yes
✔ use typescript? … yes
Now that we have a plugin, we must configure it to be available in our Strapi application.
config/plugins.ts
:1
2
3
4
5
6
export default {
"get-yt-transcript-plugin": {
enabled: true,
resolve: "./src/plugins/get-yt-transcript-plugin",
},
};
cd src/plugins/get-yt-transcript-plugin
yarn install
yarn build
yarn watch
yarn develop
We should now see the plugin in the sidebar in the admin panel:We now need to update our routes to allow us to access the plugin's exposed endpoints and use it outside of the admin panel.
Navigate to the plugin folder and let's make the following change in the src/plugin/get-yt-transcript-plugin/server/src/routes/index.ts
file:
Currently, the file looks like this:
1
2
3
4
5
6
7
8
9
10
11
export default [
{
method: "GET",
path: "/",
// name of the controller file & the method.
handler: "controller.index",
config: {
policies: [],
},
},
];
Currently, this defaults to the admin routes, which are meant to be used inside the admin panel.
In Strapi we have two types of routes:
content-api
: These routes are meant to be used outside the admin panel.admin
: These routes are meant to be used inside the admin panel.Let's update our routes to include both types.
1. Update src/plugins/get-yt-transcript-plugin/server/src/routes/index.ts
:
1
2
3
4
5
6
7
8
9
10
11
12
13
import contentApi from "./content-api";
import admin from "./admin";
export default {
"content-api": {
type: "content-api",
routes: [...contentApi],
},
admin: {
type: "admin",
routes: [...admin],
},
};
Now we must create the content-api
and the admin
routes. Let's start with the content-api
routes.
Create a new file called content-api.ts
in the src/plugins/get-yt-transcript-plugin/server/src/routes
folder and add the following:
2. Create src/plugins/get-yt-transcript-plugin/server/src/routes/content-api.ts
:
1
2
3
4
5
6
7
8
9
10
export default [
{
method: "GET",
path: "/",
handler: "controller.index",
config: {
policies: [],
},
},
];
Now let's create the admin
route.
3. Create src/plugins/get-yt-transcript-plugin/server/src/routes/admin.ts
:
1
2
3
4
5
6
7
8
9
10
export default [
{
method: "GET",
path: "/",
handler: "controller.index",
config: {
policies: [],
},
},
];
You should now have the following file structure:
Nice. Now, let's test out our plugin in its current state to see if it works.
get-yt-transcript-plugin
.Select the get-yt-transcript-plugin
and then click on the index
endpoint checkbox. Make sure to save.
Here is a screenshot of what it should look like:
Now you should be able to test the endpoint by visiting: http://localhost:1337/api/get-yt-transcript-plugin
You should see the following response:
Now, we need to create the service that will fetch the YouTube transcript.
We will use the youtubei.js
library to fetch the transcript. You can learn more about it here.
yarn add youtubei.js
Let's start by updating the code in the services.ts
file found in the src/plugins/get-yt-transcript-plugin/server/src/services
folder.
2. Create src/plugins/get-yt-transcript-plugin/server/src/services/service.ts
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import type { Core } from "@strapi/strapi";
const fetchTranscript = async (
url: string
): Promise<(string | undefined)[] | undefined> => {
const { Innertube } = await import("youtubei.js");
const youtube = await Innertube.create({
lang: "en",
location: "US",
retrieve_player: false,
});
try {
const info = await youtube.getInfo(url);
const transcriptData = await info.getTranscript();
return transcriptData?.transcript?.content?.body?.initial_segments.map(
(segment) => segment.snippet.text
);
} catch (error) {
console.error("Error fetching transcript:", error);
throw error;
}
};
async function getYouTubeTranscript(videoUrl: string) {
const videoId = new URL(videoUrl).searchParams.get("v");
const transcript = await fetchTranscript(videoId);
return transcript?.join(" ");
}
const service = ({ strapi }: { strapi: Core.Strapi }) => ({
async getYoutubeTranscript(videoId: string) {
const youtubeIdRegex = /^[a-zA-Z0-9_-]{11}$/;
const isValid = youtubeIdRegex.test(videoId);
if (!isValid) return { error: "Invalid video ID", data: null };
try {
const baseUrl = "https://www.youtube.com";
const path = "/watch";
const url = new URL(path, baseUrl);
url.searchParams.set("v", videoId);
const transcript = await getYouTubeTranscript(url.href);
return transcript;
} catch (error) {
return { error: "Error fetching transcript: " + error, data: null };
}
},
});
export default service;
The above code defines a service fetching a YouTube video's transcript using the youtubei.js
library. Here's a breakdown of what the code does:
fetchTranscript
function:
undefined
if it is not available.Innertube.create()
with default settings (language: English, location: US, and without retrieving the video player).youtube.getInfo(url)
and then attempts to fetch the transcript with info.getTranscript()
.getYouTubeTranscript
function:
fetchTranscript
to get the transcript, and joins it into a single string.service
function:
service
function exports a Strapi service that fetches YouTube transcripts.getYouTubeTranscript
to retrieve the transcript.Once you have the service ready, we can focus on creating the controller. As we mentioned before when the request is made to a designated endpoint, Strapi will call the appropriate controller, which will then call the service we just created.
In the controller.ts
file found in the src/plugins/get-yt-transcript-plugin/server/src/controllers
folder, add the following code:
Create src/plugins/get-yt-transcript-plugin/server/src/controllers/controller.ts
:
1
2
3
4
5
6
7
8
9
10
11
12
import type { Core } from "@strapi/strapi";
const controller = ({ strapi }: { strapi: Core.Strapi }) => ({
async getYoutubeTranscript(ctx) {
ctx.body = await strapi
.plugin("get-yt-transcript-plugin")
.service("service")
.getYoutubeTranscript(ctx.params.videoId);
},
});
export default controller;
We updated the following code to reference the service we just created. Now that the controller is ready, we need to update the routes to point to it before we can test it.
Remember that we created two types of routes: content-api
and admin
. We need to update both of them to point to our new controller.
So make the following changes in both files, content-api.ts
and admin.ts
, found in the src/plugins/get-yt-transcript-plugin/server/src/routes
folder:
1
2
3
4
5
6
7
8
9
10
export default [
{
method: "GET",
path: "/yt-transcript/:videoId",
handler: "controller.getYoutubeTranscript",
config: {
policies: [],
},
},
];
Now that we have the routes updated, we can test the plugin.
But first, make sure to rebuild the plugin by running the following command in the root of your plugin folder:
yarn build
And restart your Strapi server by running yarn develop
.
After rebuilding and restarting the Strapi server, let's double-check our permissions. Since we updated the controller's name, we need to make sure that the Public
role has access to it.
Here is a screenshot of what it should look like:
Now let's test it out in Postman within VSCode.
I am going to make a GET
request to the following endpoint:
1
http://localhost:1337/api/get-yt-transcript-plugin/yt-transcript/ZErV3aNdYhY
Just make sure you add a valid YouTube video ID.
You should see the following response:
Congratulations! You've now created a Strapi plugin that fetches YouTube video transcripts.
In this tutorial, we covered the process of creating our first Strapi plugin and how to get a transcript of a YouTube video by building a custom Strapi plugin.
We explored how to set up a new Strapi project, initialize a plugin, configure it, and implement the necessary components, such as routes, services, and controllers.
This example provides a foundation for building more complex plugins with additional functionality.
You can watch the video for this tutorial below, if you prefer the video version of this content.
If you have any questions or feedback, feel free to comment below. You can also join us for Strapi's "Open Office Hours" on Discord. We are here Monday through Friday.
Morning Session: 4 AM CST (9:00 AM GMT)
Afternoon Session: 12:30 PM CST (6:30 PM GMT)
Also, I am in the process of updating The Epic Next JS with Strapi 5 Blog Series to include this plugin.
As part of the update, we will use this plugin to fetch the transcript for the YouTube video to summarize it using AI.
Stay tuned!