Skip to content

wagmi

Wagmi needs a connector that translates its connection lifecycle into EIP-1193 provider calls. Konekt supplies the provider; the connector from konekt-ui/wagmi adapts it to wagmi.

In this setup:

  • wagmi’s viem HTTP transports handle public reads;
  • the Konekt connector handles accounts, signatures, transactions, and chain switching;
  • konekt-ui/wagmi can render the connect, account, and network controls.

This guide works with React 18 or 19, wagmi 2 or 3, and viem 2. The snippets use hook names that exist in both wagmi versions (useAccount, connect, disconnect, switchChain). Wagmi 3 also exports useConnection and mutate as newer aliases.

Terminal window
pnpm add konekt konekt-ui viem wagmi @tanstack/react-query react react-dom

You also need a WalletConnect project ID.

konekt-ui/wagmi exports the connector: konekt(options) for wagmi configuration and abortPairing() for cancelling the current proposal. The konekt core package still has no wagmi dependency; the connector lives in the entry point that already declares wagmi as a peer.

import { konekt } from "konekt-ui/wagmi";

If your app does not use konekt-ui, copy the connector implementation into your application instead — it is one self-contained file.

The connector:

  • creates Provider.init() lazily when wagmi first requests it;
  • configures EVM chains from the wagmi config;
  • maps Konekt account, chain, and disconnect events into wagmi events;
  • exposes display_uri through the connector’s message event;
  • opens the wallet URL from request_sent;
  • aborts a pending proposal through abortPairing().

Register the connector next to injected browser wallets. Save this as src/web3.tsx:

import type { PropsWithChildren } from "react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { WagmiProvider, createConfig, http } from "wagmi";
import { base, mainnet } from "wagmi/chains";
import { injected } from "wagmi/connectors";
import { konekt } from "konekt-ui/wagmi";
const projectId = "YOUR_PROJECT_ID";
export const konektOptions = {
projectId,
metadata: {
name: "My app",
description: "Connect to My app",
url: "https://app.example.com",
icons: ["https://app.example.com/icon.png"],
},
};
export const config = createConfig({
chains: [mainnet, base],
connectors: [
injected(),
konekt(konektOptions),
],
transports: {
[mainnet.id]: http("https://ethereum.example-rpc.com"),
[base.id]: http("https://base.example-rpc.com"),
},
});
declare module "wagmi" {
interface Register {
config: typeof config;
}
}
const queryClient = new QueryClient();
export function Web3Provider({ children }: PropsWithChildren) {
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</WagmiProvider>
);
}

Registering the connector does not open a relay socket. On mount, wagmi asks every connector whether it is already authorized, which makes this connector dynamically import Konekt and call Provider.init(). That restores a saved session, and it connects to the relay only when a saved session exists.

The wagmi transports are intentionally separate from Konekt’s optional EVM read transport. Wagmi sends public reads through its viem clients and sends wallet actions through the active connector.

ConnectButton renders:

  • a connect trigger;
  • installed connectors and WalletConnect Explorer wallets;
  • a WalletConnect pairing QR;
  • connected account and balance details;
  • network switching and disconnect controls.
import { abortPairing, ConnectButton } from "konekt-ui/wagmi";
import "konekt-ui/styles.css";
export function WalletControls() {
return <ConnectButton onDismiss={abortPairing} />;
}

The button reads the WalletConnect project ID from the registered Konekt connector, so there is nothing to configure twice. onDismiss matters because closing the modal should also abort the proposal owned by the connector. The modal itself removes its connector event listener; abortPairing() stops the underlying Konekt connection.

Once connected, Konekt behaves like the app’s other wagmi connectors:

