Build
ONCHAIN STORAGE
Irys in the Browser

Irys in The Browser

The Irys SDK reduces dependency bloat by providing dedicated packages for each token. Your install statements, import and connection code will differ depending on the token used for payment and the provider used.

Choose the code for your provider:

🚀

If you're using Irys with React, follow these extra setup steps. If you're using Irys with Vite, follow these steps.

EVM Chains

When connecting from an EVM chain, your connection code will differ based on the token you're using. The examples below use Ethereum and the WebEthereum class. To change tokens, use one from the following list.

TokenClass Name
PolygonWebMatic
Binance CoinWebBNB
Avalanche C-ChainWebAvalanche
Base EthereumWebBaseEth
USDC (on Ethereum)WebUSDCEth
ArbitrumWebArbitrum
ChainlinkWebChainlink
USDC (on Polygon)WebUSDCPolygon
BerachainWebBera
Scroll EthereumWebScrollEth
Linea EthereumWebLineaEth
IoTeXWebIotex
EthereumWebEthereum

Ethers v5

Installing:

npm install \
    @irys/web-upload \
    @irys/web-upload-ethereum \
    ethers@5

Importing & Configuring:

import { WebUploader } from "@irys/web-upload";
import { WebEthereum } from "@irys/web-upload-ethereum";
 
const getIrysUploader = async () => {
  const provider = new ethers.providers.Web3Provider(window.ethereum);
  const irysUploader = await WebUploader(WebEthereum).withProvider(provider);
 
  return irysUploader;
};

Ethers v6

Installing:

npm install \
    @irys/web-upload \
    @irys/web-upload-ethereum \
    @irys/web-upload-ethereum-ethers-v6 \
    ethers@6

Importing & Configuring:

import { WebUploader } from "@irys/web-upload";
import { WebEthereum } from "@irys/web-upload-ethereum";
import { EthersV6Adapter } from "@irys/web-upload-ethereum-ethers-v6";
import { ethers } from "ethers";
 
const getIrysUploader = async () => {
  const provider = new ethers.BrowserProvider(window.ethereum);
  const irysUploader = await WebUploader(WebEthereum).withAdapter(EthersV6Adapter(provider));
 
  return irysUploader;
};

Viem v2

Installing:

npm install \
    @irys/web-upload \
    @irys/web-upload-ethereum \
    @irys/web-upload-ethereum-viem-v2 \
    viem

Importing & Configuring:

import { WebUploader } from "@irys/web-upload";
import { WebEthereum } from "@irys/web-upload-ethereum";
import { ViemV2Adapter } from "@irys/web-upload-ethereum-viem-v2";
 
const getIrysUploader = async () => {
  const [account] = await window.ethereum.request({ method: "eth_requestAccounts",});
 
  const provider = createWalletClient({
    account,
    chain: sepolia,
    transport: custom(window.ethereum),
  });
 
  const publicClient = createPublicClient({
    chain: sepolia,
    transport: custom(window.ethereum),
  });
 
  const irysUploader = await WebUploader(WebEthereum).withAdapter(ViemV2Adapter(provider, { publicClient }));
 
  return irysUploader;
};

Solana

Installing:

npm install \
    @irys/web-upload \
    @irys/web-upload-solana
    @solana/wallet-adapter-base \
    @solana/wallet-adapter-react \
    @solana/wallet-adapter-react-ui \
    @solana/wallet-adapter-wallets \
    @solana/web3.js

Importing & Configuring:

The Solana library uses the React provider pattern. Start by setting up a top-level file named ClientProviders.tsx that wraps all your child components.

app/components/ClientProviders.js
"use client";
 
import { ReactNode, useMemo } from "react";
import { ConnectionProvider, WalletProvider } from "@solana/wallet-adapter-react";
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import { UnsafeBurnerWalletAdapter } from "@solana/wallet-adapter-wallets";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { clusterApiUrl } from "@solana/web3.js";
 
require("@solana/wallet-adapter-react-ui/styles.css");
 
export default function ClientProviders({ children }: { children: ReactNode }) {
 const network = WalletAdapterNetwork.Devnet;
 
 const endpoint = useMemo(() => clusterApiUrl(network), [network]);
 const wallets = useMemo(
   () => [new UnsafeBurnerWalletAdapter()],
   [network]
 );
 
 return (
   <ConnectionProvider endpoint={endpoint}>
     <WalletProvider wallets={wallets} autoConnect>
       <WalletModalProvider>
         {children}
       </WalletModalProvider>
     </WalletProvider>
   </ConnectionProvider>
 );
}

Then load this component via layout.tsx:

layout.tsx
import type { Metadata } from "next";
import ClientProviders from "@/app/components/ClientProviders";
import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"] });
 
export default function RootLayout({
 children,
}: Readonly<{
 children: React.ReactNode;
}>) {
 return (
   <html lang="en">
     <body className={inter.className}>
       <ClientProviders>
         {children}
       </ClientProviders>
     </body>
   </html>
 );
}

Solana's wallet-adapter library (opens in a new tab) make it easy to manage wallet connections. Create a component using this library to connect to a Solana wallet:

app/components/ConnectSolana.tsx
 
"use client";
 
import React, { useEffect, useState } from "react";
import { WalletMultiButton, WalletDisconnectButton } from "@solana/wallet-adapter-react-ui";
 
