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

# Send transactions

Use MetaMask Connect EVM to send Ethereum transactions from your JavaScript dapp. MetaMask Connect EVM supports [eth_sendTransaction](/metamask-connect/evm/reference/json-rpc-api/eth%5FsendTransaction/) through viem, ethers.js, web3.js, the raw Ethereum API, and Wagmi, with built-in gas estimation, transaction receipt tracking, and error handling for common failure cases like user rejection and insufficient funds.

With MetaMask Connect EVM:

- **Send transactions**.
- **Track transaction status** in real time.
- **Estimate gas costs** accurately.
- **Handle transaction errors** gracefully.
- **Manage complex transaction patterns**.

The following examples demonstrate how to use MetaMask Connect EVM with viem, web3.js, ethers.js, Ethereum APIs, or Wagmi to send a [basic transaction](#send-a-basic-transaction) and an [advanced transaction with gas estimation](#send-an-advanced-transaction-with-gas-estimation).

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

Follow the [JavaScript quickstart](/metamask-connect/evm/quickstart/javascript/) or [Wagmi quickstart](/metamask-connect/evm/quickstart/wagmi/) to install, initialize, and connect the EVM client.

## Send a basic transaction[​](#send-a-basic-transaction "Direct link to Send a basic transaction")

- viem
- web3.js
- ethers.js
- Ethereum API
- Wagmi

```
import { createEVMClient } from '@metamask/connect-evm'
import { createPublicClient, createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'

const evmClient = await createEVMClient({
  dapp: {
    name: 'MetaMask Connect EVM Example',
    url: window.location.href,
    iconUrl: 'https://mydapp.com/icon.png', // Optional
  },
  api: {
    supportedNetworks: {
      '0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
      '0xaa36a7': 'https://sepolia.infura.io/v3/YOUR_INFURA_API_KEY',
    },
  },
})
const provider = evmClient.getProvider()

const publicClient = createPublicClient({ chain: mainnet, transport: custom(provider) })
const walletClient = createWalletClient({ chain: mainnet, transport: custom(provider) })

// data for the transaction
const destination = '0xRECIPIENT_ADDRESS'
const amount = parseEther('0.0001')
const address = await walletClient.getAddresses()

// Submit transaction to the blockchain
const hash = await walletClient.sendTransaction({
  account: address[0],
  to: destination,
  value: amount,
})

const receipt = await publicClient.waitForTransactionReceipt({ hash })

```

```
import { createEVMClient } from '@metamask/connect-evm'
import { Web3 } from 'web3'

const evmClient = await createEVMClient({
  dapp: {
    name: 'MetaMask Connect EVM Example',
    url: window.location.href,
    iconUrl: 'https://mydapp.com/icon.png', // Optional
  },
  api: {
    supportedNetworks: {
      '0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
      '0xaa36a7': 'https://sepolia.infura.io/v3/YOUR_INFURA_API_KEY',
    },
  },
})
const provider = evmClient.getProvider()

const web3 = new Web3(provider)

// Get user's Ethereum public address
const fromAddress = (await web3.eth.getAccounts())[0]

const destination = '0xRECIPIENT_ADDRESS'
const amount = web3.utils.toWei('0.0001') // Convert 0.0001 ether to wei

// Submit transaction to the blockchain and wait for it to be mined
const receipt = await web3.eth.sendTransaction({
  from: fromAddress,
  to: destination,
  value: amount,
})

```

```
import { createEVMClient } from '@metamask/connect-evm'
import { ethers } from 'ethers'
import { BrowserProvider, parseUnits } from 'ethers'

const evmClient = await createEVMClient({
  dapp: {
    name: 'MetaMask Connect EVM Example',
    url: window.location.href,
    iconUrl: 'https://mydapp.com/icon.png', // Optional
  },
  api: {
    supportedNetworks: {
      '0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
      '0xaa36a7': 'https://sepolia.infura.io/v3/YOUR_INFURA_API_KEY',
    },
  },
})
const provider = evmClient.getProvider()

const ethersProvider = new ethers.BrowserProvider(provider)
const signer = await ethersProvider.getSigner()

const destination = '0xRECIPIENT_ADDRESS'
const amount = parseUnits('0.0001', 'ether')

// Submit transaction to the blockchain
const tx = await signer.sendTransaction({
  to: destination,
  value: amount,
})

// Wait for the transaction to be mined
const receipt = await tx.wait()

```

```
import { createEVMClient } from '@metamask/connect-evm'

const evmClient = await createEVMClient({
  dapp: {
    name: 'MetaMask Connect EVM Example',
    url: window.location.href,
    iconUrl: 'https://mydapp.com/icon.png', // Optional
  },
  api: {
    supportedNetworks: {
      '0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
      '0xaa36a7': 'https://sepolia.infura.io/v3/YOUR_INFURA_API_KEY',
    },
  },
})
const provider = evmClient.getProvider()

async function sendTransaction(recipientAddress, amount) {
  try {
    // Get current account
    const accounts = await provider.request({
      method: 'eth_requestAccounts',
    })
    const from = accounts[0]

    // Convert ETH amount to wei (hex)
    const value = `0x${(amount * 1e18).toString(16)}`

    // Prepare transaction
    const transaction = {
      from,
      to: recipientAddress,
      value,
      // Gas fields are optional - MetaMask will estimate
    }

    // Send transaction
    const txHash = await provider.request({
      method: 'eth_sendTransaction',
      params: [transaction],
    })

    return txHash
  } catch (error) {
    if (error.code === 4001) {
      throw new Error('Transaction rejected by user')
    }
    throw error
  }
}

// Track transaction status
function watchTransaction(txHash) {
  return new Promise((resolve, reject) => {
    const checkTransaction = async () => {
      try {
        const tx = await provider.request({
          method: 'eth_getTransactionReceipt',
          params: [txHash],
        })

        if (tx) {
          if (tx.status === '0x1') {
            resolve(tx)
          } else {
            reject(new Error('Transaction failed'))
          }
        } else {
          setTimeout(checkTransaction, 2000) // Check every 2 seconds
        }
      } catch (error) {
        reject(error)
      }
    }

    checkTransaction()
  })
}

```

```
import { parseEther } from 'viem'
import { useSendTransaction, useWaitForTransactionReceipt } from 'wagmi'

function SendTransaction() {
  const { data: hash, error, isPending, sendTransaction } = useSendTransaction()

  const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({
    hash,
  })

  async function handleSend() {
    sendTransaction({
      to: '0x...',
      value: parseEther('0.1'), // 0.1 ETH
    })
  }

  return (
    <div>
      <button onClick={handleSend} disabled={isPending}>
        {isPending ? 'Confirming...' : 'Send 0.1 ETH'}
      </button>

      {hash && (
        <div>
          Transaction Hash: {hash}
          {isConfirming && <div>Waiting for confirmation...</div>}
          {isConfirmed && <div>Transaction confirmed!</div>}
        </div>
      )}

      {error && <div>Error: {error.message}</div>}
    </div>
  )
}

```

## Send an advanced transaction with gas estimation[​](#send-an-advanced-transaction-with-gas-estimation "Direct link to Send an advanced transaction with gas estimation")

- Ethereum API
- Wagmi

```
import { createEVMClient } from '@metamask/connect-evm'

const evmClient = await createEVMClient({
  dapp: {
    name: 'MetaMask Connect EVM Example',
    url: window.location.href,
    iconUrl: 'https://mydapp.com/icon.png', // Optional
  },
  api: {
    supportedNetworks: {
      '0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
      '0xaa36a7': 'https://sepolia.infura.io/v3/YOUR_INFURA_API_KEY',
    },
  },
})
const provider = evmClient.getProvider()

async function estimateGas(transaction) {
  try {
    const gasEstimate = await provider.request({
      method: 'eth_estimateGas',
      params: [transaction],
    })

    // Add 20% buffer for safety
    return (BigInt(gasEstimate) * 120n) / 100n
  } catch (error) {
    console.error('Gas estimation failed:', error)
    throw error
  }
}

```

```
import { parseEther } from 'viem'
import { useSendTransaction, useWaitForTransactionReceipt, useEstimateGas } from 'wagmi'

function AdvancedTransaction() {
  const transaction = {
    to: '0x...',
    value: parseEther('0.1'),
    data: '0x...', // Optional contract interaction data
  }

  // Estimate gas
  const { data: gasEstimate } = useEstimateGas(transaction)

  const { sendTransaction } = useSendTransaction()

  function handleSend() {
    sendTransaction({
      ...transaction,
      gas: gasEstimate,
    })
  }

  return <button onClick={handleSend}>Send with Gas Estimate</button>
}

```

## Best practices[​](#best-practices "Direct link to Best practices")

Follow these best practices when handling transactions.

### Transaction security[​](#transaction-security "Direct link to Transaction security")

- Always **validate inputs** before sending transactions.
- Check wallet balances to **ensure sufficient** funds.
- **Verify addresses** are valid.

### Error handling[​](#error-handling "Direct link to Error handling")

- Handle [common errors](#common-errors) like **user rejection** and **insufficient funds**.
- Provide **clear error messages** to users.
- Implement proper **error recovery** flows.
- Consider **network congestion** in gas estimates.

### User experience[​](#user-experience "Direct link to User experience")

- Display **clear loading states** during transactions.
- Show **transaction progress** in real time.
- Provide **detailed transaction information**.

## Common errors[​](#common-errors "Direct link to Common errors")

| Error code | Description               | Solution                                                  |
| ---------- | ------------------------- | --------------------------------------------------------- |
| 4001       | User rejected transaction | Show a retry option and a clear error message.            |
| -32603     | Insufficient funds        | Check the balance before sending a transaction.           |
| -32000     | Gas too low               | Increase the gas limit or add a buffer to the estimation. |
| -32002     | Request already pending   | Prevent multiple concurrent transactions.                 |

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

See the following guides to add more functionality to your dapp:

- [Manage user accounts](/metamask-connect/evm/guides/manage-user-accounts/)
- [Manage networks](/metamask-connect/evm/guides/manage-networks/)
- [Interact with smart contracts](/metamask-connect/evm/guides/interact-with-contracts/)
