Nethereum.Reown.AppKit.Blazor 5.8.0

Prefix Reserved
dotnet add package Nethereum.Reown.AppKit.Blazor --version 5.8.0
                    
NuGet\Install-Package Nethereum.Reown.AppKit.Blazor -Version 5.8.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Nethereum.Reown.AppKit.Blazor" Version="5.8.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nethereum.Reown.AppKit.Blazor" Version="5.8.0" />
                    
Directory.Packages.props
<PackageReference Include="Nethereum.Reown.AppKit.Blazor" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Nethereum.Reown.AppKit.Blazor --version 5.8.0
                    
#r "nuget: Nethereum.Reown.AppKit.Blazor, 5.8.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Nethereum.Reown.AppKit.Blazor@5.8.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Nethereum.Reown.AppKit.Blazor&version=5.8.0
                    
Install as a Cake Addin
#tool nuget:?package=Nethereum.Reown.AppKit.Blazor&version=5.8.0
                    
Install as a Cake Tool

Nethereum.Reown.AppKit.Blazor

Nethereum integration for Reown AppKit (formerly WalletConnect AppKit) in Blazor WebAssembly and Blazor Server applications.

Overview

Nethereum.Reown.AppKit.Blazor wraps the Reown AppKit JavaScript SDK (@reown/appkit-cdn) and exposes it through Nethereum's IEthereumHostProvider abstraction.

What is Reown AppKit?

Reown AppKit (formerly WalletConnect AppKit) provides:

  • Pre-built UI components for wallet connection
  • WalletConnect v2 protocol support (QR code pairing for mobile wallets)
  • EIP-6963 support (browser extension discovery)
  • Wagmi adapter integration

Configuration Options:

  • Network configuration (Ethereum, Optimism, Arbitrum, Base, Polygon, Avalanche, Celo, Ronin)
  • Social login providers (Google, X, Discord, Farcaster, GitHub, Apple, Facebook)
  • On-ramp toggle
  • Token swap toggle
  • Transaction history toggle
  • Theme mode (light/dark) with custom CSS variables
  • Web components (<appkit-button />, <appkit-network-button />)
  • Coinbase preference options

Installation

dotnet add package Nethereum.Reown.AppKit.Blazor

Or via Package Manager Console:

Install-Package Nethereum.Reown.AppKit.Blazor

Dependencies

Package References:

  • Microsoft.Extensions.DependencyInjection.Abstractions 8.0.2
  • Microsoft.Extensions.Options 8.0.2
  • Microsoft.JSInterop 8.0.10

Project References:

  • Nethereum.UI (provides IEthereumHostProvider abstraction)
  • Nethereum.Web3 (Web3 API access)

Target Framework:

  • net8.0

External Dependencies:

Quick Start

1. Get Reown Project ID

Sign up at https://cloud.reown.com/ and create a new project to obtain your Project ID.

2. Configure Services

In Program.cs:

using Nethereum.Reown.AppKit.Blazor;

var builder = WebAssemblyHostBuilder.CreateDefault(args);

var projectId = "YOUR-REOWN-PROJECT-ID";

builder.Services.AddAppKit(new AppKitConfiguration
{
    Networks = NetworkConstants.Networks.All,
    ProjectId = projectId,
    Name = "My Dapp",
    Description = "My decentralized application",
    Url = builder.HostEnvironment.BaseAddress,
    Icons = ["https://my-dapp.com/icon.png"],
    ThemeMode = ThemeModeOptions.light,
    Swaps = true,
    Onramp = true,
    Email = true
});

await builder.Build().RunAsync();

From: consoletests/NethereumReownAppKitBlazor/Program.cs:20

3. Use in Razor Components

@page "/"
@using Nethereum.Reown.AppKit.Blazor
@using Nethereum.UI
@inject IEthereumHostProvider ethereumHostProvider
@inject IAppKit appKit


<appkit-button />
<appkit-network-button />

@if (string.IsNullOrEmpty(Address))
{
    <button @onclick="ConnectWallet">Connect Wallet</button>
}
else
{
    <div>Connected: @Address</div>
    <div>Chain ID: @ChainId</div>
}

