Skip to content

How to use a Capsule signer with permissionless.js

Capsule offers a signing solution enabling the creation of secure, embedded MPC wallets accessible via email or social login. These wallets, compatible across different applications, offer portability, recoverability, and programmability, eliminating the need for users to establish separate signers or contract accounts for each application.


To use Capsule with permissionless.js, first create an application that integrates with Capsule.

  • Refer to the Capsule documentation site for instructions on setting up an application with the Capsule.
  • For a quick start, Capsule provides an example hub, available here.


Integrating permissionless.js with Capsule is straightforward after setting up the project. Capsule provides an Externally Owned Account (EOA) wallet to use as a signer with permissionless.js accounts.

Create the Capsule signer

After following the Capsule documentation, you will have access to a CapsuleWeb3Provider object that you can use to create a SmartAccountSigner object:

import Capsule from "@usecapsule/web-sdk"
import { createCapsuleViemClient } from '@usecapsule/viem-v2-integration';
import { walletClientToSmartAccountSigner } from "permissionless"
import { http } from "viem"
import { sepolia } from "viem/chains"
// Param options here will be specific to your project.  See the Capsule docs for more info.
const capsule = new Capsule(env, apiKey)
// Convert a Capsule viem client to a SmartAccountSigner
// Follow the Capsule docs for more instructions on creating the Viem client
const viemClient = createCapsuleViemClient(capsule, {
	chain: sepolia,
	transport: http(""),
const smartAccountSigner = walletClientToSmartAccountSigner(viemClient)

Use with permissionless.js

import { signerToSimpleSmartAccount } from "permissionless/accounts"
import { createPublicClient, http } from "viem"
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"
import { sepolia } from "viem/chains"
export const publicClient = createPublicClient({
	transport: http(""),
	chain: sepolia,
const smartAccount = await signerToSimpleSmartAccount(publicClient, {
	signer: smartAccountSigner,
	factoryAddress: "0x9406Cc6185a346906296840746125a0E44976454",