Rumble Engagement API. Send a handle or channel link.
Engagement rate from a channel's latest videos. We handle the proxies, blocks and platform changes.
Rumble Engagement API at a glance
Returns a Rumble channel's or user's engagement rate per follower and per view, computed over its latest videos, shorts or live streams. The same request returns the profile, each video with its exact counts and its own rate compared with the account's typical video, views, likes, comments and reposts per video, median views, comment-to-like ratio, posting cadence, and the top and bottom video. Accepts a channel or user name, any channel or user link, or a channel ID.
GET /v1/rumble/engagement
- 1 credit per request, $0.75–$1.97 per 1,000 requests
- 12 typed fields null when unknown
handleis all it needs, e.g.Bongino- 100 credits free when you sign up, no card, so you can build before you spend
Send one request. Get 12 fields back.
Copy the request in your language, or hand it to your agent. Sign up for an API key and your first 100 credits are free.
$ npm install socialtaphandle = Bonginoconst params = new URLSearchParams({
handle: "Bongino",
});
const res = await fetch(`https://socialtap.dev/v1/rumble/engagement?${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);import os
import requests
res = requests.get(
"https://socialtap.dev/v1/rumble/engagement",
params={"handle": "Bongino"},
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"])require "json"
require "net/http"
uri = URI("https://socialtap.dev/v1/rumble/engagement")
uri.query = URI.encode_www_form('handle' => 'Bongino')
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"]<?php
$query = http_build_query([
'handle' => 'Bongino',
]);
$ch = curl_init('https://socialtap.dev/v1/rumble/engagement?' . $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;package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"os"
)
func main() {
q := url.Values{}
q.Set("handle", "Bongino")
req, err := http.NewRequest("GET", "https://socialtap.dev/v1/rumble/engagement?"+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"])
}curl 'https://socialtap.dev/v1/rumble/engagement?handle=Bongino' \
-H "x-api-key: $SOCIALTAP_API_KEY"{
"data": {
"approximate_fields": [],
"bottom_post_id": "v7gad48",
"id": "_c276782",
"metrics": {
"comment_to_like_ratio": 0.30873,
"comments_per_post": 1314.88,
"counted_post_count": 25,
"engagement_rate": 0.001517,
"engagement_rate_stddev": 0.001491,
"formats": [
{
"counted_post_count": 25,
"engagement_rate": 0.001517,
"interactions_per_post": 5573.88,
"type": "video",
"views_per_post": 410657.28
}
],
"interactions_per_post": 5573.88,
"likes_per_post": 4259,
"median_engagement_rate": 0.001104,
"median_views_per_post": 340453,
"posts_per_week": 0.24,
"quotes_per_post": null,
"rated_post_count": 25,
"reposts_per_post": 4,
"sampled_post_count": 25,
"saves_per_post": null,
"shares_per_post": null,
"view_engagement_rate": 0.011385,
"views_per_post": 410657.28
},
"newest_post_at": "2026-10-31T11:00:00Z",
"oldest_post_at": "2024-11-15T15:30:00Z",
"platform": "rumble",
"platform_specific": {},
"posts": [
{
"engagement_rate": 0.000292,
"engagement_vs_median": 0.26,
"is_counted": true,
"post": {
"approximate_fields": [],
"author": {
"avatar_url": "https://hugh.cdn.rumble.cloud/video/z8/U/K/d/b/UKdba.baa.4-bongino-t8rqq7.jpeg",
"display_name": "The Dan Bongino Show",
"id": "_c276782",
"is_verified": true,
"url": "https://rumble.com/c/bongino",
"username": "bongino"
},
"coauthors": [],
"duration_ms": 3332000,
"hashtags": [],
"id": "v7hm5b6",
"is_nsfw": false,
"is_pinned": null,
"is_sponsored": null,
"language": null,
"media": [
{
"alt_text": null,
"duration_ms": 3332000,
"expires_at": null,
"height": 1080,
"thumbnail_url": "https://hugh.cdn.rumble.cloud/video/fwe2/6a/s8/1/I/f/F/_/IfF_A.OvCc-small-Bongino-Weekend-Report-Week..jpg",
"type": "video",
"url": "https://hugh.cdn.rumble.cloud/video/fwe2/6a/s8/2/I/f/F/_/IfF_A.haa.mp4",
"width": 1920
}
],
"mentions": [],
"metrics": {
"comment_count": 82,
"like_count": 990,
"quote_count": null,
"repost_count": 0,
"save_count": null,
"share_count": null,
"view_count": 100545
},
"platform": "rumble",
"platform_specific": {
"rumble": {
"author_follower_count": 3674175,
"caption_tracks": [],
"category": null,
"concurrent_viewer_count": null,
"dislike_count": 9,
"embed_id": "v7ffsdo",
"embed_url": "https://rumble.com/embed/v7ffsdo/",
"files": [],
"is_age_restricted": false,
"is_live_now": false,
"keywords": [],
"live_started_at": null,
"numeric_id": "449194092",
"scheduled_start_at": null,
"secondary_category": null
}
},
"platform_type": "video",
"published_at": "2026-10-31T11:00:00Z",
"text": null,
"thumbnail_url": "https://hugh.cdn.rumble.cloud/video/fwe2/6a/s8/1/I/f/F/_/IfF_A.OvCc-small-Bongino-Weekend-Report-Week..jpg",
"title": "Bongino Weekend Report - Week of 10/26/26",
"type": "video",
"unknown_fields": [
"hashtags",
"mentions",
"platform_specific.rumble.keywords"
],
"url": "https://rumble.com/v7hm5b6-bongino-weekend-report-week-of-102626.html"
},
"view_engagement_rate": 0.010662,
"views_vs_median": 0.3
},
{
"engagement_rate": 0.000363,
"engagement_vs_median": 0.33,
"is_counted": true,
"post": {
"approximate_fields": [],
"author": {
"avatar_url": "https://hugh.cdn.rumble.cloud/video/z8/U/K/d/b/UKdba.baa.4-bongino-t8rqq7.jpeg",
"display_name": "The Dan Bongino Show",
"id": "_c276782",
"is_verified": true,
"url": "https://rumble.com/c/bongino",
"username": "bongino"
},
"coauthors": [],
"duration_ms": 3233000,
"hashtags": [],
"id": "v7haadi",
"is_nsfw": false,
"is_pinned": null,
"is_sponsored": null,
"language": null,
"media": [
{
"alt_text": null,
"duration_ms": 3233000,
"expires_at": null,
"height": 1080,
"thumbnail_url": "https://hugh.cdn.rumble.cloud/video/fww1/25/s8/1/g/a/y/9/gay9A.OvCc-small-Bongino-Weekend-Report-Week..jpg",
"type": "video",
"url": "https://hugh.cdn.rumble.cloud/video/fww1/25/s8/2/g/a/y/9/gay9A.haa.mp4",
"width": 1920
}
],
"mentions": [],
"metrics": {
"comment_count": 82,
"like_count": 1251,
"quote_count": null,
"repost_count": 3,
"save_count": null,
"share_count": null,
"view_count": 254011
},
"platform": "rumble",
"platform_specific": {
"rumble": {
"author_follower_count": 3674175,
"caption_tracks": [],
"category": null,
"concurrent_viewer_count": null,
"dislike_count": 17,
"embed_id": "v7f3xg0",
"embed_url": "https://rumble.com/embed/v7f3xg0/",
"files": [],
"is_age_restricted": false,
"is_live_now": false,
"keywords": [],
"live_started_at": null,
"numeric_id": "448640784",
"scheduled_start_at": null,
"secondary_category": null
}
},
"platform_type": "video",
"published_at": "2026-10-24T11:01:00Z",
"text": null,
"thumbnail_url": "https://hugh.cdn.rumble.cloud/video/fww1/25/s8/1/g/a/y/9/gay9A.OvCc-small-Bongino-Weekend-Report-Week..jpg",
"title": "Bongino Weekend Report - Week of 10/19/26",
"type": "video",
"unknown_fields": [
"hashtags",
"mentions",
"platform_specific.rumble.keywords"
],
"url": "https://rumble.com/v7haadi-bongino-weekend-report-week-of-101926.html"
},
"view_engagement_rate": 0.005248,
"views_vs_median": 0.75
},
{
"engagement_rate": 0.000354,
"engagement_vs_median": 0.32,
"is_counted": true,
"post": {
"approximate_fields": [],
"author": {
"avatar_url": "https://hugh.cdn.rumble.cloud/video/z8/U/K/d/b/UKdba.baa.4-bongino-t8rqq7.jpeg",
"display_name": "The Dan Bongino Show",
"id": "_c276782",
"is_verified": true,
"url": "https://rumble.com/c/bongino",
"username": "bongino"
},
"coauthors": [],
"duration_ms": 3316000,
"hashtags": [],
"id": "v7gyjd4",
"is_nsfw": false,
"is_pinned": null,
"is_sponsored": null,
"language": null,
"media": [
{
"alt_text": null,
"duration_ms": 3316000,
"expires_at": null,
"height": 1080,
"thumbnail_url": "https://hugh.cdn.rumble.cloud/video/fww1/bd/s8/1/i/k/s/7/iks7A.OvCc-small-Bongino-Weekend-Report-Week..jpg",
"type": "video",
"url": "https://hugh.cdn.rumble.cloud/video/fww1/bd/s8/2/i/k/s/7/iks7A.haa.mp4",
"width": 1920
}
],
"mentions": [],
"metrics": {
"comment_count": 120,
"like_count": 1180,
"quote_count": null,
"repost_count": 2,
"save_count": null,
"share_count": null,
"view_count": 265997
},
"platform": "rumble",
"platform_specific": {
"rumble": {
"author_follower_count": 3674175,
"caption_tracks": [],
"category": null,
"concurrent_viewer_count": null,
"dislike_count": 25,
"embed_id": "v7es6fm",
"embed_url": "https://rumble.com/embed/v7es6fm/",
"files": [],
"is_age_restricted": false,
"is_live_now": false,
"keywords": [],
"live_started_at": null,
"numeric_id": "448092562",
"scheduled_start_at": null,
"secondary_category": null
}
},
"platform_type": "video",
"published_at": "2026-10-17T13:00:00Z",
"text": null,
"thumbnail_url": "https://hugh.cdn.rumble.cloud/video/fww1/bd/s8/1/i/k/s/7/iks7A.OvCc-small-Bongino-Weekend-Report-Week..jpg",
"title": "Bongino Weekend Report - Week of 10/12/26",
"type": "video",
"unknown_fields": [
"hashtags",
"mentions",
"platform_specific.rumble.keywords"
],
"url": "https://rumble.com/v7gyjd4-bongino-weekend-report-week-of-101226.html"
},
"view_engagement_rate": 0.004887,
"views_vs_median": 0.78
}
],
"profile": {
"approximate_fields": [
"created_at"
],
"avatar_url": "https://hugh.cdn.rumble.cloud/video/z8/U/K/d/b/UKdba.baa.4-bongino-t8rqq7.jpeg",
"banner_url": "https://hugh.cdn.rumble.cloud/video/z8/U/K/d/b/UKdba.caa-bongino-tbhrxo.png",
"bio": "The official channel for The Dan Bongino Show®. A former Deputy Director of the FBI, Secret Service Agent, NYPD officer, and best-selling author, Dan Bongino tackles the hot political issues, debunking both liberal and Republican establishment rhetoric.",
"category": null,
"country_code": null,
"created_at": "2020-09-16T00:00:00Z",
"display_name": "The Dan Bongino Show",
"external_links": [
{
"title": "Twitter",
"url": "https://twitter.com/dbongino"
},
{
"title": "Facebook",
"url": "https://facebook.com/danbongino"
},
{
"title": "Instagram",
"url": "https://instagram.com/dbongino"
}
],
"id": "_c276782",
"is_private": false,
"is_verified": true,
"location": null,
"metrics": {
"follower_count": 3674175,
"following_count": null,
"post_count": 2150,
"total_like_count": null,
"total_view_count": 390223865
},
"platform": "rumble",
"platform_specific": {
"rumble": {
"account_type": "channel",
"numeric_id": "276782",
"user_id": "_u169h4"
}
},
"type": "unknown",
"unknown_fields": [],
"url": "https://rumble.com/c/bongino",
"username": "bongino"
},
"top_post_id": "v5pcynb",
"unknown_fields": [],
"url": "https://rumble.com/c/bongino"
},
"meta": {
"request_id": "req_3f9c2a7d1e8b4c6a9f0e2d4b6a8c0e1f",
"platform": "rumble",
"source": "page",
"is_cached": false,
"credits_charged": 1,
"latency_ms": 723,
"fetched_at": "2026-10-25T12:00:00Z",
"input": {
"kind": "profile",
"id": "_c276782",
"url": "https://rumble.com/c/bongino"
},
"credits_remaining": 9999,
"client_request_id": null,
"warnings": []
}
}import { SocialTap } from "socialtap";
const client = new SocialTap(); // apiKey defaults to process.env.SOCIALTAP_API_KEY
const res = await client.rumble.engagement.get({ handle: "Bongino" });
console.log(res.data);
console.log(res.credits.charged, res.meta.request_id);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 = "handle=" + encode("Bongino");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://socialtap.dev/v1/rumble/engagement?" + 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);
}
}using System.Text.Json;
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", Environment.GetEnvironmentVariable("SOCIALTAP_API_KEY"));
var query = string.Join("&",
"handle=" + Uri.EscapeDataString("Bongino"));
var res = await http.GetAsync("https://socialtap.dev/v1/rumble/engagement?" + 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"));// 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://socialtap.dev/v1/rumble/engagement")
.query(&[("handle", "Bongino")])
.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 · GET https://socialtap.dev/v1/rumble/engagementLong arrays and strings are shortened here. Real responses are complete.Docs One schema on 6 platforms.
The response reference lists every field, its type and when it is null. See the full schema.
Null means unknown
A field Rumble doesn't show is null, never zero or an empty string, so a real zero always means zero.
What it accepts
Rumble channel or user: a bare name (Bongino: a channel, else the user of that name), c/<name> for a channel or user/<name> for a user, any channel or user link with any tab after it (rumble.com/c/Bongino, rumble.com/c/Bongino/videos, rumble.com/user/vivafrei/about, the root rumble.com/Bongino link), or a channel's id as this API returns it (_c276782) or its c/c-<channel id> name.
Write one parser
Rumble, TikTok, Instagram and 3 more platforms answer in these fields, so the code that reads one reads them all.
platformstring- Platform ID (tiktok, instagram, …).
idstring- Platform-native account ID (equals profile.id).
urlstring- Canonical profile URL (equals profile.url).
profileobject- The account, as its profile endpoint returns it; its metrics.follower_count divides every engagement_rate.
postsobject[]- The sampled recent posts in the profile's order, each with its own figures. [] when none; [] and in unknown_fields when unreadable (a private account, a failed posts request).
metricsobject- Figures over the counted posts (by the account, not pinned); each null when no counted post has its inputs.
oldest_post_atstring- Publish time of the oldest counted post, RFC 3339 UTC: where the sample starts.
newest_post_atstring- Publish time of the newest counted post, RFC 3339 UTC: when the account last posted.
Live data from 33 platforms.
What teams build with the Rumble Engagement API.
Vet creators before a sponsorship
Compare engagement across a shortlist
Track a channel's posting cadence
Spot a creator's outlier videos
Good to know before you build.
- The figures cover the account's latest uploads on one tab, the first page of the Rumble Channel Videos API: its Videos tab by default, or tab=shorts or tab=live (its Livestreams tab, where many Rumble shows are; a stream on air or scheduled is in the sample with its counts so far). The profile and each video are exactly what the Rumble Channel API and the Rumble Channel Videos API return.
- Engagement rate counts likes plus comments, per follower and per view, so it means the same on every platform. Reposts have their own average, and Rumble's dislikes are on each video (platform_specific.rumble.dislike_count), not in the rate.
- profile.metrics.follower_count is exact, read from the account's own videos in the sample, because Rumble's profile header cuts it to three significant figures. When the sample has none of the account's videos it is the header's count, listed in approximate_fields with every per-follower rate. View, like, comment and repost counts are exact.
- A user's Videos tab (user/<name>) also lists the uploads of the channels it owns: those are in posts with is_counted false, since their followers are the channel's, and the figures cover the user's own uploads.
- When the profile's About tab can't be read, the profile comes from the account's home tab (no description, join date, or video and view counts, which a partial_data warning names) and the figures are the same. An account without uploads returns its profile with an empty sample.
- Names that are no channel or user return not_found.
1 credit per request. Failed requests are free.
Buy credits once and spend them on any endpoint, on any platform.
| Source | Price per successful request | Per 1,000 requests |
|---|---|---|
Public page page | 1 credit | $0.75–$1.97 |
- Cache hits are free.
- Credits from packs and top-ups never expire.
- A monthly plan's credits are spent first, and what is left of them ends at each renewal.
- Prices exclude tax: sales tax is added at checkout where it applies.
- Outside the US, plans and packs are sold to businesses: checkout asks for your VAT, GST or other business tax ID.
Questions about the Rumble Engagement API.
More in the API reference.
How is the engagement rate calculated?
How much does the Rumble Engagement API cost?
Try it on an account you know.
Paste its handle or link in the playground, or copy the request into your code.
- No credit card
- Failed requests are free
- Works on all 218 endpoints