appscript.dev
Automation Intermediate Docs

Summarize YouTube videos into notes

Turn transcripts into Northwind study summaries — one Doc per video.

Published Oct 6, 2025

Northwind’s team watches a lot of conference talks and tutorials, but a forty-minute video is hard to revisit and impossible to skim. The useful parts — the key terms, the takeaways — get lost unless someone sits down and writes notes, and that rarely happens.

This script does the note-taking. You give it a YouTube video ID, it fetches the transcript, asks Claude to turn it into structured study notes, and saves the result as a Google Doc — one Doc per video. What you get back is something you can search and skim in two minutes instead of rewatching the whole thing.

What you’ll need

  • A transcript service that returns plain text for a YouTube video ID. The script points at one via a URL — swap in whichever service you use.
  • An Anthropic API key saved as ANTHROPIC_API_KEY in Script Properties — see Store API keys and secrets securely.
  • Nothing else — the script creates the Doc itself in your Drive.

The script

// The transcript service endpoint — it takes a ?v= video ID and
// returns the plain-text transcript.
const TRANSCRIPT_SERVICE_URL = 'https://transcript-service.example/?v=';

// How many characters of transcript to send to Claude. Keeps the
// prompt within a sensible token budget — see "Watch out for".
const MAX_TRANSCRIPT_CHARS = 12000;

/**
 * Fetches a YouTube transcript, asks Claude to turn it into structured
 * study notes, and saves the result as a new Google Doc.
 *
 * @param {string} videoId The YouTube video ID to summarise.
 * @return {string} The URL of the created Doc.
 */
function summariseYoutube(videoId) {
  if (!videoId) {
    Logger.log('No video ID supplied — nothing to summarise.');
    return;
  }

  // 1. Fetch the transcript and trim it to the character budget.
  const transcript = UrlFetchApp.fetch(TRANSCRIPT_SERVICE_URL + videoId)
    .getContentText()
    .slice(0, MAX_TRANSCRIPT_CHARS);

  if (!transcript.trim()) {
    Logger.log('Transcript was empty for ' + videoId + ' — nothing to do.');
    return;
  }

  // 2. Ask Claude for structured notes, not a loose paragraph.
  const prompt =
    'Summarise this video transcript into structured study notes. ' +
    'Use clear sections, a list of key terms, and a list of takeaways.' +
    '\n\n' + transcript;

  // 3. Sonnet does the summarising — worth the cost for long-form text.
  const notes = callClaude(prompt, 'claude-sonnet-4-6', 2000);

  // 4. Save the notes as a new Doc, named after the video.
  const doc = DocumentApp.create('Notes — ' + videoId);
  doc.getBody().setText(notes);
  doc.saveAndClose();

  Logger.log('Saved notes: ' + doc.getUrl());
  return doc.getUrl();
}

/**
 * Minimal Anthropic API call. The key lives in Script Properties — it
 * is never pasted into the code.
 */
function callClaude(prompt, model = 'claude-haiku-4-5-20251001', maxTokens = 400) {
  const key = PropertiesService.getScriptProperties()
    .getProperty('ANTHROPIC_API_KEY');
  const res = UrlFetchApp.fetch('https://api.anthropic.com/v1/messages', {
    method: 'post',
    contentType: 'application/json',
    headers: { 'x-api-key': key, 'anthropic-version': '2023-06-01' },
    payload: JSON.stringify({
      model,
      max_tokens: maxTokens,
      messages: [{ role: 'user', content: prompt }],
    }),
    muteHttpExceptions: true,
  });
  return JSON.parse(res.getContentText()).content[0].text.trim();
}

How it works

  1. summariseYoutube takes a video ID and bails out early if none was passed, so an empty call never hits the transcript service.
  2. It fetches the transcript from TRANSCRIPT_SERVICE_URL and trims it to MAX_TRANSCRIPT_CHARS, keeping the prompt within a sensible token budget.
  3. If the transcript comes back empty — a private video, a missing caption track — it logs a message and stops rather than summarising nothing.
  4. It builds a prompt asking for structured notes: sections, key terms, and takeaways, rather than one loose paragraph.
  5. It calls Claude Sonnet, which is worth the cost for coherent long-form summarising.
  6. It creates a Google Doc named after the video, writes the notes into the body, saves it, and returns the Doc’s URL.

Example run

Call summariseYoutube('dQw4w9WgXcQ') and a new Doc appears in your Drive, titled Notes — dQw4w9WgXcQ, containing something like:

Overview A 35-minute talk on structuring Apps Script projects for maintainability.

Key terms

  • Triggers — scheduled or event-driven entry points
  • Script Properties — per-project key/value storage
  • Execution quota — the daily limit on runtime

Takeaways

  1. Keep configuration in named constants at the top of the file.
  2. Guard every external call so a bad response fails loudly.
  3. Batch sheet reads and writes to stay well inside the quota.

That is a page you can skim before a meeting instead of rewatching the talk.

Run it

This is an on-demand job — you run it once per video:

  1. In the Apps Script editor, write a one-line wrapper that calls summariseYoutube with the video ID, then select it and click Run.
  2. Approve the authorisation prompt the first time.
  3. Open your Drive to find the new Notes — ... Doc.

Watch out for

  • The transcript service is yours to supply. The URL here is a placeholder; point TRANSCRIPT_SERVICE_URL at a real service and check what format it returns before relying on the output.
  • Long videos are truncated. Only the first MAX_TRANSCRIPT_CHARS characters are sent, so notes for a long talk cover the opening, not the end. Raise the cap and max_tokens together if you need full coverage.
  • The Doc title uses the video ID, not the video name. Two runs on the same video create two Docs — rename them, or look up the real title to use instead.
  • Notes are only as good as the transcript. Auto-generated captions garble names and jargon; expect Claude to carry those errors through into the summary.

Related