We build custom applications 5x faster and cheaper 🚀
Book a Free Consultation
Stuck on an error? Book a 30-minute call with an engineer and get a direct fix + next steps. No pressure, no commitment.
Integrate a YouTube Summarizer with OpenClaw by building a small, authenticated external summarization service (fetches transcripts, chunks them, calls an LLM), hosting it with TLS and an API key or OAuth, then installing a thin OpenClaw skill via ClawHub that calls that service. Keep heavy or stateful work (transcript storage, long-running jobs, retries) outside the agent runtime; the agent should make simple REST calls and return structured results. Configure authentication (YouTube OAuth if you need private captions, OpenAI or LLM credentials for summarization, and a service API key for the OpenClaw-to-service call) in ClawHub as credentials/environment variables, and then test and debug by checking logs, API responses, token scopes, and skill invocation traces.
This example is a practical external HTTP service you host. It:
Install dependencies:
# <b>//</b> install packages
pip install flask youtube-transcript-api openai
from flask import Flask, request, jsonify
from youtube_transcript_api import YouTubeTranscriptApi
import openai
import os
import re
import math
app = Flask(__name__)
openai.api_key = os.environ.get("OPENAI_API_KEY") # <b>//</b> set this in environment
def extract_video_id(url_or_id):
# accepts a raw id or a full YouTube URL
m = re.search(r"(?:v=|\/)([0-9A-Za-z_-]{11})", url_or_id)
if m:
return m.group(1)
if re.fullmatch(r"[0-9A-Za-z_-]{11}", url_or_id):
return url_or_id
raise ValueError("Invalid YouTube URL or ID")
def chunk_text(text, max_chars=3000):
# naive character-based chunking; tune for tokens if needed
chunks = []
start = 0
while start < len(text):
end = min(start + max_chars, len(text))
chunks.append(text[start:end])
start = end
return chunks
@app.route("/summarize", methods=["POST"])
def summarize():
data = request.get_json() or {}
youtube_url = data.get("youtube_url")
if not youtube_url:
return jsonify({"error": "youtube_url required"}), 400
try:
video_id = extract_video_id(youtube_url)
except ValueError:
return jsonify({"error": "invalid youtube url or id"}), 400
# <b>//</b> Fetch transcript (may throw if not available)
try:
transcript_parts = YouTubeTranscriptApi.get_transcript(video_id)
except Exception as e:
return jsonify({"error": "transcript_unavailable", "details": str(e)}), 500
full_text = " ".join(part.get("text", "") for part in transcript_parts).strip()
if not full_text:
return jsonify({"error": "empty_transcript"}), 500
# <b>//</b> Chunk and summarize each chunk with the LLM
chunks = chunk_text(full_text, max_chars=3000)
chunk_summaries = []
for c in chunks:
resp = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a concise summarization assistant. Produce short bullet-point summaries and a single-paragraph concise summary."},
{"role": "user", "content": f"Summarize the following transcript chunk:\n\n{c}"}
],
max_tokens=500,
temperature=0.2
)
text = resp["choices"][0]["message"]["content"].strip()
chunk_summaries.append(text)
# <b>//</b> Combine chunk summaries into final summary
combine_prompt = "Combine these chunk summaries into a final concise summary (first a single-paragraph summary, then 3 bullets with key takeaways):\n\n" + "\n\n---\n\n".join(chunk_summaries)
final_resp = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a concise summarization assistant."},
{"role": "user", "content": combine_prompt}
],
max_tokens=600,
temperature=0.2
)
final_summary = final_resp["choices"][0]["message"]["content"].strip()
return jsonify({"summary": final_summary, "video_id": video_id})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
curl -X POST "https://your-service.example.com/summarize" \
-H "Authorization: Bearer YOUR_SERVICE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"youtube_url":"https://www.youtube.com/watch?v=VIDEO_ID"}'
Speak one‑on‑one with a senior engineer about your no‑code app, migration goals, and budget. In just half an hour you’ll leave with clear, actionable next steps—no strings attached.
1
Direct answer: a 403 from the OpenClaw Connector calling YouTube transcripts usually means wrong auth type, missing OAuth scopes, denied ownership/permissions, or quota. Switch from an API key to OAuth2, request the correct YouTube scopes, re-consent the user, ensure the authenticated account can access the video's captions, and inspect the API error body for the exact reason.
Quick token inspect
```bash // inspect access token scopes curl "https://oauth2.googleapis.com/tokeninfo?access_token=ya29._TOKEN" ```2
Add a declarative entry for the YouTube Summarizer in your openclaw.yaml or openclaw.json under the project’s plugins/skills section: give it an id, display name, endpoint (the external service URL or OpenClaw-hosted skill endpoint), auth configuration that points to environment-variable names for API keys/OAuth, an inputs/outputs schema, and a flag to expose it to Pipelines and the CLI.
YAML snippet you can adapt:
plugins:
- id: youtube-summarizer
name: YouTube Summarizer
description: Summarize YouTube video transcripts
type: external
endpoint: https://you-summarizer.example.com/v1/summarize
auth:
type: api_key
env: YT_SUMMARIZER_API_KEY
schemas:
input: ./schemas/ytsummarizer-input.json
output: ./schemas/ytsummarizer-output.json
pipeline_enabled: true
cli_visible: true
3
Direct answer: Make sure the new skill package is installed into the exact Python environment the OpenClaw agent runtime uses, or add the package folder to the agent's PYTHONPATH, then restart the agent process so the runtime reloads sys.path and imports the new module.
4
Write a Transform/Schema Adapter that extracts the summary string from the YouTube Summarizer JSON, assigns it to the record's summary field, and returns the adapted object for OpenClaw's schema validator. Validate the adapted object against your record schema before returning so OpenClaw will accept it.
Steps to follow:
function transform(youtubeJson){
<b>//</b> pick likely summary fields
const summary = youtubeJson.summaryText || youtubeJson.summary || (youtubeJson.segments && youtubeJson.segments.map(s=>s.text).join('\n')) || '';
<b>//</b> produce record shape OpenClaw expects
return { summary };
}
This prompt helps an AI assistant understand your setup and guide you through the fix step by step, without assuming technical knowledge.
From startups to enterprises and everything in between, see for yourself our incredible impact.
Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We’ll discuss your project and provide a custom quote at no cost.Â