Direct messages are essential for building engagement on Bluesky and helping users grow their following. Whether you're building a full-featured Bluesky client or adding social features to your app, implementing chat functionality can significantly boost user retention and community building. In this tutorial, we'll dive deep into Bluesky's chat API.

Why Chat Features Matter for Bluesky Growth

Before we get into the technical details, let's understand why DMs are crucial for users who want to grow their Bluesky audience:

  • Direct engagement - Personal conversations create stronger connections than public replies
  • Collaboration opportunities - DMs enable partnerships, guest posts, and cross-promotion
  • Community building - Private conversations help foster tight-knit communities
  • Networking - Reaching out to influencers and thought leaders directly
  • Customer support - Brands can handle inquiries privately

Understanding the Bluesky Chat Architecture

Bluesky's chat system uses a separate set of lexicons under the chat.bsky.* namespace. Unlike the main app.bsky.* lexicons for posts and profiles, chat has its own dedicated infrastructure. Here's what you need to know:

  • Conversations (convos) - A thread between two or more participants
  • Messages - Individual messages within a conversation
  • Participants - The users involved in a conversation
  • Read state - Tracking which messages have been read

Setting Up Chat Authentication

Chat APIs require the same authentication as other Bluesky APIs, but you'll be making requests to a different service endpoint. First, authenticate to get your session tokens:

// Authenticate with Bluesky
POST https://bsky.social/xrpc/com.atproto.server.createSession
Content-Type: application/json

{
    "identifier": "your-handle.bsky.social",
    "password": "your-app-password"
}

// Response
{
    "accessJwt": "eyJ...",
    "refreshJwt": "eyJ...",
    "handle": "your-handle.bsky.social",
    "did": "did:plc:xxxxx"
}

Important: Chat requests go to a different endpoint than the main API. You'll typically use api.bsky.chat or the chat proxy endpoint.

Fetching Conversations (List All DMs)

To display a user's inbox with all their conversations, use the chat.bsky.convo.listConvos endpoint:

// List all conversations
GET https://api.bsky.chat/xrpc/chat.bsky.convo.listConvos
Authorization: Bearer {accessJwt}

// Optional parameters:
// ?limit=50 (max 100)
// ?cursor={cursor} (for pagination)

// Response structure
{
    "cursor": "next-page-cursor",
    "convos": [
        {
            "id": "convo-id-123",
            "rev": "revision-string",
            "members": [
                {
                    "did": "did:plc:user1",
                    "handle": "user1.bsky.social",
                    "displayName": "User One",
                    "avatar": "https://..."
                },
                {
                    "did": "did:plc:user2",
                    "handle": "user2.bsky.social",
                    "displayName": "User Two"
                }
            ],
            "lastMessage": {
                "id": "msg-id",
                "text": "Hey, great post!",
                "sender": { "did": "did:plc:user1" },
                "sentAt": "2025-12-19T10:30:00Z"
            },
            "unreadCount": 2,
            "muted": false
        }
    ]
}

Loading Messages in a Conversation

Once a user selects a conversation, fetch the message history:

// Get messages in a conversation
GET https://api.bsky.chat/xrpc/chat.bsky.convo.getMessages
    ?convoId=convo-id-123
    &limit=50
Authorization: Bearer {accessJwt}

// Response
{
    "cursor": "older-messages-cursor",
    "messages": [
        {
            "id": "msg-001",
            "rev": "rev-string",
            "text": "Hey! Love your content about Bluesky development.",
            "sender": { "did": "did:plc:user1" },
            "sentAt": "2025-12-19T10:00:00Z"
        },
        {
            "id": "msg-002",
            "rev": "rev-string",
            "text": "Thanks! Are you building something on ATProtocol?",
            "sender": { "did": "did:plc:user2" },
            "sentAt": "2025-12-19T10:05:00Z"
        }
    ]
}

Sending Direct Messages

To send a message, you'll need the conversation ID. If starting a new conversation, you may need to create it first:

// Send a message to an existing conversation
POST https://api.bsky.chat/xrpc/chat.bsky.convo.sendMessage
Authorization: Bearer {accessJwt}
Content-Type: application/json

{
    "convoId": "convo-id-123",
    "message": {
        "text": "Thanks for connecting! I'd love to collaborate."
    }
}

// Response includes the sent message with ID and timestamp

Starting a New Conversation

To initiate a DM with someone you haven't messaged before, use getConvoForMembers which will return an existing conversation or create a new one:

// Get or create a conversation with specific users
GET https://api.bsky.chat/xrpc/chat.bsky.convo.getConvoForMembers
    ?members=did:plc:targetuser
Authorization: Bearer {accessJwt}

// This returns a conversation object
// Then send your first message using sendMessage

Marking Messages as Read

To update the read state and clear unread counts, call the update endpoint after a user views messages:

// Update read state
POST https://api.bsky.chat/xrpc/chat.bsky.convo.updateRead
Authorization: Bearer {accessJwt}
Content-Type: application/json

{
    "convoId": "convo-id-123",
    "messageId": "latest-read-msg-id"
}

Real-Time Message Updates

For a great user experience, you'll want to show new messages in real-time. Bluesky provides event streams for chat updates. Here's how to subscribe:

// Subscribe to chat events via WebSocket or polling
// The exact implementation depends on your platform

// Polling approach (simpler but less efficient):
// Poll getMessages or listConvos every few seconds

// WebSocket approach (better UX):
// Connect to the chat event stream for instant updates
// Events include: new messages, read receipts, typing indicators

Handling Chat Privacy and Settings

Users can control who can message them. Respect these settings in your app:

  • Accept messages from everyone - Anyone can start a conversation
  • Accept from followers only - Only people they follow can DM
  • Accept from following only - Only people following them can DM
  • Muted conversations - User won't get notifications but can still read
// Check if you can message a user
GET https://api.bsky.chat/xrpc/chat.bsky.convo.getConvoAvailability
    ?members=did:plc:targetuser
Authorization: Bearer {accessJwt}

// Response indicates if messaging is allowed

Building Features That Drive Bluesky Growth

Now that you understand the chat API, here are ideas for features that help users grow their Bluesky presence:

  • Smart notifications - Alert users when influential accounts message them
  • Message templates - Help users craft professional outreach messages
  • Conversation insights - Show response rates and engagement metrics
  • Quick replies - Saved responses for common questions
  • DM scheduling - Send messages at optimal times for engagement
  • Unread highlights - Prioritize conversations with high-follower accounts

Best Practices for Bluesky Chat Implementation

Follow these guidelines to build a great chat experience:

  • Cache aggressively - Store conversation lists and messages locally to reduce API calls
  • Handle rate limits - Implement exponential backoff for API requests
  • Respect user privacy - Never expose message content in logs or analytics
  • Optimize for mobile - DMs are often accessed on phones, so optimize performance
  • Show typing indicators - Real-time feedback makes conversations feel alive
  • Support rich content - Handle links, mentions, and eventually media in messages

Error Handling for Chat APIs

Chat APIs can fail for various reasons. Handle these common errors gracefully:

  • User blocked you - Show a friendly message that the user isn't accepting DMs
  • Rate limited - Queue messages and retry with backoff
  • Conversation not found - The conversation may have been deleted
  • Authentication expired - Refresh tokens and retry

What's Next for Bluesky Chat?

The Bluesky team continues to enhance chat features. Stay tuned for:

  • Group conversations - Chat with multiple participants
  • Media messages - Send images and videos in DMs
  • Message reactions - React to messages with emoji
  • End-to-end encryption - Enhanced privacy for sensitive conversations

Monitor Bluesky Trends While Building

While you're building chat features, stay on top of what's happening on Bluesky:

Building great chat features will set your Bluesky client apart and help your users build meaningful connections. Good luck, and happy coding!