@code {
    private string? Address;
    private long ChainId;
    private IWeb3 web3 = default!;

    protected override async Task OnInitializedAsync()
    {
        // Subscribe to account changes
        ethereumHostProvider.SelectedAccountChanged += async (address) =>
        {
            Address = address;
            await InvokeAsync(StateHasChanged);
        };

        // Subscribe to network changes
        ethereumHostProvider.NetworkChanged += async (chainId) =>
        {
            ChainId = chainId;
            await InvokeAsync(StateHasChanged);
        };

        // Get Web3 instance with AppKit integration
        web3 = await ethereumHostProvider.GetWeb3Async();
    }

    private async Task ConnectWallet()
    {
        Address = await ethereumHostProvider.EnableProviderAsync();
    }
}

From: consoletests/NethereumReownAppKitBlazor/Pages/Index.razor:15

Configuration

AppKitConfiguration Properties

public class AppKitConfiguration
{
    // Required
    public required IEnumerable<Network> Networks { get; init; }
    public required string ProjectId { get; init; }
    public required string Name { get; init; }
    public required string Description { get; init; }
    public required string Url { get; init; }
    public required string[] Icons { get; init; }

    // Network
    public Network? DefaultNetwork { get; init; }

    // Theme
    public ThemeModeOptions? ThemeMode { get; set; } // dark, light, or null (system default)
    public ThemeVariables? ThemeVariables { get; init; }

    // Wallet Configuration
    public AllWalletsOptions AllWallets { get; init; } = AllWalletsOptions.SHOW; // SHOW, HIDE, ONLY_MOBILE
    public string[]? FeaturedWalletIds { get; init; }
    public string[]? IncludeWalletIds { get; init; }
    public string[]? ExcludeWalletIds { get; init; }

    // Coinbase
    public CoinbasePreferenceOptions CoinbasePreference { get; set; } = CoinbasePreferenceOptions.all;
    // Options: all, smartWalletOnly, eoaOnly

    // Legal
    public string? TermsConditionsUrl { get; init; }
    public string? PrivacyPolicyUrl { get; init; }
    public bool LegalCheckbox { get; init; } = false;

    // Provider Configuration
    public bool? DisableAppend { get; init; }
    public bool? EnableWallets { get; init; }
    public bool? EnableEIP6963 { get; init; }
    public bool? EnableCoinbase { get; init; }
    public bool? EnableInjected { get; init; }

    // Debug
    public bool Debug { get; init; } = false;

    // Features
    public bool Swaps { get; init; } = true;
    public bool Onramp { get; init; } = true;
    public bool Email { get; init; } = true;
    public bool EmailShowWallets { get; init; } = true;
    public HashSet<SocialOptions>? Socials { get; init; }
    public bool History { get; init; } = true;
    public bool Analytics { get; init; } = true;
}

From: src/Nethereum.Reown.AppKit.Blazor/AppKitConfiguration.cs:37

Social Login Options

public enum SocialOptions
{
    google,
    x,           // Twitter/X
    discord,
    farcaster,
    github,
    apple,
    facebook
}

Default: All 7 social options are enabled by default.

From: src/Nethereum.Reown.AppKit.Blazor/AppKitConfiguration.cs:14

Theme Customization

public struct ThemeVariables
{
    public string W3mFontFamily { get; init; }
    public string W3mAccent { get; init; }
    public string W3mColorMix { get; init; }
    public int W3mColorMixStrength { get; init; }
    public string W3mFontSizeMaster { get; init; }
    public string W3mBorderRadiusMaster { get; init; }
    public int W3mZIndex { get; init; }
}

Example:

builder.Services.AddAppKit(new AppKitConfiguration
{
    // ... other config
    ThemeMode = ThemeModeOptions.dark,
    ThemeVariables = new ThemeVariables
    {
        W3mFontFamily = "Roboto, sans-serif",
        W3mAccent = "#FF6B00",
        W3mColorMix = "#FF6B00",
        W3mColorMixStrength = 20,
        W3mBorderRadiusMaster = "8px",
        W3mZIndex = 9999
    }
});

From: src/Nethereum.Reown.AppKit.Blazor/AppKitConfiguration.cs:87

Network Configuration

Pre-configured Networks

Nethereum.Reown.AppKit.Blazor includes 10 pre-configured networks:

