> For the complete documentation index, see [llms.txt](/llms.txt).

# Create a social invite link

`delegation toolkit` `smart accounts kit` `embedded wallets` `social` `invite` `referral` `link`MetaMask Developer Relations | Sep 8, 2025

Open in Claude

This tutorial walks you through creating an invite link so users can refer their friends to your dapp with minimal friction.

For example, Alice (the inviter) wants Bob (the invitee) to try out your dapp. She sends him a link that allows him to claim 0.001 ETH from her wallet within a time limit. Bob can start using your dapp right away, without installing a wallet or paying gas fees.

You'll enable this by:

- Adding an [embedded wallet](/embedded-wallets/) for instant onboarding.
- Creating a [MetaMask smart account](/smart-accounts-kit/concepts/smart-accounts/) to create and redeem an invitation.
- Creating an [open delegation](/smart-accounts-kit/concepts/delegation/overview/) to represent an invitation.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

- Install [Node.js](https://nodejs.org/en/blog/release/v18.18.0) v18 or later.
- Install [Yarn](https://yarnpkg.com/), [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), or another package manager.
- Get a [Client ID](/embedded-wallets/dashboard/) from the Embedded Wallets (Web3Auth) dashboard.
- [Create a Pimlico API key](https://docs.pimlico.io/guides/create-api-key#create-api-key).  
note  
This tutorial uses Pimlico's bundler and paymaster, but you can use any bundler and paymaster of your choice.

## Steps[​](#steps "Direct link to Steps")

### 1\. Set up the project[​](#1-set-up-the-project "Direct link to 1. Set up the project")

#### 1.1. Install dependencies[​](#11-install-dependencies "Direct link to 1.1. Install dependencies")

Install the [Smart Accounts Kit](https://www.npmjs.com/package/@metamask/smart-accounts-kit) and other dependencies in your project:

- npm
- Yarn
- pnpm
- Bun

```
npm install @metamask/smart-accounts-kit @web3auth/modal wagmi @tanstack/react-query

```

```
yarn add @metamask/smart-accounts-kit @web3auth/modal wagmi @tanstack/react-query

```

```
pnpm add @metamask/smart-accounts-kit @web3auth/modal wagmi @tanstack/react-query

```

```
bun add @metamask/smart-accounts-kit @web3auth/modal wagmi @tanstack/react-query

```

#### 1.2. Set up Embedded Wallets[​](#12-set-up-embedded-wallets "Direct link to 1.2. Set up Embedded Wallets")

Configure [MetaMask Embedded Wallets (previously Web3Auth)](/embedded-wallets/) to enable users to instantly connect to your dapp using familiar login methods, like social accounts or email.

1. Add a `WEB3AUTH_CLIENT_ID` environment variable, replacing `<YOUR-CLIENT-ID>` with your Web3Auth Client ID:  
.env.local  
```  
WEB3AUTH_CLIENT_ID=<YOUR-CLIENT-ID>  
```
2. Configure Web3Auth options:  
providers/AppProvider.tsx  
```  
import { WEB3AUTH_NETWORK, Web3AuthOptions } from '@web3auth/modal'  
const web3AuthOptions: Web3AuthOptions = {  
  clientId: process.env.WEB3AUTH_CLIENT_ID as string,  
  web3AuthNetwork: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET,  
}  
const web3authConfig = {  
  web3AuthOptions,  
}  
```
3. Create a connect button:  
components/ConnectButton.tsx  
```  
import { useWeb3AuthConnect } from '@web3auth/modal/react'  
import Button from '@/components/Button' // You can add your own Button component  
export default function ConnectButton() {  
  const { connect } = useWeb3AuthConnect()  
  return (  
    <div className="flex gap-2">  
      <Button onClick={() => connect()}>Connect with Web3Auth</Button>  
    </div>  
  )  
}  
```

#### 1.3. Set up Wagmi[​](#13-set-up-wagmi "Direct link to 1.3. Set up Wagmi")

Wrap your dapp with the Wagmi, Web3Auth, and React Query providers. Add Wagmi using the Web3Auth Wagmi adapter so wallet connections from Web3Auth are available to Wagmi hooks.

providers/AppProvider.tsx

```
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { Web3AuthProvider } from '@web3auth/modal/react'
import { WagmiProvider } from '@web3auth/modal/react/wagmi'

const queryClient = new QueryClient()

export function AppProvider({ children }: { children: React.ReactNode }) {
  return (
    <Web3AuthProvider config={web3authConfig}>
      <QueryClientProvider client={queryClient}>
        <WagmiProvider>{children}</WagmiProvider>
      </QueryClientProvider>
    </Web3AuthProvider>
  )
}

```

### 2\. Set up a Bundler Client[​](#2-set-up-a-bundler-client "Direct link to 2. Set up a Bundler Client")

Set up a Bundler Client using Viem's [createBundlerClient](https://viem.sh/account-abstraction/clients/bundler) function. You can use the [bundler](/smart-accounts-kit/development/reference/glossary#bundler)**Bundler** An ERC-4337 component that manages the alternate mempool: it collects user operations from smart accounts, packages them, and submits them to the network. service to estimate gas for user operations and submit transactions to the network.

Set `paymaster` to `true` to use the Pimlico [paymaster](/smart-accounts-kit/development/reference/glossary#paymaster)**Paymaster** A service that pays for user operations on behalf of a smart account. with the Bundler Client, and replace `<YOUR-API-KEY>` with your Pimlico API key:

```
import { createBundlerClient } from 'viem/account-abstraction'
import { usePublicClient } from 'wagmi'

const publicClient = usePublicClient()

const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://api.pimlico.io/v2/11155111/rpc?apikey=<YOUR-API-KEY>'),
  paymaster: true, // The same Pimlico URL will be used for bundler and paymaster.
})

```

### 3\. Create a smart account[​](#3-create-a-smart-account "Direct link to 3. Create a smart account")

Create an account to create and redeem an invitation. This account will create a delegation, and must be a [MetaMask smart account](/smart-accounts-kit/concepts/smart-accounts/). This example uses a [Hybrid smart account](/smart-accounts-kit/guides/smart-accounts/create-smart-account/#hybrid-smart-account), which is a flexible smart account implementation that supports both an [EOA](/smart-accounts-kit/development/reference/glossary#externally-owned-account-eoa)**Externally owned account (EOA)** A private-key-controlled account with no built-in programmable execution logic. owner and any number of [passkey](/smart-accounts-kit/development/reference/glossary#passkey)**Passkey** A cryptographic key that can be used to sign transactions instead of a private key. (WebAuthn) signers:

```
import { Implementation, toMetaMaskSmartAccount } from '@metamask/smart-accounts-kit'
import { useConnection, usePublicClient, useWalletClient } from 'wagmi'

const { address } = useConnection()
const publicClient = usePublicClient()
const { data: walletClient } = useWalletClient()

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [address, [], [], []],
  deploySalt: '0x',
  signer: { walletClient },
})

```

### 4\. Create an invitation[​](#4-create-an-invitation "Direct link to 4. Create an invitation")

#### 4.1. Deploy the account[​](#41-deploy-the-account "Direct link to 4.1. Deploy the account")

To create an invitation, first deploy the smart account by sending a [user operation](/smart-accounts-kit/development/reference/glossary#user-operation)**User operation** A pseudo-transaction object defined by ERC-4337 that describes what a smart account should execute. User operations are submitted to the alternate mempool managed by bundlers.:

```
import { zeroAddress } from 'viem'

// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n
const maxPriorityFeePerGas = 1n

const userOperationHash = await bundlerClient.sendUserOperation({
  account: smartAccount,
  calls: [{ to: zeroAddress }],
  maxFeePerGas,
  maxPriorityFeePerGas,
})

```

#### 4.2. Fund the account[​](#42-fund-the-account "Direct link to 4.2. Fund the account")

Fund the deployed smart account with some Sepolia ETH to enable the invitee to spend funds when they redeem the invitation.

note

You can use the [MetaMask faucet](/developer-tools/faucet/) to get Sepolia ETH.

#### 4.3. Create an open root delegation[​](#43-create-an-open-root-delegation "Direct link to 4.3. Create an open root delegation")

Create an [open root delegation](/smart-accounts-kit/concepts/delegation/overview/) to represent an invitation. A root delegation is the first delegation in a chain of delegations, and an open root delegation grants permission to any account. In this example, the inviter creates an invitation that can be redeemed by any invitee, allowing the invitee to spend up to 0.001 ETH.

```
import { createOpenDelegation } from '@metamask/smart-accounts-kit'

const delegation = createOpenDelegation({
  from: smartAccount.address,
  environment: smartAccount.environment,
  scope: {
    type: 'nativeTokenTransferAmount',
    // 0.001 ETH in wei format.
    maxAmount: 1000000000000000n,
  },
})

```

#### 4.4. Sign the delegation[​](#44-sign-the-delegation "Direct link to 4.4. Sign the delegation")

Sign the delegation to enable the invitee to redeem the invitation in the future:

```
const signature = await smartAccount.signDelegation({
  delegation,
})

const signedDelegation = {
  ...delegation,
  signature,
}

```

#### 4.5. Share the invitation[​](#45-share-the-invitation "Direct link to 4.5. Share the invitation")

Encode the delegation into a shareable invite link:

```
import { Delegation } from '@metamask/smart-accounts-kit'

export function encodeDelegation(delegation: Delegation): string {
  const delegationJson = JSON.stringify(delegation)
  return Buffer.from(delegationJson, 'utf-8').toString('base64')
}

const encoded = encodeDelegation(signedDelegation)

const url = new URL(window.location.href)
url.searchParams.set('delegation', encoded)
const shareableUrl = url.toString()

```

The inviter can now share the link with anyone.

### 5\. Redeem the invitation[​](#5-redeem-the-invitation "Direct link to 5. Redeem the invitation")

#### 5.1. Decode the shared invitation[​](#51-decode-the-shared-invitation "Direct link to 5.1. Decode the shared invitation")

When the invitee opens the shared invite link, decode the delegation:

```
import { Delegation } from '@metamask/smart-accounts-kit'

const urlParams = new URLSearchParams(window.location.search)
const encodedDelegation = urlParams.get('delegation')

export function decodeDelegation(encodedDelegation: string): Delegation {
  const decodedDelegationJson = Buffer.from(encodedDelegation, 'base64').toString('utf-8')
  return JSON.parse(decodedDelegationJson) as Delegation
}

const decodedDelegation = decodeDelegation(encodedDelegation)

```

#### 5.2. Redeem the delegation[​](#52-redeem-the-delegation "Direct link to 5.2. Redeem the delegation")

[Redeem the delegation](/smart-accounts-kit/guides/delegation/execute-on-smart-accounts-behalf/#7-redeem-the-delegation) by submitting a [user operation](/smart-accounts-kit/development/reference/glossary#user-operation)**User operation** A pseudo-transaction object defined by ERC-4337 that describes what a smart account should execute. User operations are submitted to the alternate mempool managed by bundlers. from the smart account to the `DelegationManager` contract. Submitting the user operation deploys the account for first-time users.

The [Delegation Manager](/smart-accounts-kit/development/reference/glossary#delegation-manager)**Delegation Manager** The ERC-7710 component that validates and redeems delegations, including signature checks and caveat enforcer hooks. validates the delegation and executes delegated actions. In this case, the invitee can spend up to 0.001 ETH when using your dapp.

```
import {
  createExecution,
  getSmartAccountsEnvironment,
  ExecutionMode,
} from '@metamask/smart-accounts-kit'
import { DelegationManager } from '@metamask/smart-accounts-kit/contracts'

const delegations = [decodedDelegation]

const executions = [createExecution({ target: smartAccount.address, value: 1000000000000000n })]

const redeemDelegationCalldata = DelegationManager.encode.redeemDelegations({
  delegations: [delegations],
  modes: [ExecutionMode.SingleDefault],
  executions: [executions],
})

// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n
const maxPriorityFeePerGas = 1n

const userOperationHash = await bundlerClient.sendUserOperation({
  account: smartAccount,
  calls: [
    {
      to: smartAccount.address,
      data: redeemDelegationCalldata,
    },
  ],
  maxFeePerGas,
  maxPriorityFeePerGas,
})

```

## Next steps[​](#next-steps "Direct link to Next steps")

- See [invitation-link-example](https://github.com/MetaMask/gator-examples/tree/feat/invitation-link-example/examples/invitation-link-example) on GitHub for a complete example dapp.
- When creating an invitation, you can add more rules and restrictions using [delegation scopes](/smart-accounts-kit/guides/delegation/use-delegation-scopes/) and [caveat enforcers](/smart-accounts-kit/guides/delegation/use-delegation-scopes/constrain-scope/).
- Learn more about [smart account implementations](/smart-accounts-kit/guides/smart-accounts/create-smart-account/).
- Learn more about [delegation types](/smart-accounts-kit/concepts/delegation/overview/#delegation-types).

[Share](https://www.facebook.com/sharer/sharer.php?https://metamask.io/tutorials/create-invite-link)[Tweet](http://twitter.com/share?text=Checkout Create a social invite link published by @MetaMask&url=https://metamask.io/tutorials/create-invite-link)Copy

On this page
- [Prerequisites](#prerequisites)
- [Steps](#steps)
  - [1\. Set up the project](#1-set-up-the-project)
    - [1.1. Install dependencies](#11-install-dependencies)
    - [1.2. Set up Embedded Wallets](#12-set-up-embedded-wallets)
    - [1.3. Set up Wagmi](#13-set-up-wagmi)
  - [2\. Set up a Bundler Client](#2-set-up-a-bundler-client)
  - [3\. Create a smart account](#3-create-a-smart-account)
  - [4\. Create an invitation](#4-create-an-invitation)
    - [4.1. Deploy the account](#41-deploy-the-account)
    - [4.2. Fund the account](#42-fund-the-account)
    - [4.3. Create an open root delegation](#43-create-an-open-root-delegation)
    - [4.4. Sign the delegation](#44-sign-the-delegation)
    - [4.5. Share the invitation](#45-share-the-invitation)
  - [5\. Redeem the invitation](#5-redeem-the-invitation)
    - [5.1. Decode the shared invitation](#51-decode-the-shared-invitation)
    - [5.2. Redeem the delegation](#52-redeem-the-delegation)
- [Next steps](#next-steps)
