Title: Voffload for Cloudflare Stream
Author: Gerald Drißner
Published: <strong>June 15, 2026</strong>
Last modified: June 15, 2026

---

Search plugins

![](https://ps.w.org/voffload-cloudflare-stream/assets/banner-772x250.png?rev=3573209)

![](https://ps.w.org/voffload-cloudflare-stream/assets/icon-256x256.png?rev=3573209)

# Voffload for Cloudflare Stream

 By [Gerald Drißner](https://profiles.wordpress.org/geralddrissner/)

[Download](https://downloads.wordpress.org/plugin/voffload-cloudflare-stream.1.0.0.zip)

 * [Details](https://wordpress.org/plugins/voffload-cloudflare-stream/#description)
 * [Reviews](https://wordpress.org/plugins/voffload-cloudflare-stream/#reviews)
 *  [Installation](https://wordpress.org/plugins/voffload-cloudflare-stream/#installation)
 * [Development](https://wordpress.org/plugins/voffload-cloudflare-stream/#developers)

 [Support](https://wordpress.org/support/plugin/voffload-cloudflare-stream/)

## Description

**Voffload for Cloudflare Stream** moves the heavy lifting of video hosting and 
playback off your own server and onto Cloudflare Stream. You pick existing video
attachments in your WordPress Media Library, the plugin uploads them to Cloudflare
Stream, and your visitors then watch them through Cloudflare’s adaptive‑bitrate 
player instead of downloading large files from your origin.

This is useful if self‑hosted videos are slowing your site down, eating bandwidth,
or stressing your host. Cloudflare Stream handles transcoding, multiple quality 
levels, and global delivery for you.

_This plugin is an independent project. It is not affiliated with, endorsed by, 
or sponsored by Cloudflare, Inc. “Cloudflare” and “Cloudflare Stream” are trademarks
of Cloudflare, Inc., used here only to describe compatibility._

#### What it does

 * Lists the video attachments already in your Media Library and shows their Cloudflare
   Stream status (Not uploaded / Processing / Ready / Error).
 * Uploads selected videos to Cloudflare Stream. It first asks Cloudflare to fetch
   the public file URL (“URL copy”). If Cloudflare cannot reach that URL (for example
   because of hotlink protection, a firewall rule, or Automatic Platform Optimization),
   it automatically falls back to a direct upload from your server for files under
   200 MB.
 * Stores each video’s Cloudflare Stream UID and processing status on the attachment.
 * Can non-destructively sync existing Cloudflare Stream videos back to matching
   WordPress video attachments when metadata or a unique exact title/filename match
   identifies the local attachment.
 * Can delete selected Cloudflare Stream videos from the plugin dashboard, individually
   or in bulk, while keeping the original WordPress media attachments.
 * Tracks “processing” videos with a background check (WP‑Cron) that runs every 
   10 minutes — but only while at least one video is still processing. When everything
   is ready, the background check stops on its own, so the plugin does not make 
   unnecessary calls.
 * Automatically replaces your local video output on the frontend with the Cloudflare
   Stream player once the matching Stream video is ready (this is optional and can
   be turned off — see “Automatic replacement” below).
 * Provides a shortcode for manual placement of the player (see the “Shortcode” 
   section below for the exact tag and options).
 * Includes a non‑destructive **Connection test** that checks your token, account
   access, and playback settings without uploading anything.
 * Uses a structured dashboard with setup status, workflow descriptions, action 
   guidance, and a small version/copyright/license footer.
 * Never deletes your local video files. Deleting a Stream copy from Cloudflare 
   only clears the plugin’s local Stream metadata; removing local files is intentionally
   left to you.

#### Do I need a paid Cloudflare account?

You need a Cloudflare account and an active **Cloudflare Stream** subscription. 
A few clarifications, because this is a common point of confusion:

 * Cloudflare Stream is a separate, usage‑based product. As of 2026 it is billed
   at roughly **$5 per 1,000 minutes of video stored** per month and **$1 per 1,000
   minutes delivered**. Encoding and ingest are free, and there are no per‑GB egress
   fees.
 * You do **not** need a Cloudflare Pro plan specifically, and Stream does **not**
   require the Workers Paid plan. A **free Cloudflare account works**, as long as
   you have added a Stream subscription to it.
 * If you are on a **Pro or Business** plan, Cloudflare includes a small monthly
   allowance (around 100 minutes of storage and 10,000 minutes of delivery) on top.

Always confirm current pricing on Cloudflare’s own pricing page, as it can change.

### Dashboard guide

The plugin dashboard is available under **Media  Cloudflare Stream**.

 * The top overview explains the three-step workflow: configure Cloudflare, upload
   or reconnect videos, then serve and maintain the Stream copies.
 * The setup status pills show whether the Account ID, API token, and Customer Code
   are present before you run actions that need them.
 * The **Video Library** table lists WordPress video attachments and shows their
   local file link, Stream status, Stream UID, and shortcode.
 * **Upload selected** creates a Cloudflare Stream copy for selected local WordPress
   videos. The WordPress attachment remains in the Media Library.
 * **Refresh selected status** reads the current processing state from Cloudflare.
   If no local UID is saved, the plugin first attempts a safe reconnect.
 * **Reconnect selected from Cloudflare** finds existing Stream videos for selected
   local attachments by stored metadata first and then by exact unique title/filename
   matches.
 * **Delete from Cloudflare** deletes the remote Stream asset after confirmation
   and clears only local Stream metadata. It does not delete the WordPress attachment.
 * The manual UID fallback is for rare cases where automatic matching is unsafe 
   because Cloudflare metadata is missing or multiple possible matches exist.

### Compatibility

 * Requires WordPress 6.5 or newer.
 * Tested up to WordPress 7.0.
 * Requires PHP 8.1 or newer. PHP 8.3 or newer is recommended for current WordPress
   installations.
 * Tested with modern PHP 8.x environments, including PHP 8.5.

### Getting your Cloudflare details

You need three pieces of information from your Cloudflare account.

**1. Account ID**
 Log in to the Cloudflare dashboard at https://dash.cloudflare.
com/ and open the **Stream** product (or any account page). Your Account ID is shown
in the URL and on the account/overview pages. It is a 32‑character hexadecimal string.

**2. API Token (with Stream permission)**
 Create a scoped token so the plugin can
upload and check status. Do **not** use the Global API Key.

 1. In the Cloudflare dashboard, go to **Manage Account  API Tokens** or **My Profile
    API Tokens** and choose **Create Token  Create Custom Token**. Direct link: https://
    dash.cloudflare.com/profile/api-tokens
 2. Under **Permissions**, add **Account  Stream  Edit**. Some Cloudflare screens use
    the newer label **Account  Stream  Write**; that is the equivalent write permission.
    Uploads, status updates, sync/reconnect, and remote deletion require Edit/Write.
    Read-only tokens can verify access but cannot upload or delete videos.
 3. Under **Account Resources**, scope the token to the specific Cloudflare account
    that owns the Stream library.
 4. Do not add unnecessary permissions. This plugin does **not** need DNS, Zone, Workers,
    Cache Purge, or Global API Key permissions.
 5. (Recommended) Set an expiration and, if your server has a static IP, restrict the
    token to that IP.
 6. Click **Continue to summary  Create Token**. **Copy the token immediately** — Cloudflare
    shows it only once and you cannot retrieve it later.

For better security you can define the token in your `wp-config.php` instead of 
saving it in the database:

    ```
    define( 'VOFFLOADCFS_API_TOKEN', 'xxx' );
    ```

When this constant is set, the plugin uses it and never stores the token in the 
WordPress database (so it stays out of database backups).

**3. Customer Code**
 This is the code in your Stream playback URLs, of the form`
customer-CODE.cloudflarestream.com`. The plugin needs it to build the official Cloudflare
Stream iframe URL. To find it, open **Cloudflare Dashboard  Stream  Videos**, open
any uploaded video, and copy the embed/iframe code. The iframe `src` contains `customer-
CODE.cloudflarestream.com`. You may paste the bare code, the full customer subdomain,
the iframe URL, or the full iframe snippet; the plugin extracts and stores only 
the code.

### Automatic replacement (serve from Cloudflare Stream when available)

In **Media  Cloudflare Stream  Settings** you control when ready videos are automatically
served from Cloudflare instead of from your server. There are independent checkboxes
so you can enable exactly what you want:

 * **Automatically replace Gutenberg video blocks** — replaces the core/video block
   on the frontend when the linked attachment has a Stream UID.
 * **Automatically replace WordPress [video] shortcodes** — replaces the built‑in`[
   video]` shortcode output.
 * **Automatically replace local video HTML and video‑file links** — also catches
   classic‑editor `<video>` tags, video blocks that have no attachment ID, and direct
   links to local video files.

Automatic replacement happens only for videos that already have a saved Cloudflare
Stream UID and are marked ready. While Cloudflare is still processing a video, the
local WordPress video output remains in place. If you turn every automatic option
off, nothing on your frontend changes until you place a shortcode yourself.

### Shortcode

Use the shortcode to place a Cloudflare Stream player manually, for example inside
a post, page, or widget.

By WordPress attachment ID (the ID shown in the Media  Cloudflare Stream table):

    ```
    [voffloadcfs_video id="123"]
    ```

By Cloudflare Stream UID directly:

    ```
    [voffloadcfs_video uid="VIDEO_UID"]
    ```

Optional attributes:

 * `title` — accessible title for the player iframe.
 * `aspect` — aspect ratio as `width/height` (default `16/9`). Example: `aspect="
   4/3"`.

Example with options:

    ```
    [voffloadcfs_video id="123" title="My talk" aspect="16/9"]
    ```

The shortcode requires the **Customer Code** setting to be filled in, because that
is what builds the official Cloudflare Stream iframe URL. If a logged‑in editor 
views a shortcode that cannot render (missing UID, wrong ID, missing Customer Code),
the plugin shows a short admin‑only notice explaining why; normal visitors simply
see nothing.

### External services

This plugin connects to **Cloudflare Stream**, a third‑party service operated by
Cloudflare, Inc., because that is the service it exists to integrate with.

What is sent, and when:

 * **When you upload a video:** the plugin sends the video (or the public URL of
   the video so Cloudflare can fetch it), the attachment title, the attachment ID,
   and your site URL to the Cloudflare API. This happens only when you choose to
   upload a video.
 * **When you check status, run the connection test, reconnect selected videos, 
   or sync existing Stream videos:** the plugin sends your Account ID and API token(
   as an authorization header) to the Cloudflare API to read video status, verify
   the token, list Stream video metadata, search Stream videos by name for a selected
   local attachment, or verify a manually entered Stream UID. The connection test,
   reconnect, and sync do not upload any video.
 * **When you delete a Stream video from the plugin dashboard:** the plugin sends
   your Account ID, API token, and the selected Cloudflare Stream video UID to the
   Cloudflare API. Cloudflare deletes the remote Stream video and its copies. The
   original WordPress media attachment is not deleted.
 * **On the frontend:** when a video is served from Stream, the visitor’s browser
   loads the Cloudflare Stream player iframe from `customer-CODE.cloudflarestream.
   com`, so the visitor’s browser communicates directly with Cloudflare.

Cloudflare API endpoint: https://api.cloudflare.com/
 Cloudflare terms of service:
https://www.cloudflare.com/terms/ Cloudflare privacy policy: https://www.cloudflare.
com/privacypolicy/

No data is sent anywhere else, and the plugin does not send analytics about your
site to the plugin author.

## Installation

 1. In your WordPress admin, go to **Plugins  Add New  Upload Plugin** and upload the
    plugin ZIP, then click **Activate**. (Or install it directly from the WordPress.
    org plugin directory.)
 2. Go to **Media  Cloudflare Stream**.
 3. Enter your **Account ID**, **API Token**, and **Customer Code** (see “Getting your
    Cloudflare details” below).
 4. Click **Test Cloudflare connection** to confirm everything is configured correctly.
 5. Select one or more videos and click **Upload selected**.
 6. Wait for status to reach **Ready** (refresh manually, or let the background check
    update it), then your videos are served from Cloudflare Stream.

If you already uploaded videos with an earlier unpublished build, use **Sync existing
Cloudflare Stream videos** or select affected rows and click **Reconnect selected
from Cloudflare**. As a final fallback, paste a Stream UID and attach it to one 
selected WordPress video. The sync lists videos in your Cloudflare Stream account
and imports only those that still match an existing WordPress video attachment for
the current site, using stored metadata first and then exact unique title/filename
matches. It does not delete, upload, or overwrite videos.

## FAQ

### Does this delete my original video files?

No. The plugin never deletes local files. When a Stream video is ready, the matching
local video output on the frontend is replaced by the Cloudflare Stream player (
if you leave automatic replacement enabled), but the original files stay on your
server until you remove them yourself. If you use **Delete from Cloudflare**, only
the remote Cloudflare Stream copy is deleted and the local Stream metadata is cleared.

### What happens to my Cloudflare videos if I uninstall the plugin?

Uninstalling removes the plugin’s WordPress settings and the local Stream metadata
it stored on your attachments. It does **not** delete any videos from Cloudflare.
To remove videos from Cloudflare before uninstalling, use **Delete from Cloudflare**
in the plugin dashboard or remove them in the Cloudflare Stream dashboard/API.

### Why did an upload fail with a “not reachable” or copy error?

Cloudflare’s “URL copy” needs to fetch your public media URL. If hotlink protection,
a firewall/WAF rule, Cloudflare Automatic Platform Optimization, or login‑protected
media blocks that fetch, the copy fails. For files under 200 MB the plugin then 
uploads directly from your server automatically. For files 200 MB or larger, either
make the media URL publicly reachable so URL copy can be used, or upload that file
to Cloudflare with a tus client (the resumable protocol used for large uploads).

### Does it work with caching plugins like WP Rocket and with Cloudflare APO?

Yes. The frontend output is a standard iframe, so it caches well. If you use Automatic
Platform Optimization, direct uploads from the server are used as the fallback when
Cloudflare cannot fetch your media URL.

### Do I need to keep the browser open while videos process?

No. After upload, Cloudflare processes the video on its side. The plugin checks 
status in the background every 10 minutes while videos are still processing, and
stops checking once they are all ready. You can also refresh status manually at 
any time.

### Can I store the API token outside the database?

Yes. Add `define( 'VOFFLOADCFS_API_TOKEN', 'xxx' );` to `wp-config.php` and the 
plugin will use that and never write the token to the database.

### Can I reconnect videos that already exist in Cloudflare Stream?

Yes, if those videos can be matched safely. Use **Sync existing Cloudflare Stream
videos** in Media  Cloudflare Stream, or select rows and click **Reconnect selected
from Cloudflare**. As a final fallback, paste a Stream UID and attach it to one 
selected WordPress video. The plugin first uses the WordPress attachment ID stored
in Stream metadata, then falls back to exact unique title/filename matches. Ambiguous
matches are skipped to avoid linking the wrong video.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“Voffload for Cloudflare Stream” is open source software. The following people have
contributed to this plugin.

Contributors

 *   [ Gerald Drißner ](https://profiles.wordpress.org/geralddrissner/)

[Translate “Voffload for Cloudflare Stream” into your language.](https://translate.wordpress.org/projects/wp-plugins/voffload-cloudflare-stream)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/voffload-cloudflare-stream/),
check out the [SVN repository](https://plugins.svn.wordpress.org/voffload-cloudflare-stream/),
or subscribe to the [development log](https://plugins.trac.wordpress.org/log/voffload-cloudflare-stream/)
by [RSS](https://plugins.trac.wordpress.org/log/voffload-cloudflare-stream/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.0.0

 * First public release prepared for the WordPress.org directory.
 * Renamed to “Voffload for Cloudflare Stream” and updated the WordPress.org slug/
   text domain accordingly.
 * Removed the explicit translation loader because WordPress.org loads plugin translations
   automatically on supported WordPress versions.
 * Added uninstall cleanup that removes plugin options, transients, and local Stream
   metadata (Cloudflare videos are never touched).
 * Added a “Settings” link on the Plugins screen.
 * Hardened admin request handling with wp_unslash before sanitizing all input.
 * Documented external service usage (Cloudflare Stream) and account/pricing requirements.
 * Set the WordPress compatibility to 7.0 and the minimum PHP version to 8.1 for
   the public release.
 * Restricted Cloudflare Stream management to administrators by default, because
   uploads can incur Cloudflare usage costs.
 * Made the Customer Code field accept a full iframe/embed snippet and extract the
   code automatically.
 * Kept local WordPress video output in place until the Cloudflare Stream video 
   is marked ready.
 * Carries forward the 0.2.x functionality: URL-copy with direct-upload fallback
   under 200 MB, self-managing status cron, connection test, Cloudflare-to-WordPress
   metadata sync/reconnect, remote Stream deletion, polished dashboard help/styling,
   collapsible setup help, shortcode playback, and automatic frontend replacement
   for blocks, [video] shortcodes, local HTML, and local video-file links.

## Meta

 *  Version **1.0.0**
 *  Last updated **14 hours ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.5 or higher **
 *  Tested up to **7.0**
 *  PHP version ** 8.1 or higher **
 * Tags
 * [media offload](https://wordpress.org/plugins/tags/media-offload/)[streaming](https://wordpress.org/plugins/tags/streaming/)
   [video](https://wordpress.org/plugins/tags/video/)[video hosting](https://wordpress.org/plugins/tags/video-hosting/)
   [video player](https://wordpress.org/plugins/tags/video-player/)
 *  [Advanced View](https://wordpress.org/plugins/voffload-cloudflare-stream/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/voffload-cloudflare-stream/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/voffload-cloudflare-stream/reviews/)

## Contributors

 *   [ Gerald Drißner ](https://profiles.wordpress.org/geralddrissner/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/voffload-cloudflare-stream/)