import { formatUnits, parseEther } from "viem";
import {
useAccount,
useBalance,
useDisconnect,
useSendTransaction,
useSwitchChain,
} from "wagmi";
import { base } from "wagmi/chains";
export function AccountActions() {
const account = useAccount();
const balance = useBalance({ address: account.address });
const transaction = useSendTransaction();
const switching = useSwitchChain();
const disconnecting = useDisconnect();
if (!account.isConnected || !account.address) {
return <p>No wallet connected.</p>;
}
return (
<section>
<p>{account.address}</p>
<p>
{balance.data
? `${formatUnits(balance.data.value, balance.data.decimals)} ${balance.data.symbol}`
: "Loading balance…"}
</p>
<button
type="button"
disabled={transaction.isPending}
onClick={() =>
transaction.sendTransaction({
to: "0x000000000000000000000000000000000000dEaD",
value: parseEther("0.001"),
})
}
>
Send transaction
</button>
<button
type="button"
disabled={switching.isPending}
onClick={() => switching.switchChain({ chainId: base.id })}
>
Switch to Base
</button>
<button
type="button"
disabled={disconnecting.isPending}
onClick={() => disconnecting.disconnect()}
>
Disconnect
</button>
</section>
);
}

The connector forwards the wallet actions to Konekt. Reads such as useBalance() continue to use the HTTP transport in the wagmi config.

Use useWagmiPairing() when you want to keep your own connect button while reusing the wallet picker:

import { useState } from "react";
import { WalletModal } from "konekt-ui";
import { abortPairing, useWagmiPairing } from "konekt-ui/wagmi";
export function CustomWalletButton() {
const [open, setOpen] = useState(false);
const pairing = useWagmiPairing();
return (
<>
<button type="button" onClick={() => setOpen(true)}>
Choose a wallet
</button>
<WalletModal
open={open}
pairing={pairing}
onDismiss={abortPairing}
onClose={() => setOpen(false)}
/>
</>
);
}

Static registration in createConfig() is the recommended path, and the one this guide uses. Because the connector imports Konekt lazily inside getProvider(), registration costs one dynamic import during wagmi’s reconnect and no relay socket unless a saved session exists.

That import still happens for a visitor who never connects a wallet. If you need Konekt entirely absent until someone opens the wallet picker, pass getWalletConnect to ConnectButton or useWagmiPairing() and create the connector on demand:

import { useCallback, useRef } from "react";
import type { Connector } from "wagmi";
import { useConfig } from "wagmi";
import { abortPairing, ConnectButton, konekt } from "konekt-ui/wagmi";
import { konektOptions } from "./web3";
export function WalletControls() {
const config = useConfig();
const connector = useRef<Connector>(undefined);
const getWalletConnect = useCallback(async () => {
// `_internal` is wagmi's private API. Registering a connector after
// createConfig() has no public equivalent.
connector.current ??= config._internal.connectors.setup(konekt(konektOptions));
return connector.current;
}, [config]);
return (
<ConnectButton
projectId={konektOptions.projectId}
getWalletConnect={getWalletConnect}
onDismiss={abortPairing}
/>
);
}

The projectId prop is needed only on this path: with no Konekt connector registered until pairing starts, the wallet picker has nowhere else to read the ID from.

This is the trade-off the repository’s example app demonstrates. Weigh it deliberately: config._internal is not part of wagmi’s public API and can change in a minor release. Prefer static registration unless the initial-chunk saving matters for your app, and pin your wagmi version if you adopt this pattern.

To keep the provider and modal out of the initial page chunk in other ways, follow the lazy-loading patterns and measured bundle sizes.

“No WalletConnect connector is registered”

Section titled ““No WalletConnect connector is registered””

Import konekt from konekt-ui/wagmi and add konekt(konektOptions) to createConfig({ connectors }). The connector’s id or type must be "konekt".

Pass onDismiss={abortPairing} to ConnectButton or WalletModal.

Wagmi HTTP transports handle reads without a wallet. Confirm that the Konekt connector is active and that the user approved a session before sending wallet actions.

Add it to the wagmi chains array and provide its HTTP transport. The connector derives its proposed EVM chains from that config.