Skip to content

Todo para WordPress, el desarrollo web — y mucho más

🤖 Configurar menú persistente y botones para bot de Facebook Messenger

🤖 Configurar menú persistente y botones para bot de Facebook Messenger

Ha lanzado un bot en Facebook Messenger, responde a los mensajes, pero algo falta. Un usuario abre el chat y ve una ventana vacía. Sin menú, sin pistas, sin botón «Comenzar». Primer contacto y silencio. La gente simplemente no entiende qué puede hacer su bot.

Tres componentes convierten un bot sin rostro en una interfaz comprensible: un menú persistente con acciones rápidas, un botón «Comenzar» para el primer contacto y un texto de saludo que recibe al usuario por su nombre. Antes, todo esto se configuraba mediante el parámetro obsoleto thread_settings. Ahora Meta ha trasladado el control a la API unificada de Messenger Profile, y las antiguas llamadas cURL de los tutoriales de 2017 simplemente no funcionan.

En esta guía, el enfoque actual para configurar el menú persistente, el botón «Comenzar» y el saludo a través de la API de Messenger Profile. Con ejemplos funcionales de cURL y un manejador de POSTBACK en PHP que distingue los clics en los elementos del menú.

💡 Resumen rápido:

  • Configure el menú persistente mediante persistent_menu en la API de Messenger Profile: hasta 20 elementos, localización, desactivación del compositor
  • Añada el botón «Comenzar» mediante el parámetro get_started: al primer contacto, Facebook devuelve el PSID del usuario
  • Configure el texto de saludo mediante greeting: las plantillas {{user_first_name}} siguen funcionando en 2026
  • Escriba un manejador de POSTBACK en PHP: un switch sobre payload distingue qué elemento del menú pulsó el usuario
  • Considere los límites: 10 llamadas a la API de Profile cada 10 minutos por página, hasta 24 horas para la actualización de la caché del menú

Qué cambió: Thread Settings → API de Messenger Profile

Antes de 2020, el menú, el botón «Comenzar» y el saludo se configuraban con solicitudes POST separadas al endpoint /me/thread_settings. El tipo de configuración se especificaba en el cuerpo mediante setting_type: call_to_actions para el menú, greeting para el saludo. En 2026, este enfoque no funciona, el endpoint ha sido eliminado de la documentación.

Ahora todas las propiedades del bot se establecen a través de la API de Messenger Profile, un endpoint unificado:

1POST https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN

El cuerpo de la solicitud es un objeto JSON con las propiedades necesarias: persistent_menu para el menú, get_started para el botón «Comenzar», greeting para el saludo, ice_breakers y whitelisted_domains. Puede enviarlas juntas o por separado. El perfil se sobrescribe, no envíe una propiedad si no desea modificarla.

Documentación oficial: Menú persistente en Meta for Developers. La versión de la API se actualiza cada seis meses, verifique la actual mediante el Registro de cambios.

Requisitos para que el menú funcione, vigentes a junio de 2026:

  • La página de Facebook está publicada, el bot cambiado a modo «público» en la configuración de la app
  • La app tiene el permiso pages_messaging
  • El usuario ejecuta Messenger versión 106 o superior
  • El botón «Comenzar» está configurado (sin él, el menú no se muestra)
  • Usted tiene el rol de administrador de la página
Código de programa en una pantalla de monitor

1. Menú persistente (persistent_menu)

El menú se sitúa a la izquierda del campo de entrada, el usuario pulsa el icono de «hamburguesa» y ve una lista de acciones. Esta es la navegación de nivel superior: «Ayuda», «Catálogo», «Soporte». Hasta 20 elementos, pero Meta recomienda limitarlo a cinco para una mejor experiencia de usuario.

Cada elemento es un objeto con type (postback o web_url), title (hasta 30 caracteres) y payload o url. Los emojis en los títulos funcionan, cópielos de getemoji.com.

