The Uploader component is used to upload either single files or groups of files using a single wallet interaction. Uploads are signed and paid for using the user's wallet.


The component uses lazy funding, only funding when the currently funded balance is not sufficient to cover the cost of this upload. Once uploaded, file URLs are stored in the fileUrls state variable.

When uploading a single file, the URL generated is in the form[transaction-id]. When uploading multiple files, they are grouped together and uploaded as a group along with a manifest. The URL generated is in the form[manifest-id]/[file-name].

Image & receipt preview

Once uploaded, the UI updates to include buttons that can be clicked to view the upload and the upload receipt. When previewing uploads, all image types are supported. If your application is working with files other than images, you can remove the upload preview or modify the code to include support for previewing your file type.

If you don't choose to show the receipt, you can retrieve it later using the upload transaction id and the function bundlr.utils.getReceipt().

Customizing the UI

In default mode, the Uploader component shows both the image preview and receipt preview buttons. They can be hidden by passing config parameters to the component.

Default Behavior<Uploder />
Hide the image preview<Uploder showImageView={ false } />
Hide the receipt preview<Uploder showReceiptView={ false } />

If either parameter is left blank, it defaults to true.


The component is designed to be used as-is. Users making significant changes to the UI will need to understand the following.


To download data uploded to Arweave, use a gateway. The Uploader component is currently configured to use the Arweave gateway, to change this modify this variable.

const GATEWAY_BASE = "";


The Uploader component wraps the base File (opens in a new tab) object with a FileWrapper instance used to track the file's progress as it gets uploaded.

interface FileWrapper {
	file: File;
	isUploaded: boolean;
	id: string;
	previewUrl: string;
	loadingReceipt: boolean;

Single file uploads

File uploads happen in the function handleUpload().

For single file uploads, first a Content-Type tag is created to assist the browser in rendering the file, then the file is upload and the FileWrapper object is updated.

// This occurs when exactly one file is selected
try {
	for (const file of files) {
		const tags: Tag[] = [{ name: "Content-Type", value: file.file.type }];
		const uploadedTx = await fundAndUpload(file.file, tags); = uploadedTx;
		file.isUploaded = true;
		file.previewUrl = GATEWAY_BASE + uploadedTx;
} catch (e) {
	console.log("Error on upload: ", e);

Multiple file uploads

When uploading multiple files at once, they are grouped together as a nested bundle and uploaded with a manifest.

try {
	// Remove the File objects from the FileWrapper objects
	const filesToUpload: File[] = => file.file);
	console.log("Multi-file upload");
	const manifestId = await fundAndUploadNestedBundle(filesToUpload);
	// Now that the upload is done, update the FileWrapper objects with the preview URL
	const updatedFiles = => ({
		isUploaded: true,
		previewUrl: GATEWAY_BASE + manifestId + "/" +,
} catch (e) {
	console.log("Error on upload: ", e);

Showing receipts

When showing a receipt, it is first retrieved using bundlr.utils.getReceipt() and then set to the receipt state variable.

The receipt is formatted in the class ReceiptJSONView, which can be modified if you desire custom formatting.

const showReceipt = async (id: string) => {
	try {
		const bundlr = await getBundlr();
		const receipt = await bundlr.utils.getReceipt(id);
		setPreviewURL(""); // Only show one or the other
	} catch (e) {
		console.log("Error fetching receipt: " + e);