All guides

November 9, 2026 · 4 min read

How to Get YouTube Transcripts in Go

In short

Fetch YouTube transcripts in Go with net/http: typed structs for the JSON response, SRT and VTT downloads, translation, and retries on temporary errors.

Go's standard library is all you need. One GET request to the TranscriptYT YouTube Transcript API returns any public video's transcript with timestamps, so your service never scrapes YouTube or runs into datacenter IP blocks.

Fetch and decode a transcript

Create a free key in the dashboard (100 transcripts, no card) and export it as TRANSCRIPTYT_KEY.

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"time"
)

type Segment struct {
	Start    float64 `json:"start"`
	Duration float64 `json:"duration"`
	Text     string  `json:"text"`
}

type Transcript struct {
	VideoID  string    `json:"videoId"`
	Title    string    `json:"title"`
	Language string    `json:"language"`
	Source   string    `json:"source"`
	Segments []Segment `json:"segments"`
}

type apiError struct {
	Error struct {
		Code    string `json:"code"`
		Message string `json:"message"`
	} `json:"error"`
}

var client = &http.Client{Timeout: 120 * time.Second}

func getTranscript(video string) (*Transcript, error) {
	q := url.Values{"url": {video}}
	req, err := http.NewRequest("GET", "https://transcript-yt.com/v1/transcript?"+q.Encode(), nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("TRANSCRIPTYT_KEY"))
	res, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()
	if res.StatusCode != http.StatusOK {
		var e apiError
		json.NewDecoder(res.Body).Decode(&e)
		return nil, fmt.Errorf("%s: %s", e.Error.Code, e.Error.Message)
	}
	var t Transcript
	return &t, json.NewDecoder(res.Body).Decode(&t)
}

func main() {
	t, err := getTranscript("https://youtu.be/5f3Pn-N6yLc")
	if err != nil {
		panic(err)
	}
	fmt.Println(t.Title, t.Language, t.Source)
	for _, s := range t.Segments[:3] {
		fmt.Printf("%7.1fs  %s\n", s.Start, s.Text)
	}
}

Subtitle files and translation

Add format=srt, vtt, text, csv, or md and copy the body straight to a file. Add translate_to=es (or any of 150+ codes) to translate while keeping the timings.

q := url.Values{"url": {"5f3Pn-N6yLc"}, "format": {"srt"}, "translate_to": {"es"}}
// same request as above, then:
f, _ := os.Create("captions.es.srt")
defer f.Close()
io.Copy(f, res.Body)

Retries

BLOCKED, RATE_LIMITED, and UPSTREAM_ERROR are temporary; retry them with exponential backoff. VIDEO_UNAVAILABLE, NO_CAPTIONS, and LANGUAGE_NOT_AVAILABLE are final for that video, and a 402 means you're out of credits. Failed requests are never billed. Every code is listed in the docs.

Common questions

Is there a Go package for YouTube transcripts?

You don't need one: the API is a single GET request, and the structs below decode the response. Any language that can send HTTPS works the same way.

How do I get plain text instead of segments?

Add format=text to the query and read the body as a string, or join the segments' Text fields.

Can I fetch many videos concurrently?

Yes. Paid plans allow 200 requests a minute; run a small worker pool with goroutines, or use the batch endpoint for up to 500 videos in one request, depending on plan.

Try the YouTube Transcript API

Get transcripts as JSON, text, SRT, or VTT. 100 free credits, no card required.

More guides