XMTP Web3 Messenger Integration

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
XMTP Web3 Messenger Integration
Medium
~3-5 business days
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

XMTP Web3 Messenger Integration

Regular in-dApp chat—Firebase Realtime Database or Websocket with JWT auth. Problem: centralized message storage, dependence on your server, no protocol-level encryption. XMTP (Extensible Message Transport Protocol)—decentralized messaging where messages encrypt with wallet's end-to-end keys and store in decentralized node network. Ethereum address = user identifier, private key = encryption key.

How XMTP Works

On first use, user creates XMTP identity: signs message with wallet, deterministic identity key generated from signature. This key registers in XMTP network. Messages encrypt with recipient's public key via X3DH (Extended Triple Diffie-Hellman)—same protocol as Signal.

Messages store in XMTP nodes, not your server. User can open your integration, Coinbase Wallet, Converse, or any XMTP-compatible client—and see all messages.

Installation and Basic Integration

npm install @xmtp/browser-sdk
import { Client } from "@xmtp/browser-sdk"

// Initialize client
async function initXMTP(signer: WalletSigner) {
  const client = await Client.create(signer, { env: "production" })
  return client
}

// Check if address is registered in XMTP
async function canMessage(client: Client, address: string): Promise<boolean> {
  return await client.canMessage(address)
}

// Create or open conversation
async function getOrCreateConversation(client: Client, recipientAddress: string) {
  const conversation = await client.conversations.newConversation(recipientAddress)
  return conversation
}

Nuance: Client.create requires wallet signature. First time—two signatures (identity creation), repeat runs—one. Communicate properly in UI or users get confused.

Integration with wagmi/viem

XMTP expects Signer object with signMessage method. Adapter for wagmi:

import { useWalletClient } from "wagmi"
import { Client } from "@xmtp/browser-sdk"

function useXMTPClient() {
  const { data: walletClient } = useWalletClient()
  const [xmtp, setXmtp] = useState<Client | null>(null)

  const connect = async () => {
    if (!walletClient) return

    // Adapter: wagmi WalletClient -> XMTP Signer
    const signer = {
      getAddress: () => walletClient.account.address,
      signMessage: (message: string) =>
        walletClient.signMessage({ message })
    }

    const client = await Client.create(signer, {
      env: "production",
      // Persistent key storage in localStorage
      persistConversations: true
    })

    setXmtp(client)
  }

  return { xmtp, connect }
}

Conversation List and Messages

function ConversationList({ client }: { client: Client }) {
  const [conversations, setConversations] = useState<Conversation[]>([])

  useEffect(() => {
    const loadConversations = async () => {
      const convos = await client.conversations.list()
      setConversations(convos)
    }

    loadConversations()

    // Listen for new conversations
    const stream = client.conversations.stream()
    const subscription = stream.then(s => {
      ;(async () => {
        for await (const convo of s) {
          setConversations(prev => [convo, ...prev])
        }
      })()
    })

    return () => { subscription.then(s => s.return?.()) }
  }, [client])

  return (
    <ul>
      {conversations.map(convo => (
        <ConversationItem key={convo.peerAddress} conversation={convo} />
      ))}
    </ul>
  )
}
function MessageThread({ conversation }: { conversation: Conversation }) {
  const [messages, setMessages] = useState<DecodedMessage[]>([])

  useEffect(() => {
    const loadMessages = async () => {
      const msgs = await conversation.messages({ limit: 50 })
      setMessages(msgs)
    }

    loadMessages()

    // Realtime streaming of new messages
    const startStream = async () => {
      for await (const message of await conversation.streamMessages()) {
        setMessages(prev => [...prev, message])
      }
    }
    startStream()
  }, [conversation])

  const sendMessage = async (text: string) => {
    await conversation.send(text)
  }

  return (
    <div>
      {messages.map(msg => (
        <MessageBubble
          key={msg.id}
          text={msg.content}
          isMine={msg.senderAddress === conversation.client.address}
          timestamp={msg.sent}
        />
      ))}
    </div>
  )
}

Content Types: Rich Message Content

XMTP supports more than text. Content Types—standardized mechanism for arbitrary message types:

import { ContentTypeAttachment, AttachmentCodec } from "@xmtp/content-type-attachments"
import { ContentTypeReaction, ReactionCodec } from "@xmtp/content-type-reaction"

// Initialize with custom content types
const client = await Client.create(signer, {
  env: "production",
  codecs: [new AttachmentCodec(), new ReactionCodec()]
})

// Send file (up to 1MB, larger—via remote attachments)
await conversation.send({
  filename: "contract.pdf",
  mimeType: "application/pdf",
  data: pdfBytes
}, { contentType: ContentTypeAttachment })

// React to message
await conversation.send({
  reference: messageId,
  action: "added",
  content: "👍",
  schema: "unicode"
}, { contentType: ContentTypeReaction })

Standard content types: text/plain, attachment, remote-attachment (files on IPFS/S3), reaction, reply (message replies), read-receipt. For custom needs—register own namespace.

Frames and Bots

XMTP supports Frames (like Farcaster Frames)—interactive cards in messages with buttons. Bot on XMTP—just Node.js process with XMTP client listening for incoming messages and replying:

const botClient = await Client.create(botSigner, { env: "production" })

for await (const message of await botClient.conversations.streamAllMessages()) {
  if (message.senderAddress === botClient.address) continue  // don't reply to self

  const response = await generateBotResponse(message.content)
  await message.conversation.send(response)
}

Used for transaction notifications, price alerts, customer support.

Development Timeline

Day 1-2: XMTP SDK integration, wallet adapter, basic conversation and message UI.

Day 3: Real-time streaming, message sending, address search.

Day 4-5: Advanced content types, notifications, mobile adaptation.

Basic messenger with text messages and real-time updates — 2-3 days. Full-featured chat with attachments, reactions, XMTP bot — 4-5 days.