Messenger

Build bots for Facebook Messenger with templates, buttons, reactions, and postbacks.

Building for Instagram Direct Messages? Use the Instagram adapter instead. It connects through Instagram API with Instagram Login and does not require a Facebook Page.

Create a new bot

Scaffold a Next.js bot with the Messenger adapter using create-chat-sdk:

pnpm create chat-sdk@latest my-bot --adapter messenger memory -y

The generated app uses the Memory state adapter for local development. To add the adapter to an existing app, start at Install.

Install

pnpm add @chat-adapter/messenger @chat-adapter/state-memory

Quick start

The adapter auto-detects FACEBOOK_APP_SECRET, FACEBOOK_PAGE_ACCESS_TOKEN, and FACEBOOK_VERIFY_TOKEN from the environment.

lib/bot.ts
import { Chat } from "chat";
import { createMessengerAdapter } from "@chat-adapter/messenger";
import { createMemoryState } from "@chat-adapter/state-memory";

const bot = new Chat({
  userName: "mybot",
  adapters: {
    messenger: createMessengerAdapter(),
  },
  state: createMemoryState(),
});

bot.onDirectMessage(async (thread, message) => {
  await thread.post("Hello from Messenger!");
});

The memory state adapter keeps subscriptions and locks in process memory, which suits local development. Use Redis or PostgreSQL in production.

app/api/webhooks/messenger/route.ts
import { after } from "next/server";
import { bot } from "@/lib/bot";

export async function GET(request: Request) {
  return bot.webhooks.messenger(request);
}

export async function POST(request: Request) {
  return bot.webhooks.messenger(request, {
    waitUntil: (task) => after(() => task),
  });
}

Platform setup

Create a Meta app

  1. Go to developers.facebook.com/apps.
  2. Create an app and select "Engage with customers on Messenger from Meta".
  3. Under App Settings then Basic, copy the App Secret to FACEBOOK_APP_SECRET.

Create a Facebook Page

Users interact with your bot by messaging a Facebook Page, so the bot needs one to send and receive messages. If you don't already have a Page, create one under a Facebook Business profile.

Get credentials

  1. In your Meta app dashboard, open Use Cases then Messenger API Settings.
  2. Under Generate access tokens, click Add or remove Pages and select your Page.
  3. Generate the token and copy it to FACEBOOK_PAGE_ACCESS_TOKEN.

Choose your own random string for FACEBOOK_VERIFY_TOKEN. You enter the same value in the next step.

Configure webhooks

Deploy the GET and POST route shown above to a public HTTPS URL first, then, in Messenger API Settings:

  1. Click Add Callback URL and enter https://your-domain.com/api/webhooks/messenger.
  2. Set Verify Token to the same value as FACEBOOK_VERIFY_TOKEN.
  3. Click Verify and Save.
  4. Add subscriptions: messages, messaging_postbacks, messaging_reactions, message_deliveries, message_reads.

Configuration

Prop

Type

Environment variables

VariableRequiredDescription
FACEBOOK_APP_SECRETYesApp secret used to verify webhook signatures
FACEBOOK_PAGE_ACCESS_TOKENYesAccess token for the Facebook Page the bot sends as
FACEBOOK_VERIFY_TOKENYesYour chosen secret for the webhook verification handshake

Webhooks

The route handles two kinds of request from Meta:

  • GET verification handshake: Meta sends a hub.verify_token challenge that must match FACEBOOK_VERIFY_TOKEN.
  • POST event delivery: incoming messages, reactions, and postbacks, signed with X-Hub-Signature-256 and verified against FACEBOOK_APP_SECRET.

Interactive messages

The adapter converts card elements to Messenger templates:

  • Generic Template: used when the card has a title or imageUrl. Up to 3 buttons.
  • Button Template: used when the card has text content and buttons but no title or image. Max 640 characters.
  • Text fallback: used when the card contains unsupported elements (tables, select menus) or exceeds these constraints.

Constraints:

  • Max 3 buttons per template.
  • Button titles limited to 20 characters (truncated with ellipsis).
  • Subtitles limited to 80 characters.
  • Button Template text limited to 640 characters.

Inbound attachments

Inbound attachment URLs remain available as attachment.url. The adapter's fetchData function downloads media only from Meta's fbsbx.com and fbcdn.net hosts, refuses private and internal addresses (including after redirects), limits responses to 25 MB, and times out after 30 seconds. External fallback and link-share URLs are preserved but rejected before any network request.

Read receipts

Use thread.markAsRead() in a message handler to send Messenger's mark_seen sender action:

bot.onDirectMessage(async (thread) => {
  await thread.markAsRead();
  await thread.post("Thanks, I have seen your message.");
});

Messenger applies this action to the conversation's seen state rather than a single message, even when you pass a message or message ID.

Thread IDs

messenger:{recipientId}

Example: messenger:27161130920158013.

recipientId is the user's ID as Meta sends it in the webhook's sender.id. Each conversation between the Page and one user is one thread.

Feature support

Messaging

FeatureSupported
Post message
Message replies
Edit message
Delete message
File uploads
StreamingBuffered
Scheduled messages

Rich content

FeatureSupported
Card formatGeneric / Button Templates
ButtonsMax 3, postback
Link buttonsweb_url
Select menus
TablesASCII
Charts
FieldsASCII
Images in cards
Modals

Conversations

FeatureSupported
Slash commands
Mentions
Add reactions
Remove reactions
Typing indicator
Mark as read
Message edit events
Message delete events
DMs
Ephemeral messages
User lookup
Parent subject
Native client
Custom API endpoint

Message history

FeatureSupported
Fetch messagesCached sent only
Fetch single messageCached
Fetch thread info
Fetch channel messagesCached
List threads
Fetch channel info
Post channel message

More adapters