Configuración del menú. Envíe POST a la API de Messenger Profile:

1curl -X POST -H "Content-Type: application/json" -d '{
2 "persistent_menu": [
3 {
4 "locale": "default",
5 "composer_input_disabled": false,
6 "call_to_actions": [
7 {
8 "type": "postback",
9 "title": "🆘 Help",
10 "payload": "HELP_PAYLOAD"
11 },
12 {
13 "type": "postback",
14 "title": "📰 News",
15 "payload": "LATEST_POSTS_PAYLOAD"
16 },
17 {
18 "type": "web_url",
19 "title": "🌐 Website",
20 "url": "https://yoursite.com/",
21 "webview_height_ratio": "full"
22 }
23 ]
24 }
25 ]
26}' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"

Respuesta exitosa: {"result": "success"}. El menú no aparecerá inmediatamente, la caché del lado del cliente tarda hasta 24 horas en actualizarse. Al probar, elimine la conversación e inicie una nueva para ver los cambios al instante.

Eliminación del menú. DELETE con el parámetro fields:

1curl -X DELETE "https://graph.facebook.com/v22.0/me/messenger_profile?fields=persistent_menu&access_token=PAGE_ACCESS_TOKEN"

Desactivación del compositor. Si el bot funciona solo mediante menú y botones, establezca "composer_input_disabled": true. El campo de entrada desaparecerá, el usuario interactúa exclusivamente a través de los elementos del menú y los botones de postback. Útil para bots de preguntas frecuentes y catálogos.

Localización. Añada objetos con la clave locale para cada idioma. El objeto con "locale": "default" es obligatorio, funciona como respaldo:

1{
2 "persistent_menu": [
3 {
4 "locale": "default",
5 "call_to_actions": [...]
6 },
7 {
8 "locale": "ru_RU",
9 "call_to_actions": [...]
10 }
11 ]
12}

Menú personalizado. A través del endpoint /me/custom_user_settings puede anular el menú para un usuario específico por su PSID. Límite: 10 llamadas por usuario cada 10 minutos. Tras eliminar el menú personalizado, se restaura el menú de la página.

2. Manejo de POSTBACK en PHP

Cuando un usuario hace clic en un elemento de menú con type: "postback", Facebook envía un evento messaging_postbacks a su webhook. En el cuerpo de la solicitud, un objeto postback incluye un campo payload que usted define al configurar el menú.

El manejador PHP lee el JSON entrante desde php://input, extrae el payload y mediante switch determina qué acción ejecutar. A continuación, el código actual para 2026 con el endpoint v22.0:

1<?php
2// Read incoming request from Facebook
3$input = json_decode(file_get_contents('php://input'), true);
4
5// Extract recipient and sender data
6$page_id = $input['entry'][0]['id'];
7$sender = $input['entry'][0]['messaging'][0]['sender']['id'];
8
9// Determine whether message or postback
10$message = $input['entry'][0]['messaging'][0]['message']['text'] ?? '';
11$postback = $input['entry'][0]['messaging'][0]['postback']['payload'] ?? '';
12
13if ($message || $postback) {
14
15 if ($message) {
16 $reply = 'Message received: ' . $message;
17 } else {
18 switch ($postback) {
19 case 'HELP_PAYLOAD':
20 $reply = 'You clicked the "Help" button. How can I help?';
21 break;
22
23 case 'LATEST_POSTS_PAYLOAD':
24 $reply = 'Here are fresh posts from this week.';
25 break;
26
27 default:
28 $reply = 'Action not recognized. Try again.';
29 }
30 }
31
32 // Form response
33 $responseJSON = json_encode([
34 'recipient' => ['id' => $sender],
35 'message' => ['text' => $reply],
36 ]);
37
38 $access_token = 'YOUR_PAGE_ACCESS_TOKEN';
39 $url = 'https://graph.facebook.com/v22.0/me/messages?access_token=' . $access_token;
40
41 // Send via cURL
42 $ch = curl_init($url);
43 curl_setopt($ch, CURLOPT_POST, 1);
44 curl_setopt($ch, CURLOPT_POSTFIELDS, $responseJSON);
45 curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
46 $result = curl_exec($ch);
47 curl_close($ch);
48}

