Skip to content
← All posts
TutorialJavaScriptLangChain

How to Build a YouTube Agent with LangChain in JavaScript

Hussein Hakizimana··6 min read

Agents need data to be useful. If you're building one that works with YouTube content, you need a way to give it access to transcripts, comments, and search results without writing a scraper or managing quota limits.

This post shows how to add YouTube tools to a LangChain agent using Stophy. The agent gets three tools — fetch a transcript, pull comments, search YouTube — and can call them as needed based on the user's question.

Setup

Terminal
1npm install @langchain/core @langchain/openai langchain

You need a Stophy API key from stophy.dev/dashboard and an OpenAI API key.

Build the tools

Start with a shared fetch helper so you're not repeating headers:

js
1async function stophy(body) {
2 const res = await fetch('https://api.stophy.dev/v1/video', {
3 method: 'POST',
4 headers: {
5 'Authorization': `Bearer ${process.env.STOPHY_API_KEY}`,
6 'Content-Type': 'application/json',
7 },
8 body: JSON.stringify(body),
9 });
10 if (!res.ok) throw new Error(`Stophy request failed: ${res.status}`);
11 const { data } = await res.json();
12 return data;
13}

Now the three tools:

js
1import { DynamicTool } from '@langchain/core/tools';
2
3const transcriptTool = new DynamicTool({
4 name: 'get_transcript',
5 description: 'Get the full transcript of a YouTube video. Input is a YouTube video URL.',
6 func: async (videoUrl) => {
7 const data = await stophy({ videoUrl, type: 'transcript' });
8 if ('empty' in data) return 'No transcript available for this video.';
9 return data.text;
10 },
11});
12
13const commentsTool = new DynamicTool({
14 name: 'get_comments',
15 description: 'Get the top comments from a YouTube video. Input is a YouTube video URL.',
16 func: async (videoUrl) => {
17 const data = await stophy({ videoUrl, type: 'comments', sortBy: 'top' });
18 return data.items
19 .slice(0, 20)
20 .map((c) => `${c.author}: ${c.text}`)
21 .join('\n');
22 },
23});
24
25const searchTool = new DynamicTool({
26 name: 'search_youtube',
27 description: 'Search YouTube for videos. Input is a search query string.',
28 func: async (q) => {
29 const res = await fetch('https://api.stophy.dev/v1/search', {
30 method: 'POST',
31 headers: {
32 'Authorization': `Bearer ${process.env.STOPHY_API_KEY}`,
33 'Content-Type': 'application/json',
34 },
35 body: JSON.stringify({ q }),
36 });
37 if (!res.ok) throw new Error(`Search failed: ${res.status}`);
38 const { data } = await res.json();
39 return data.items
40 .slice(0, 5)
41 .map((v) => `${v.title} — ${v.videoUrl}`)
42 .join('\n');
43 },
44});

Wire up the agent

js
1import { ChatOpenAI } from '@langchain/openai';
2import { AgentExecutor, createOpenAIFunctionsAgent } from 'langchain/agents';
3import { ChatPromptTemplate, MessagesPlaceholder } from '@langchain/core/prompts';
4
5const tools = [transcriptTool, commentsTool, searchTool];
6
7const prompt = ChatPromptTemplate.fromMessages([
8 ['system', 'You are a research assistant with access to YouTube data. Use the tools to answer questions about videos, channels, and topics.'],
9 ['human', '{input}'],
10 new MessagesPlaceholder('agent_scratchpad'),
11]);
12
13const llm = new ChatOpenAI({ model: 'gpt-4o', temperature: 0 });
14const agent = await createOpenAIFunctionsAgent({ llm, tools, prompt });
15const executor = new AgentExecutor({ agent, tools });

Run it

js
1const result = await executor.invoke({
2 input: 'Summarize this video and tell me what the top comments say: https://www.youtube.com/watch?v=YOUR_VIDEO_ID',
3});
4
5console.log(result.output);

The agent calls get_transcript, reads the content, then calls get_comments for audience reaction, and combines them into a summary. You don't have to orchestrate any of that — it figures out what to call based on the question.

Full script

js
1import { DynamicTool } from '@langchain/core/tools';
2import { ChatOpenAI } from '@langchain/openai';
3import { AgentExecutor, createOpenAIFunctionsAgent } from 'langchain/agents';
4import { ChatPromptTemplate, MessagesPlaceholder } from '@langchain/core/prompts';
5
6async function stophy(body) {
7 const res = await fetch('https://api.stophy.dev/v1/video', {
8 method: 'POST',
9 headers: {
10 'Authorization': `Bearer ${process.env.STOPHY_API_KEY}`,
11 'Content-Type': 'application/json',
12 },
13 body: JSON.stringify(body),
14 });
15 if (!res.ok) throw new Error(`Stophy request failed: ${res.status}`);
16 const { data } = await res.json();
17 return data;
18}
19
20const tools = [
21 new DynamicTool({
22 name: 'get_transcript',
23 description: 'Get the full transcript of a YouTube video. Input is a YouTube video URL.',
24 func: async (videoUrl) => {
25 const data = await stophy({ videoUrl, type: 'transcript' });
26 if ('empty' in data) return 'No transcript available for this video.';
27 return data.text;
28 },
29 }),
30 new DynamicTool({
31 name: 'get_comments',
32 description: 'Get the top comments from a YouTube video. Input is a YouTube video URL.',
33 func: async (videoUrl) => {
34 const data = await stophy({ videoUrl, type: 'comments', sortBy: 'top' });
35 return data.items.slice(0, 20).map((c) => `${c.author}: ${c.text}`).join('\n');
36 },
37 }),
38 new DynamicTool({
39 name: 'search_youtube',
40 description: 'Search YouTube for videos. Input is a search query string.',
41 func: async (q) => {
42 const res = await fetch('https://api.stophy.dev/v1/search', {
43 method: 'POST',
44 headers: {
45 'Authorization': `Bearer ${process.env.STOPHY_API_KEY}`,
46 'Content-Type': 'application/json',
47 },
48 body: JSON.stringify({ q }),
49 });
50 if (!res.ok) throw new Error(`Search failed: ${res.status}`);
51 const { data } = await res.json();
52 return data.items.slice(0, 5).map((v) => `${v.title} — ${v.videoUrl}`).join('\n');
53 },
54 }),
55];
56
57const prompt = ChatPromptTemplate.fromMessages([
58 ['system', 'You are a research assistant with access to YouTube data. Use the tools to answer questions about videos, channels, and topics.'],
59 ['human', '{input}'],
60 new MessagesPlaceholder('agent_scratchpad'),
61]);
62
63const llm = new ChatOpenAI({ model: 'gpt-4o', temperature: 0 });
64const agent = await createOpenAIFunctionsAgent({ llm, tools, prompt });
65const executor = new AgentExecutor({ agent, tools });
66
67const result = await executor.invoke({
68 input: 'Summarize this video and tell me what the top comments say: https://www.youtube.com/watch?v=YOUR_VIDEO_ID',
69});
70
71console.log(result.output);
Terminal
1STOPHY_API_KEY=your_key OPENAI_API_KEY=your_key node --input-type=module agent.js

The docs have the rest of the endpoints — channels, playlists, search filters, and more.