public static class NetworkConstants
{
    public static class Networks
    {
        public static readonly Network Ethereum;       // Chain ID: 1
        public static readonly Network Optimism;       // Chain ID: 10
        public static readonly Network Ronin;          // Chain ID: 2020
        public static readonly Network RoninSaigon;    // Chain ID: 2021 (testnet)
        public static readonly Network Base;           // Chain ID: 8453
        public static readonly Network Arbitrum;       // Chain ID: 42161
        public static readonly Network Celo;           // Chain ID: 42220
        public static readonly Network CeloAlfajores;  // Chain ID: 44787 (testnet)
        public static readonly Network Polygon;        // Chain ID: 137
        public static readonly Network Avalanche;      // Chain ID: 43114

        public static readonly IReadOnlyCollection<Network> All;
    }
}

Usage:

// Use all networks
Networks = NetworkConstants.Networks.All

// Use specific networks
Networks = new[]
{
    NetworkConstants.Networks.Ethereum,
    NetworkConstants.Networks.Optimism,
    NetworkConstants.Networks.Base
}

From: src/Nethereum.Reown.AppKit.Blazor/Network.cs:37

Custom Network Configuration

public class Network
{
    public required long Id { get; init; }
    public required string Name { get; init; }
    public required Currency NativeCurrency { get; init; }
    public BlockExplorers? BlockExplorers { get; init; }
    public required RpcUrls RpcUrls { get; init; }
    public bool Testnet { get; init; }
}

public record Currency(string Name, string Symbol, int Decimals);
public record RpcUrls(RpcUrl Default);
public record RpcUrl(string[] Http, string? WebSocket);
public record BlockExplorers(BlockExplorer Default);
public record BlockExplorer(string Name, string Url);

Example:

var customNetwork = new Network
{
    Id = 11155111,
    Name = "Sepolia",
    NativeCurrency = new Currency("Sepolia Ether", "ETH", 18),
    RpcUrls = new RpcUrls(new RpcUrl(
        ["https://rpc.sepolia.org"],
        "wss://rpc.sepolia.org"
    )),
    BlockExplorers = new BlockExplorers(new BlockExplorer(
        "Etherscan",
        "https://sepolia.etherscan.io"
    )),
    Testnet = true
};

From: src/Nethereum.Reown.AppKit.Blazor/Network.cs:5

UI Components

Built-in Web Components

Reown AppKit provides pre-built web components that can be used directly in Razor templates:


<appkit-button />


<appkit-network-button />

These components are automatically styled based on your theme configuration and handle all wallet connection UI interactions.

From: consoletests/NethereumReownAppKitBlazor/Pages/Index.razor:21

IAppKit Interface

For programmatic control over the AppKit modal:

@inject IAppKit appKit

@code {
    private void OpenModal()
    {
        appKit.Open();    // Open the wallet connection modal
    }

    private void CloseModal()
    {
        appKit.Close();   // Close the modal
    }

    private void DisconnectWallet()
    {
        appKit.Disconnect();  // Disconnect current wallet
    }
}

From: src/Nethereum.Reown.AppKit.Blazor/IAppKit.cs:3

IEthereumHostProvider Integration

AppKit implements IEthereumHostProvider, enabling standard Nethereum integration patterns:

Account and Network Events

@inject IEthereumHostProvider ethereumHostProvider

@code {
    protected override async Task OnInitializedAsync()
    {
        // Subscribe to account changes
        ethereumHostProvider.SelectedAccountChanged += async (address) =>
        {
            Console.WriteLine($"Account changed: {address}");
            await InvokeAsync(StateHasChanged);
        };

        // Subscribe to network changes
        ethereumHostProvider.NetworkChanged += async (chainId) =>
        {
            Console.WriteLine($"Network changed: {chainId}");
            await InvokeAsync(StateHasChanged);
        };

        // Check availability
        bool available = await ethereumHostProvider.CheckProviderAvailabilityAsync();

        // Get current account
        string? account = await ethereumHostProvider.GetProviderSelectedAccountAsync();
    }
}

From: consoletests/NethereumReownAppKitBlazor/Pages/Index.razor:56

Web3 Integration

@code {
    private IWeb3 web3 = default!;

    protected override async Task OnInitializedAsync()
    {
        // Get Web3 instance with AppKit request interception
        web3 = await ethereumHostProvider.GetWeb3Async();

        // All RPC calls requiring wallet interaction are automatically routed through AppKit
        var blockNumber = await web3.Eth.Blocks.GetBlockNumber.SendRequestAsync();
    }
}

From: src/Nethereum.Reown.AppKit.Blazor/AppKitHostProvider.cs:47

Examples

Example 1: Sign Typed Data (EIP-712)

