Client-Side Signing
Build and send transactions in the browser with kit + wallet adapters.
Search across all documentation pages
Build and send transactions in the browser with kit + wallet adapters.
"use client";
import { createSolanaRpc, signTransactionMessageWithSigners } from "@solana/kit";When to reach for this:
"use client";
import { useCallback } from "react";
import { useWallet } from "@solana/wallet-adapter-react";
import {
createSolanaRpc,
createTransactionMessage,
setTransactionMessageLifetimeUsingBlockhash,
appendTransactionMessageInstruction,
signTransactionMessageWithSigners,
sendAndConfirmTransactionFactory,
createSolanaRpcSubscriptions,
} from "@solana/kit";
import { getTransferSolInstruction } from "@solana-program/system";
export function SendButton({ to, lamports }: { to: string; lamports: bigint }) {
const wallet = useWallet();
const rpc = createSolanaRpc(process.env.NEXT_PUBLIC_RPC_URL!);
const rpcSubscriptions = createSolanaRpcSubscriptions(process.env.NEXT_PUBLIC_RPC_WSS_URL!);
const onSend = useCallback(async () => {
if (!wallet.publicKey) return;
const { value: bh } = await rpc.getLatestBlockhash().send();
// Bridge wallet to kit signer (use your template's helper)
let msg = createTransactionMessage({ version: 0 });
// set fee payer signer, lifetime, transfer ix...
const signed = await signTransactionMessageWithSigners(msg);
const sendAndConfirm = sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions });
await sendAndConfirm(signed, { commitment: "confirmed" });
}, [wallet, rpc, rpcSubscriptions, to, lamports]);
return <button onClick={onSend}>Send</button>;
}What this demonstrates:
| Alternative | Use When | Don't Use When |
|---|---|---|
| Server-sponsored tx | Onboarding gasless | Full self-custody |
| Embedded wallet | Web2 UX | Power users |
Providers in client layout.tsx; pages mix server + client components.
Server env only for keypairs; NEXT_PUBLIC_ for RPC URLs.
All examples use @solana/kit, not web3.js v1.
Signing only in client components.
Revalidate on-chain reads carefully - chain is source of truth.
HTTPS endpoints returning Solana Actions JSON.
Separate React Native app with MWA.
Surfpool for integration; mock RPC in unit tests.
Separate env files and program IDs.
Decode simulation logs for user-facing messages.
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.
Reviewed by Chris St. John·Last updated Jul 16, 2026