Qué cambió. La versión de la API en la URL se elevó de v2.7 a v22.0. En lugar de ensamblar manualmente la cadena JSON, se usa json_encode(), lo que reduce la probabilidad de romper el escapado. Se agregó un bloque default en el switch para payloads no reconocidos. La construcción ?? (fusión de null) es más limpia que el antiguo isset() con ternarios.

Dónde ubicarlo. El código va en el archivo al que apunta la URL del webhook de la aplicación de Facebook. Generalmente es webhook.php en la raíz del sitio. Asegúrese de que el método GET en la misma URL maneje la verificación del webhook mediante hub_challenge.

Importante. Almacene el token de acceso en variables de entorno o en la configuración, no en el código. Para desarrollo local use un archivo .env con PAGE_ACCESS_TOKEN=....

3. Botón Comenzar (get_started)

El botón aparece en la pantalla de bienvenida en el primer contacto con la página. Al hacer clic, Facebook envía messaging_postbacks con el payload que usted especificó. Como respuesta, puede saludar al usuario por su nombre o mostrar un menú de botones.

Sin un botón «Comenzar» configurado, el menú persistente no se muestra; este es un requisito obligatorio de la plataforma.

Configuración:

1curl -X POST -H "Content-Type: application/json" -d '{
2 "get_started": {
3 "payload": "GET_STARTED_PAYLOAD"
4 }
5}' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"

El payload es una cadena arbitraria de hasta 1000 caracteres. En el manejador PHP, agregue case 'GET_STARTED_PAYLOAD' en el switch y devuelva un saludo personalizado.

Eliminación:

1curl -X DELETE "https://graph.facebook.com/v22.0/me/messenger_profile?fields=get_started&access_token=PAGE_ACCESS_TOKEN"

4. Texto de saludo (greeting)

El saludo se muestra en un chat vacío antes del primer mensaje. Admite las plantillas {{user_first_name}}, {{user_last_name}} y {{user_full_name}}. La personalización por nombre aumenta la interacción: el usuario percibe que el bot se dirige a él específicamente.

Configuración:

1curl -X POST -H "Content-Type: application/json" -d '{
2 "greeting": [
3 {
4 "locale": "default",
5 "text": "Hi, {{user_first_name}}! I am a helper bot. Ask a question or open the menu on the left."
6 }
7 ]
8}' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"

El texto de saludo también admite localización; agregue objetos con la clave locale.

Eliminación:

1curl -X DELETE "https://graph.facebook.com/v22.0/me/messenger_profile?fields=greeting&access_token=PAGE_ACCESS_TOKEN"

5. Ice Breakers: preguntas frecuentes antes del primer mensaje

Ice Breakers es una funcionalidad relativamente nueva de Messenger Platform. Son botones con preguntas predefinidas que aparecen antes de que el usuario haya escrito algo. Al hacer clic, se envía el texto en nombre del usuario y se inicia el diálogo.

Resulta conveniente para la incorporación: en lugar de una ventana vacía, la persona ve «¿Qué puedes hacer?», «¿Dónde está mi pedido?», «Contactar a soporte» e inicia el diálogo con un solo toque.

Configuración:

1curl -X POST -H "Content-Type: application/json" -d '{
2 "ice_breakers": [
3 {
4 "question": "What can you do?",
5 "payload": "ICE_CAPABILITIES"
6 },
7 {
8 "question": "Where is my order?",
9 "payload": "ICE_ORDER_STATUS"
10 }
11 ]
12}' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"

Hasta 4 preguntas, máximo 80 caracteres por pregunta. El payload se maneja en el mismo manejador PHP mediante switch.