@code {
    private async Task SignTypedDataAsync()
    {
        var typedData = new TypedData<Domain>
        {
            Domain = new Domain
            {
                Name = "Ether Mail",
                Version = "1",
                ChainId = ChainId,
                VerifyingContract = "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC"
            },
            Types = MemberDescriptionFactory.GetTypesMemberDescription(
                typeof(Domain), typeof(Mail), typeof(Person)
            ),
            PrimaryType = nameof(Mail)
        };

        var mail = new Mail
        {
            From = new Person { Name = "Alice", Wallets = ["0x1234..."] },
            To = [new Person { Name = "Bob", Wallets = ["0x5678..."] }],
            Contents = "Hello, Bob!"
        };

        typedData.SetMessage(mail);

        string signature = await web3.Eth.AccountSigning.SignTypedDataV4.SendRequestAsync(
            typedData.ToJson()
        );

        // Verify signature
        string recoveredAddress = new Eip712TypedDataSigner()
            .RecoverFromSignatureV4(typedData, signature);
    }
}

From: consoletests/NethereumReownAppKitBlazor/Pages/Index.razor:76

Example 2: Personal Sign

using Nethereum.Hex.HexTypes;

@code {
    private async Task PersonalSignAsync()
    {
        var message = new HexUTF8String("Hello World");
        string signature = await web3.Eth.AccountSigning.PersonalSign.SendRequestAsync(message);

        Console.WriteLine($"Signature: {signature}");
    }
}

From: consoletests/NethereumReownAppKitBlazor/Pages/Index.razor:149

Example 3: Switch Network

using Nethereum.RPC.HostWallet;
using Nethereum.Hex.HexTypes;

@code {
    private async Task SwitchToEthereumMainnet()
    {
        var response = await web3.Eth.HostWallet.SwitchEthereumChain.SendRequestAsync(
            new SwitchEthereumChainParameter
            {
                ChainId = 1.ToHexBigInteger()
            }
        );
    }
}

From: consoletests/NethereumReownAppKitBlazor/Pages/Index.razor:116

Example 4: Add Custom Network

using Nethereum.RPC.Chain;
using Nethereum.RPC.HostWallet;

@code {
    private async Task AddOptimismNetwork()
    {
        var chainFeature = ChainDefaultFeaturesServicesRepository.GetDefaultChainFeature(
            Nethereum.Signer.Chain.Optimism
        );

        var addParameter = chainFeature.ToAddEthereumChainParameter();

        string? response = await web3.Eth.HostWallet.AddEthereumChain.SendRequestAsync(
            addParameter
        );
    }
}

From: consoletests/NethereumReownAppKitBlazor/Pages/Index.razor:164

Example 5: Get Block Number

@code {
    private async Task GetBlockNumberAsync()
    {
        var blockNumber = await web3.Eth.Blocks.GetBlockNumber.SendRequestAsync();
        Console.WriteLine($"Current block: {blockNumber.Value}");
    }
}

From: consoletests/NethereumReownAppKitBlazor/Pages/Index.razor:135

Architecture

Request Interception

AppKit uses AppKitInterceptor to route Nethereum RPC requests through the Wagmi adapter:

┌─────────────────────────────────────────┐
│  Your Application                       │
│  (Nethereum Web3 API calls)             │
└─────────────────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────┐
│  AppKitInterceptor                      │
│  (Routes requests to Wagmi)             │
└─────────────────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────┐
│  Wagmi Core (via JavaScript Interop)    │
│  - sendTransaction                      │
│  - signMessage                          │
│  - signTypedData                        │
│  - call                                 │
│  - getBalance                           │
│  - estimateGas                          │
└─────────────────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────┐
│  Connected Wallet Provider              │
│  (Browser extension, mobile wallet,     │
│   social login, etc.)                   │
└─────────────────────────────────────────┘

Supported RPC Methods:

  • eth_sendTransactionWagmiCore.sendTransaction
  • eth_signTypedData_v4WagmiCore.signTypedData
  • personal_signWagmiCore.signMessage
  • eth_callWagmiCore.call
  • eth_getBalanceWagmiCore.getBalance
  • eth_estimateGasWagmiCore.estimateGas
  • eth_chainIdWagmiCore.getChainId
  • eth_getTransactionReceiptWagmiCore.getTransactionReceipt

From: src/Nethereum.Reown.AppKit.Blazor/wwwroot/js/index.js:193

JavaScript Interop

