Rumble Transcript API

Beta

Returns the timed transcript of a public Rumble video, short or past live stream: the uploader's caption track when there is one, otherwise Rumble's automatic captions, as segments with start and end times and the full text, in the language you ask for when Rumble has it. Each answer says which track it used, links its WebVTT file and lists every track the video has. Videos without captions are transcribed from their audio with speech-to-text. Accepts every Rumble video link form, embed links included, or a bare video ID.

Get 100 free creditsAPI referenceTry it

Price
From 1 credit per request, up to 122 credits$0.75–$1.45 per 1,000 requests
Request
GET /v1/rumble/transcriptOne API key, one JSON schema
Input
urle.g. https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html
Failed requests
Free: 0 credits

Use cases

What teams build with it. From one request.

  • Summarize or search Rumble videos and podcasts with LLMs
  • Monitor what channels say about a topic or brand
  • Index a channel's back catalog for RAG
  • Turn live stream replays into articles and clips

What you get

Transcripts in one schema. The same on every platform.

platformstring
Platform the media is hosted on.
idstring
Platform-native ID of the post (equals post.id).
urlstring
Canonical URL of the post.
languagestring
BCP-47 language of the returned transcript; null when unknown.
sourcestring
captions = platform caption track; asr = speech-to-text on the audio. New values may be added.
is_auto_generatedboolean
True when the track was machine-generated (platform auto-captions or ASR).
available_languagesstring[]
BCP-47 caption languages the platform offers for this post; [] if none or not listed.
duration_msinteger
Media duration in milliseconds; null when unknown.

Every field, its type and when it is null: the response reference and the transcript schema.

Example request

cURL
curl -G 'https://staging.socialtap.dev/v1/rumble/transcript' \
  --data-urlencode 'url=https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html' \
  -H "x-api-key: $SOCIALTAP_API_KEY"
Node.js
const params = new URLSearchParams({
  url: "https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html",
});
const res = await fetch(`https://staging.socialtap.dev/v1/rumble/transcript?${params}`, {
  headers: { "x-api-key": process.env.SOCIALTAP_API_KEY ?? "" },
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const { data, meta } = body;
console.log(data, meta.credits_charged);
Python
import os

import requests

res = requests.get(
    "https://staging.socialtap.dev/v1/rumble/transcript",
    params={"url": "https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html"},
    headers={"x-api-key": os.environ["SOCIALTAP_API_KEY"]},
)
body = res.json()
if not res.ok:
    raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
data, meta = body["data"], body["meta"]
print(data, meta["credits_charged"])
Go
package main

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

func main() {
	q := url.Values{}
	q.Set("url", "https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html")
	req, err := http.NewRequest("GET", "https://staging.socialtap.dev/v1/rumble/transcript?"+q.Encode(), nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("x-api-key", os.Getenv("SOCIALTAP_API_KEY"))
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()
	var body struct {
		Data  json.RawMessage `json:"data"`
		Meta  map[string]any  `json:"meta"`
		Error *struct {
			Code    string `json:"code"`
			Message string `json:"message"`
		} `json:"error"`
	}
	if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
		log.Fatal(err)
	}
	if body.Error != nil {
		log.Fatalf("%s: %s", body.Error.Code, body.Error.Message)
	}
	fmt.Println(string(body.Data), body.Meta["credits_charged"])
}
PHP
<?php

$query = http_build_query([
    'url' => 'https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html',
]);
$ch = curl_init('https://staging.socialtap.dev/v1/rumble/transcript?' . $query);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('SOCIALTAP_API_KEY')],
]);
$body = json_decode(curl_exec($ch), true);
if (curl_getinfo($ch, CURLINFO_RESPONSE_CODE) >= 400) {
    throw new RuntimeException($body['error']['code'] . ': ' . $body['error']['message']);
}
print_r($body['data']);
echo $body['meta']['credits_charged'], PHP_EOL;
Ruby
require "json"
require "net/http"

uri = URI("https://staging.socialtap.dev/v1/rumble/transcript")
uri.query = URI.encode_www_form('url' => 'https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html')
req = Net::HTTP::Get.new(uri)
req["x-api-key"] = ENV.fetch("SOCIALTAP_API_KEY")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(req) }
body = JSON.parse(res.body)
raise "#{body["error"]["code"]}: #{body["error"]["message"]}" unless res.is_a?(Net::HTTPSuccess)
pp body["data"]
puts body["meta"]["credits_charged"]
Java
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class Main {
    public static void main(String[] args) throws Exception {
        String query = "url=" + encode("https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html");
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://staging.socialtap.dev/v1/rumble/transcript?" + query))
            .header("x-api-key", System.getenv("SOCIALTAP_API_KEY"))
            .GET()
            .build();
        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());
        // An error is {"error": {"code", "message", ...}}; success is {data, meta}, meta.credits_charged its price.
        if (response.statusCode() >= 400) throw new RuntimeException(response.body());
        System.out.println(response.body());
    }

    static String encode(String value) {
        return URLEncoder.encode(value, StandardCharsets.UTF_8);
    }
}
.NET
using System.Text.Json;

