ytdlp.online

All fixes

On this page

yt-dlp Rumble 403 fix: fall back to player data

Published

Download fix plugin rumble_player.py

If yt-dlp fails to download a Rumble video with Unable to download JSON metadata: HTTP Error 403: Forbidden, you can load the compatibility plugin below. When Rumble's embedJS/u3 JSON endpoint returns 403, the plugin fetches the same video's official embed player page (/embed/), extracts its inline media data, and continues the download.

To skip local plugin setup and manual URL conversion, use our Rumble video downloader, which already includes this fix.

Identify where the 403 occurs

A Rumble download can fail with 403 at three different stages. This plugin addresses the second one:

Error Where the request is blocked What to do
Unable to download webpage: HTTP Error 403 The watch page HTML is blocked (see issue #15089) Use the official oEmbed API to obtain the /embed/ URL, together with --impersonate firefox
Unable to download JSON metadata: HTTP Error 403 The embedJS/u3 metadata endpoint is blocked (see issue #17496) Use this plugin to fall back to inline data from the /embed/ page
Formats are listed, but a fragment or MP4 download returns 403 The CDN rejects the media request Check the proxy and request headers, or try another quality format

Quick fix steps

1. Save the plugin file

Create this directory structure in your working directory and save the full plugin code at the end as rumble_player.py. You do not need to edit yt-dlp's source code.

plugins/
└── rumble/
    └── yt_dlp_plugins/
        └── extractor/
            └── rumble_player.py

2. Get the video's official /embed/ URL

The ID in a Rumble watch page URL, such as v6xxxx, differs from the embed player ID, such as vb0ofn. You cannot construct the embed URL by copying that ID. If you only have a watch page URL, request the real /embed/ URL from Rumble's public oEmbed API:

curl -fsSG --data-urlencode "url=https://rumble.com/your-video.html" "https://rumble.com/api/Media/oembed.json"

Find <iframe src="https://rumble.com/embed/xxxx/..." in the JSON response's html field and copy the https://rumble.com/embed/xxxx/ URL.

If oEmbed returns 403, install curl_cffi and retry with a Firefox fingerprint. Replace the example URL below with the full watch-page URL.

python -m pip install curl_cffi
python -c "import sys; from curl_cffi import requests; r = requests.get('https://rumble.com/api/Media/oembed.json', params=dict(url=sys.argv[1]), impersonate='firefox', timeout=15); r.raise_for_status(); print(r.text)" "https://rumble.com/your-video.html"

If the retry fails, use the online downloader to convert the link automatically.

3. List formats and check the fallback

Run this command from the directory containing plugins, replacing the example URL with your video's /embed/ URL:

yt-dlp --ignore-config --plugin-dirs ./plugins --no-cache-dir -v -F "https://rumble.com/embed/vb0ofn/"

The [RumbleEmbed+PlayerFallback] label confirms that the plugin loaded:

  • If the JSON endpoint returns 403, a Downloading player webpage log entry follows. This indicates that the fallback ran; the resulting format list confirms that parsing succeeded.
  • If the JSON endpoint returns 200 on your connection, yt-dlp follows its normal extraction path without an extra player page request.

4. Download and check decoding

Choose a format ID from the -F output, such as mp4-360p, and download it:

yt-dlp --ignore-config --plugin-dirs ./plugins --no-cache-dir -v --no-playlist -f mp4-360p -o "rumble-test.%(ext)s" "https://rumble.com/embed/vb0ofn/"

The terminal output from our test shows the fallback being used and the download completing:

[RumbleEmbed+PlayerFallback] vb0ofn: Downloading JSON metadata
[RumbleEmbed+PlayerFallback] vb0ofn: Downloading player webpage
[info] vb0ofn: Downloading 1 format(s): mp4-360p
[download] 100% of    7.85MiB in 00:01:20 at 99.48KiB/s

Use ffprobe and ffmpeg to inspect the MP4 container and check its video and audio streams for decoding errors:

ffprobe -v error -show_entries stream=codec_name,codec_type,width,height:format=duration,size -of json "rumble-test.mp4"
ffmpeg -nostdin -v error -xerror -i "rumble-test.mp4" -map 0:v:0 -map "0:a:0?" -f null -

How the player page provides a fallback for the JSON 403

1. Reuse inline data from the same site

By default, RumbleEmbedIE requests JSON metadata from https://rumble.com/embedJS/u3/?request=video&ver=2&v=.... Extraction stops if Cloudflare or the site's request filtering blocks that endpoint with HTTP 403.

The official embed page at https://rumble.com/embed/<video_id>/ also includes a video configuration object in its scripts. It has the same structure, including the ua field containing media URLs for each quality, the title, and the duration. Returning this object from _download_json lets yt-dlp's existing format parser continue without changes.

2. Remove the non-JSON field (loaded: h())

The inline object is not strictly valid JSON. It ends with a runtime function call, loaded: h(), as in this example:

u.f["vb0ofn"] = {"ua": {"mp4": {"360": {"url": "https://..."}}}, "title": "...", loaded: h()};

A JSON parser rejects h(). The plugin uses the transform_source hook in _search_json to remove only the trailing , loaded: xxx() with a regular expression before parsing. It works entirely on text in memory and does not execute the page's JavaScript:

  • Match the requested video: extract only the object whose key matches the current video_id (\b[\w$]+\.f\[\s*["']{video_id}["']\s*\]\s*=), then check that the result is a dictionary with a nonempty ua media field.
  • Limit when the fallback runs: use it only when _download_json catches an HTTPError with status 403. Errors such as 401, 404, 429, and 500, or a page without a valid object, preserve the original exception.
  • Handle watch URLs in the online service: alongside this plugin, our service uses oEmbed to convert watch page URLs to /embed/ URLs. It also defaults to the firefox-135 fingerprint when --impersonate has not been specified.

Full plugin code

Save this code as plugins/rumble/yt_dlp_plugins/extractor/rumble_player.py. It has been verified with Python 3.12+ and yt-dlp 2026.10.10+.

"""Reuse official player media data when Rumble's JSON endpoint is blocked."""

import re

from yt_dlp.extractor.rumble import RumbleEmbedIE as BaseRumbleEmbedIE
from yt_dlp.networking.exceptions import HTTPError
from yt_dlp.utils import ExtractorError


class RumbleEmbedIE(BaseRumbleEmbedIE, plugin_name='PlayerFallback'):
    def _real_extract(self, url):
        self._player_url = url
        return super()._real_extract(url)

    def _download_json(self, url_or_request, video_id, *args, **kwargs):
        try:
            return super()._download_json(url_or_request, video_id, *args, **kwargs)
        except ExtractorError as error:
            if not isinstance(error.cause, HTTPError) or error.cause.status != 403:
                raise
            webpage = self._download_webpage(self._player_url, video_id, note='Downloading player webpage')
            # Parse this video's object and strip the runtime call without executing page scripts.
            data = self._search_json(
                rf'''\b[\w$]+\.f\[\s*["']{re.escape(video_id)}["']\s*\]\s*=\s*''',
                webpage, 'player data', video_id,
                fatal=False,
                transform_source=lambda source: re.sub(r',\s*loaded\s*:\s*[\w$]+\(\s*\)\s*(?=})', '', source))
            if not isinstance(data, dict) or not data.get('ua'):
                raise error
            return data
yt-dlp Tools
View all yt-dlp tools
yt-dlp Help & Docs