A Multimedia Experience
An overview of integrating images, videos, and other media into BSV applications. Explains how UHRP (BRC-26) and overlay networks link off-chain hosting to on-chain file references for immutable, censorship-resistant content, with options for monetization and access control.
UHRP (the Universal Hash Resolution Protocol) provides a hash-based reference to files so that multiple hosts can serve the same content, creating a more resilient, efficient, and verifiable storage and delivery model for multimedia and other data.
Why UHRP?
-
Self-Authenticating Content
Each UHRP URL is derived from the file’s SHA-256 hash. When someone downloads content by its UHRP URL, they can verify the bytes match that hash, ensuring data integrity without needing external trust in the host. -
Resilient & Distributed
Multiple storage providers can offer the same file, increasing availability and bandwidth. If one go offline, others can still serve the same content. -
Lower On-Chain Costs
You do not need to store large files on-chain. Instead, you store only an advertisement of availability (a small “token” UTXO) while the file itself stays on standard HTTP storage. -
Easy to Host & Access
You can upload your data to any UHRP-supporting storage host (e.g., https://nanostore.babbage.systems) or even self-host your own server. As long as the host is recognized by the UHRP network, your file is available through its UHRP URL.
Part 1: Publishing Content with UHRP
Step 1: Install the BSV TS-SDK
Make sure your Node.js project is set up, then install the TS-SDK that provides the StorageUploader:
1npm install @bsv/sdkStep 2: Configure and Use the StorageUploader
Below is a simplified example showing how you might upload a file. The uploader requests an upload location from a storage server, performs the upload, and returns a UHRP URL referencing your file.
1import { StorageUploader, WalletClient } from '@bsv/sdk'
2
3async function uploadFileExample() {
4 // You’ll typically configure this with a wallet and a storageURL:
5 const uploader = new StorageUploader({
6 storageURL: 'https://nanostore.babbage.systems', // or your own host
7 wallet: new WalletClient('auto') // must implement WalletInterface
8 })
9
10 // 1. Prepare your file data as a byte array
11 const fileData = [/* your file bytes */]
12
13 // 2. Publish the file
14 const result = await uploader.publishFile({
15 file: {
16 data: fileData,
17 type: 'image/jpeg' // or other MIME type
18 },
19 retentionPeriod: 60 // host for 60 minutes
20 })
21
22 console.log('Published:', result.published)
23 console.log('UHRP URL:', result.uhrpURL)
24 // Example: "XUUVZqvzYskUvVfBZsrqXsvyoAUojQcJxDr6hTUwEz1vPLdvc64z"
25
26 return result.uhrpURL
27}What’s happening?
- The uploader calls the storage server’s
/uploadroute to ask for an upload destination and instructions. - After uploading the bytes, a UHRP URL is returned, created by hashing the file data (SHA-256) and base58-check encoding it with a UHRP prefix.
By default, the storage host will publish an “advertisement” transaction on-chain (the UTXO “token”), letting others on the UHRP network know this file is available.
Part 2: Downloading and Verifying Content with UHRP
Using the StorageDownloader, you can resolve a UHRP URL to one or more HTTP endpoints and fetch the file. The downloader validates the file’s hash to ensure authenticity.
1import { StorageDownloader } from '@bsv/sdk'
2
3async function downloadFileExample(uhrpUrl: string) {
4 const downloader = new StorageDownloader({ networkPreset: 'mainnet' })
5
6 // Resolve: Finds the underlying HTTP link(s) from UHRP advertisements
7 const linkedUrls = await downloader.resolve(uhrpUrl)
8 console.log('Resolved URLs:', linkedUrls)
9
10 // Optionally: Download the file’s bytes and verify:
11 const result = await downloader.download(uhrpUrl)
12 console.log('Downloaded content length:', result.data.length)
13 console.log('MIME type:', result.mimeType)
14
15 // result.data is a byte array that you can convert into a Blob, store, or process
16}If multiple hosts serve that UHRP URL, the downloader tries each in turn until it successfully verifies content matching the expected hash.
Part 3: Bringing It All Into a React Frontend
The @bsv/uhrp-react library provides ready-made React components for images and media sources. After installing:
1npm install @bsv/uhrp-reactyou can use <Img> and <Source> elements to leverage UHRP URLs seamlessly. The library automatically resolves the hash to a valid HTTP location, verifying the file hash behind the scenes. Here’s a short example:
1import React from 'react'
2import { Img, Source } from '@bsv/uhrp-react'
3
4function MyMediaGallery() {
5 return (
6 <div>
7 <h1>My UHRP-based Media</h1>
8
9 {/* Display an image by its UHRP URL */}
10 <Img
11 src="XUUVZqvzYskUvVfBZsrqXsvyoAUojQcJxDr6hTUwEz1vPLdvc64z"
12 alt="Photo stored on UHRP"
13 style={{ maxWidth: '300px' }}
14 />
15
16 {/* Display video content by its UHRP URL */}
17 <video controls width="400">
18 <Source src="XUTEGfCykZ4E8oJhT98keoPTg2Q28Nq4sJJXLf9CYA5CjV7ZsTCV" />
19 </video>
20 </div>
21 )
22}
23
24export default MyMediaGalleryKey features of these React components:
- Automatic resolution – The components figure out where to load the content from by using a built-in store.
- Fallback/Loading – You may provide a loading or fallback element while the content is resolving.
- Seamless integration – They behave just like standard
<img>or<source>tags after resolution.
Putting It All Together
- Create or obtain a wallet that can sign requests.
- Configure the
StorageUploaderto upload files to your chosen UHRP storage server (e.g., https://nanostore.babbage.systems or your own). - Retrieve the resulting UHRP URL from the upload. This is your permanent, self-authenticating reference to the data.
- Use the
StorageDownloaderin your backend or scripts to verify and fetch data from any host that has advertised it. - In your React front end, install
@bsv/uhrp-reactand simply drop in<Img>or<Source>with your UHRP URLs. The library handles everything else and ensures your content loads from whichever hosting server is available.
This approach provides a scalable and distributed way to store and serve files without locking you into a single hosting provider. Through the UHRP network, you can pay multiple hosts to advertise the data, maximizing redundancy and guaranteeing that content is always served as originally published.