using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("SOCIALTAP_API_KEY"));

var query = string.Join("&",
    "url=" + Uri.EscapeDataString("https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html"));
var res = await http.GetAsync("https://staging.socialtap.dev/v1/rumble/transcript?" + query);
using var body = JsonDocument.Parse(await res.Content.ReadAsStringAsync());
if (!res.IsSuccessStatusCode)
{
    var error = body.RootElement.GetProperty("error");
    throw new Exception($"{error.GetProperty("code")}: {error.GetProperty("message")}");
}
Console.WriteLine(body.RootElement.GetProperty("data"));
Console.WriteLine(body.RootElement.GetProperty("meta").GetProperty("credits_charged"));
Rust
// Cargo.toml: reqwest = { version = "0.12", features = ["blocking", "json"] }, serde_json = "1"
use std::env;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let res = reqwest::blocking::Client::new()
        .get("https://staging.socialtap.dev/v1/rumble/transcript")
        .query(&[("url", "https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html")])
        .header("x-api-key", env::var("SOCIALTAP_API_KEY")?)
        .send()?;
    let ok = res.status().is_success();
    let body: serde_json::Value = res.json()?;
    if !ok {
        return Err(format!("{}: {}", body["error"]["code"], body["error"]["message"]).into());
    }
    println!("{} {}", body["data"], body["meta"]["credits_charged"]);
    Ok(())
}
200 OK
{
  "data": {
    "available_languages": [
      "en"
    ],
    "duration_ms": 1678000,
    "id": "v79xhhm",
    "is_auto_generated": true,
    "language": "en",
    "platform": "rumble",
    "platform_specific": {
      "rumble": {
        "caption_tracks": [
          {
            "is_auto_generated": true,
            "label": "English (auto)",
            "language": "en",
            "url": "https://hugh.cdn.rumble.cloud/video/fwe2/2f/s8/11/k/V/p/o/kVpoA.fn8Si.1.vtt"
          }
        ],
        "caption_url": "https://hugh.cdn.rumble.cloud/video/fwe2/2f/s8/11/k/V/p/o/kVpoA.fn8Si.1.vtt",
        "track_label": "English (auto)"
      }
    },
    "segments": [
      {
        "end_ms": 11030,
        "start_ms": 6830,
        "text": "Let's get into these questions, and we'll try and get through as many as we can."
      },
      {
        "end_ms": 15630,
        "start_ms": 11030,
        "text": "The first one is from Christi Marbet, who says there were a few questions about this."
      },
      {
        "end_ms": 17730,
        "start_ms": 15630,
        "text": "They want you to comment on the following, quote,"
      }
    ],
    "source": "captions",
    "text": "Let's get into these questions, and we'll try and get through as many as we can. The first one is from Christi Marbet, who says there were a few questions about this. They want you to comment on the following, quote, the Christoph piece on Palestinian rape in Israel, and its supp…",
    "url": "https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html"
  },
  "meta": {
    "request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
    "platform": "rumble",
    "source": "captions",
    "is_cached": false,
    "credits_charged": 1,
    "latency_ms": 0,
    "fetched_at": "2026-10-25T12:00:00Z",
    "input": {
      "kind": "video",
      "id": "v79xhhm",
      "url": "https://rumble.com/v79xhhm-discovery-why-glenn-wants-israel-to-sue-the-new-york-times.html"
    },
    "credits_remaining": 9999,
    "client_request_id": null,
    "warnings": [],
    "mode": "live"
  }
}

Long arrays and strings are shortened for display; real responses are complete.

Pricing

Pay per request. Only when it succeeds.

SourcePrice per successful requestPer 1,000 requests
Captions captions1 credit$0.75–$1.45
Speech-to-text asr2 credits + 2 per started minute of media
up to 122 credits (60 started minutes of media)
$1.50–$2.90 + $1.50–$2.90 per started minute of media
  • Failed requests are free: errors cost 0 credits.
  • Cache hits are free: responses served from the cache cost 0 credits.
  • Credits never expire.
  • One credit balance for every endpoint and platform.

Credit packs · How this endpoint is priced · How credits work

FAQ

Questions, answered.

How much does the Rumble Transcript API cost?
1 credit for captions results (meta.source = captions) and 2 credits + 2 per started minute of media, up to 122 credits (60 started minutes of media) for speech-to-text results (meta.source = asr), charged only for successful requests. SocialTap credits cost $0.75–$1.45 per 1,000 depending on the pack.
Am I charged for failed requests?
No. Requests that return an error cost 0 credits. Responses served from the cache are free too.

Start with 100 free credits. No card required.

Test keys answer every endpoint from recorded responses, free, so you can build before you spend. Failed requests are always free.

Get your API keyRead the API reference