Skip to main content

Playing Media from Walrus

You can play audio and video stored as Walrus blobs directly in a browser. Point an HTML media element, such as <audio> or <video>, at a Walrus aggregator URL, and the browser streams the blob as it plays. No download step or plugin is required.

Set $AGGREGATOR to an aggregator endpoint from the Network Reference.

Point a media element at an aggregator

A blob read endpoint is an HTTP URL, so you can use it as the src of a <video> or <audio> element:

<video controls src="https://aggregator.walrus-mainnet.walrus.space/v1/blobs/<BLOB_ID>"></video>

The browser fetches the blob from the aggregator and plays it. For the read paths and their exact shapes, see Reading Blobs with the HTTP API.

Set a content type so the browser plays instead of downloads

When you read a blob by its blob ID, the aggregator response does not include a content type from your metadata. The browser infers the type instead. Browsers infer media types well in most cases, but the aggregator deliberately blocks inference of dangerous executable types, such as JavaScript, to protect users.

If a blob URL shows raw bytes or garbled text in the address bar instead of a player, the browser treated the response as generic data rather than a media type.

To make playback reliable, read the blob by object ID and set the content-type attribute when you store it. The aggregator returns recognized attributes, including content-type, as HTTP response headers on the by-object-id read path:

<video controls src="https://aggregator.walrus-mainnet.walrus.space/v1/blobs/by-object-id/<OBJECT_ID>"></video>

For the full list of recognized attributes and how to set them, see Reading by object ID and Managing blobs.

Seek and stream with byte ranges

Aggregators support the HTTP Range header, which is what lets a browser seek within a video without downloading the whole file first. When you send a Range header with a byte range, the aggregator returns 206 Partial Content with just that range:

$ curl -H "Range: bytes=0-999" "$AGGREGATOR/v1/blobs/<BLOB_ID>"

There is also a dedicated endpoint that takes the range as query parameters:

$ curl "$AGGREGATOR/v1/blobs/<BLOB_ID>/byte-range?start=0&length=1024"
info

A byte-range read verifies only the consistency of the bytes it fetches, not the whole blob. This gives you faster partial reads with weaker integrity guarantees than a full read. Use a full read when you need to verify the entire blob.

Cross-origin playback

A plain <video src> or <audio src> element loads media cross-origin without extra configuration. If your application instead fetches blob bytes with JavaScript (for example, fetch followed by URL.createObjectURL, or drawing a frame to a <canvas>), the request is subject to the aggregator's cross-origin resource sharing (CORS) policy, which depends on how that aggregator and any CDN in front of it are deployed. If a cross-origin fetch fails, prefer the direct-src approach, or read through an aggregator you control.

References