import "@solana/wallet-adapter-react-ui/styles.css";
 
const ConnectSolana: React.FC = () => {
  const [isClient, setIsClient] = useState(false);
 
  // Prevent hydration errors by ensuring this runs only on the client side
  useEffect(() => {
    setIsClient(true);
  }, []);
 
  if (!isClient) {
    return null;
  }
 
  return (
    <div className="border-2 border-primary rounded-2xl p-4 w-full max-w-md">
      {/* Solana wallet connect button */}
      <div className="mr-5">
        <WalletMultiButton />
      </div>
      {/* Solana wallet disconnect button */}
      <div className="ml-5">
        <WalletDisconnectButton />
      </div>
    </div>
  );
};
 
export default ConnectSolana;

Then create a component called ConnectIrys.tsx that connects to an Irys bundler.

app/components/ConnectIrys.tsx
 
"use client";
 
import { useState } from "react";
import { useWallet } from "@solana/wallet-adapter-react";
import { WebUploader } from "@irys/web-upload";
import { WebSolana } from "@irys/web-upload-solana";
  
const getIrysUploader = async (wallet: any) => {
 try {
   const irysUploader = await WebUploader(WebSolana).withProvider(wallet);
    
   return irysUploader; 
 } catch (error) {
   console.error("Error connecting to Irys:", error);
   throw new Error("Error connecting to Irys");
 }
};
 
const ConnectIrys = (): JSX.Element => {
 const wallet = useWallet();
 const [isConnected, setIsConnected] = useState<boolean>(false);
 
 const connectToIrys = async () => {
   if (!wallet) {
     console.log("Wallet not connected");
     return;
   }
 
   try {
     const irysUploader = await getIrysUploader(wallet);
     console.log(`Connected to Irys from ${irysUploader.address}`);
     setIsConnected(true);
   } catch (error) {
     console.log("Error connecting to Irys");
   }
 };
 
 return (
   <div>
     <button onClick={connectToIrys}>
       {isConnected ? "Connected to Irys" : "Connect Irys"}
     </button>
   </div>
 );
};
 
export default ConnectIrys;

And load them all through your page.tsx file:

page.tsx
import Image from "next/image";
import ConnectSolana from "./components/ConnectSolana";
import ConnectIrys from "./components/ConnectIrys";
 
export default function Home() {
  return (
    <main className="flex min-h-screen flex-col justify-around items-center p-24 bg-black">
      <ConnectSolana />
      <ConnectIrys />
    </main>
  );
}

Aptos

Start by scaffolding a blank Aptos project using npx create-aptos-dapp (opens in a new tab).

Next, install the following packages needed by Irys:

npm install \
    @irys/web-upload \
    @irys/web-upload-aptos \
    axios

Replace your App.tsx file with the following:

import React, { useState } from "react";
import { useWallet } from "@aptos-labs/wallet-adapter-react";
import { WebUploader } from "@irys/web-upload";
import { WebAptos } from "@irys/web-upload-aptos";
 
// Radix UI Components
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Header } from "@/components/Header";
 
function App() {
  const { connected } = useWallet();
  const wallet = useWallet();
  const [irysStatus, setIrysStatus] = useState("Not connected");
 
  const connectIrys = async () => {
    console.log("connect irys called");
    console.log({wallet})
    try {
      const irysUploader = await WebUploader(WebAptos).withProvider(wallet);
      console.log({irysUploader})
 
      setIrysStatus(`Connected to Irys: ${irysUploader.address}`);
    } catch (error) {
      console.error("Error connecting to Irys:", error);
      setIrysStatus("Error connecting to Irys");
    }
  };
 
  return (
    <>
      <Header />
      <div className="flex items-center justify-center flex-col">
        <Card className="mt-6">
          <CardHeader>
            {connected ? (
              <CardTitle>
                <button onClick={connectIrys}>
                  {irysStatus === "Not connected" ? "Connect Irys" : irysStatus}
                </button>
              </CardTitle>
            ) : (
              <CardTitle>To get started, connect a wallet</CardTitle>
            )}
          </CardHeader>
        </Card>
      </div>
    </>
  );
}
 
export default App;
 

The npx create-aptos-dapp CLI uses React + Vite. Vite does not automatically polyfill Node.js core modules like crypto, stream, os, or path. To fix compatibility issues, install the necessary polyfill packages:

npm install --save-dev \
    crypto-browserify \
    stream-browserify \
    os-browserify \
    path-browserify \
    vite-plugin-node-polyfills

Modify your vite.config.js to use vite-plugin-node-polyfills to handle the polyfills required for Node.js core modules:

import path from "path";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { nodePolyfills } from "vite-plugin-node-polyfills";
 
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react(),
    nodePolyfills({
      // Enable polyfills for specific globals and modules
      globals: {
        Buffer: true,
        global: true,
        process: true,
      },
      protocolImports: true, // Polyfill node: protocol imports
    }),
  ],
  resolve: {
    alias: {
      // Polyfill Node.js core modules
      crypto: "crypto-browserify",
      stream: "stream-browserify",
      os: "os-browserify/browser",
      path: "path-browserify",
      "@": path.resolve(__dirname, "./frontend"), 
    },
  },
  build: {
    outDir: "dist", // Output directory
  },
  server: {
    open: true, 
  },
});

After making these changes, restart your development server:

npm run dev