The package uses JavaScript interop to communicate with the Reown AppKit CDN:

import { createAppKit, WagmiAdapter, WagmiCore }
  from 'https://cdn.jsdelivr.net/npm/@reown/appkit-cdn@1.4.1/dist/appkit.min.js'

Key JavaScript Functions:

  • InitializeAsync(configJson) - Initialize AppKit with configuration
  • EnableProviderAsync() - Open modal and request wallet connection
  • WatchAccount(callback) - Subscribe to account changes
  • WatchChainId(callback) - Subscribe to network changes
  • GetAccount() - Get current account state
  • SignMessageAsync(message) - Sign personal message
  • SendTransactionAsync(id, method, params) - Execute Wagmi method

From: src/Nethereum.Reown.AppKit.Blazor/wwwroot/js/index.js:1

Blazor Server vs WebAssembly

This package supports both Blazor Server and Blazor WebAssembly:

Blazor WebAssembly:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddAppKit(config);

Blazor Server:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAppKit(config);

The JavaScript interop (IJSRuntime) works in both hosting models.

Advanced Configuration

Disable Email Login

builder.Services.AddAppKit(new AppKitConfiguration
{
    // ... other config
    Email = false,
    Socials = new HashSet<SocialOptions> { SocialOptions.google, SocialOptions.github }
});

Coinbase Smart Wallet Only

builder.Services.AddAppKit(new AppKitConfiguration
{
    // ... other config
    CoinbasePreference = CoinbasePreferenceOptions.smartWalletOnly
});

Hide All Wallets (Social Login Only)

builder.Services.AddAppKit(new AppKitConfiguration
{
    // ... other config
    AllWallets = AllWalletsOptions.HIDE,
    Email = true,
    Socials = new HashSet<SocialOptions>
    {
        SocialOptions.google,
        SocialOptions.discord
    }
});
builder.Services.AddAppKit(new AppKitConfiguration
{
    // ... other config
    FeaturedWalletIds = new[]
    {
        "c57ca95b47569778a828d19178114f4db188b89b763c899ba0be274e97267d96", // MetaMask
        "4622a2b2d6af1c9844944291e5e7351a6aa24cd7b23099efac1b2fd875da31a0"  // Trust Wallet
    }
});

Wallet IDs can be found in the WalletConnect Explorer: https://walletconnect.com/explorer

builder.Services.AddAppKit(new AppKitConfiguration
{
    // ... other config
    TermsConditionsUrl = "https://my-dapp.com/terms",
    PrivacyPolicyUrl = "https://my-dapp.com/privacy",
    LegalCheckbox = true  // Require users to accept T&C before connecting
});

Troubleshooting

AppKit Modal Not Opening

Issue: Calling EnableProviderAsync() doesn't show the modal.

Solution: Ensure JavaScript interop is initialized:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await Task.Delay(100); // Wait for JS initialization
        await ethereumHostProvider.CheckProviderAvailabilityAsync();
    }
}

Account Not Detected After Connection

Issue: SelectedAccount is null after connecting.

Solution: AppKit uses async account detection. Subscribe to SelectedAccountChanged event:

ethereumHostProvider.SelectedAccountChanged += async (address) =>
{
    if (!string.IsNullOrEmpty(address))
    {
        // Account detected
    }
};

RPC Calls Failing with "User Rejected"

Issue: User canceled the wallet transaction prompt.

Solution: Wrap calls in try-catch:

try
{
    var signature = await web3.Eth.AccountSigning.PersonalSign.SendRequestAsync(message);
}
catch (Exception ex)
{
    if (ex.Message.Contains("User rejected"))
    {
        // Handle user rejection
    }
}

Debug Mode

Enable debug logging to troubleshoot JavaScript interop issues:

builder.Services.AddAppKit(new AppKitConfiguration
{
    // ... other config
    Debug = true  // Logs AppKit events to browser console
});
  • Nethereum.UI - IEthereumHostProvider abstraction
  • Nethereum.Web3 - Web3 API for Ethereum interactions
  • Nethereum.Blazor - EIP-6963 multi-wallet support for Blazor
  • Nethereum.Metamask.Blazor - MetaMask-specific integration
  • Nethereum.WalletConnect - Low-level WalletConnect v2 protocol implementation

Additional Resources

License

MIT License - see LICENSE file for details

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.8.0 117 1/6/2026
5.0.0 255 5/28/2025
4.29.0 213 2/10/2025