⁉️🤔 Preguntas frecuentes

¿Por qué no aparece el menú aunque la solicitud devolvió éxito?

Razones principales: botón «Comenzar» no configurado, página no publicada, aplicación en modo desarrollo, usuario con versión antigua de Messenger o usando el navegador integrado de Facebook. El menú se almacena en caché localmente; la actualización del lado del cliente puede tardar hasta 24 horas. Para pruebas, elimine la conversación con el bot e inicie una nueva. Si el menú sigue sin verse, revise todos los puntos: página publicada, bot público, permiso pages_messaging obtenido, botón «Comenzar» configurado.

¿Se puede crear un menú anidado?

Sí, mediante el parámetro call_to_actions dentro de un elemento del menú. La anidación admite un solo nivel; el submenú se despliega al pulsar el elemento padre. El formato es similar al del menú principal: un arreglo de objetos con type, title y payload/url. El elemento padre con menú anidado no puede ser web_url, solo postback. La profundidad máxima es un nivel. Esta es una limitación de la plataforma y no se puede eludir.

¿En qué se diferencia el menú a nivel de usuario del menú a nivel de página?

El menú a nivel de página es único para todos los usuarios de la página. El menú a nivel de usuario, a través de /me/custom_user_settings, permite mostrar elementos distintos a diferentes personas: los usuarios nuevos ven «Qué puedo hacer», los recurrentes ven «Historial de pedidos». El menú a nivel de usuario se actualiza en tiempo real; el de página, con un retraso de hasta 24 horas. Límite: 10 llamadas por usuario cada 10 minutos. Al eliminar el menú personalizado, el menú de página se restablece automáticamente.

¿Cómo verificar que el webhook recibe el POSTBACK?

Active el modo de depuración en la configuración de la aplicación de Facebook y pulse un elemento del menú en el chat con el bot. Los registros mostrarán una entrada con el campo postback.payload. Alternativamente, añada error_log(print_r($input, true)) al inicio del manejador y revise los registros del servidor. Para desarrollo local use ngrok: crea un túnel hacia una URL HTTPS pública con un certificado válido que apunta a su localhost.

¿Hay que actualizar el código si cambia la versión de la API?

Sí, dos veces al año. Meta lanza una nueva versión de la API cada seis meses y desactiva las antiguas dos años después del lanzamiento de la versión que las reemplaza. Siga el Registro de cambios de Messenger Platform. En el código, solo reemplace el número de versión en la URL; la lógica de llamada rara vez cambia. Descontinuación programada: v19.0, enero de 2026; v20.0, mayo de 2026; v21.0, octubre de 2026. La versión v22.0 estará activa hasta mayo de 2027. Establezca la variable $api_version en el código.

Qué hacer con el bot después de la configuración: lista de verificación

El menú, el botón y el saludo son la base, no el final. Cuando la mecánica básica funciona, tres pasos convierten al bot de una tarjeta de presentación en una herramienta útil:

  • Conectar analíticas. Facebook Messenger Insights muestra aperturas, mensajes enviados y recibidos, y diálogos activos. Sin estos datos no sabrá qué elementos del menú se usan realmente.

  • Configurar una respuesta por defecto. Cuando un usuario escribe un texto no contemplado en el guion, el bot debe responder de forma significativa, no quedarse en silencio. Añada una rama predeterminada al manejador con una oferta para abrir el menú o contactar a una persona.

  • Actualizar el menú según la temporada. Promociones, nuevos productos, ventas de temporada: cambie los elementos del menú a lo largo del año. A través de la API del perfil de Messenger esto se hace con una sola solicitud POST.

Si el bot gestiona pedidos o recopila contactos, configure el dominio en whitelisted_domains para el correcto funcionamiento del WebView dentro de Messenger. Y no olvide los límites de frecuencia: 10 llamadas a la API del perfil cada 10 minutos por página. Encole las actualizaciones masivas del menú para miles de usuarios con pausas.