What is a Persistent Menu?
A Persistent Menu allows you to display a permanent menu with your business's main actions, such as business hours, store locations, products, or other frequently used options. The menu is always visible during a conversation with your Facebook Messenger bot.

Supported Button Types
The Persistent Menu supports the following button types:
-
URL buttons (
web_url) -
Callback buttons (
postback)
Create a Persistent Menu
Use the following function to create a Persistent Menu for a Facebook page:
response = fb_set_persistent_menu(group_id, buttons)
Parameters
| Parameter | Description |
|---|---|
| group_id | Facebook Bot ID. You can find it in the Channel section of your MaviBot project. |
| buttons | Dictionary describing the menu buttons. |
Button Dictionary Structure
buttons = {
"default": [
["postback", "Button 1", "callback_text 1"],
["postback", "Button 2", "callback_text 2"],
["web_url", "Website", "https://mavibot.ai/"]
]
}
The default key is required. It defines the buttons displayed for users whose locale does not have a custom menu.
Each button is described by an array:
["button_type", "Button text", "Value"]
Supported Button Formats
Callback Button
["postback", "Button text", "callback_text"]
| Value | Description |
|---|---|
| postback | Button type. |
| Button text | Text displayed on the button. |
| callback_text | Text sent to the bot when the button is clicked. |
URL Button
["web_url", "Button text", "https://example.com"]
| Value | Description |
|---|---|
| web_url | Button type. |
| Button text | Text displayed on the button. |
| URL | Website opened when the button is clicked. |
Localization
You can display different menus depending on the user's locale.
Simply add additional keys to the button dictionary.
Example:
buttons = {
"default": [
["postback", "Button 1", "callback_text 1"],
["postback", "Button 2", "callback_text 2"],
["web_url", "Website", "https://mavibot.ai/"]
],
"en_EN": [
["postback", "Button", "callback_text 1"],
["postback", "Button 2", "callback_text 2"],
["web_url", "Website", "https://mavibot.ai/"]
]
}
In this example, users with the en_EN locale will receive a different menu.
Supported Locales
af_ZA, ar_AR, as_IN, az_AZ, be_BY, bg_BG, bn_IN, br_FR, bs_BA, ca_ES,
cb_IQ, co_FR, cs_CZ, cx_PH, cy_GB, da_DK, de_DE, el_GR, en_GB, en_UD,
en_US, es_ES, es_LA, et_EE, eu_ES, fa_IR, ff_NG, fi_FI, fo_FO, fr_CA,
fr_FR, fy_NL, ga_IE, gl_ES, gn_PY, gu_IN, ha_NG, he_IL, hi_IN, hr_HR,
hu_HU, hy_AM, id_ID, is_IS, it_IT, ja_JP, ja_KS, jv_ID, ka_GE, kk_KZ,
km_KH, kn_IN, ko_KR, ku_TR, lt_LT, lv_LV, mg_MG, mk_MK, ml_IN, mn_MN,
mr_IN, ms_MY, mt_MT, my_MM, nb_NO, ne_NP, nl_BE, nl_NL, nn_NO, or_IN,
pa_IN, pl_PL, ps_AF, pt_BR, pt_PT, qz_MM, ro_RO, ru_RU, rw_RW, sc_IT,
si_LK, sk_SK, sl_SI, so_SO, sq_AL, sr_RS, sv_SE, sw_KE, sz_PL, ta_IN,
te_IN, tg_TJ, th_TH, tl_PH, tr_TR, tz_MA, uk_UA, ur_PK, uz_UZ, vi_VN,
zh_CN, zh_HK, zh_TW
Create a Persistent Menu for a Specific User
To create a menu that is visible only to the user for whom the function is called, pass 1 as the third parameter.
response = fb_set_persistent_menu(group_id, buttons, 1)
Note
User-level Persistent Menus are updated immediately.
Page-level Persistent Menus may take up to 24 hours to update.
Facebook also limits user-level menu updates to 10 requests per user every 10 minutes.
Disable the Composer
You can disable the Messenger composer so that users can interact with the bot only through the Persistent Menu.
This is useful when the bot should only allow predefined actions.
Disable the Composer for All Users
response = fb_set_persistent_menu(group_id, buttons, "", 1)
Disable the Composer for a Specific User
response = fb_set_persistent_menu(group_id, buttons, 1, 1)
Parameters
| Parameter | Description |
|---|---|
| group_id | Facebook Bot ID. |
| buttons | Button dictionary. |
| 3rd parameter | Set to 1 to apply the menu only to the current user. Leave empty to apply it to the page. |
| 4th parameter | Set to 1 to disable the Messenger composer. |
Return Values
If the function completes successfully:
{"result":"success"}
Otherwise, an error description is returned.
Example:
Error parse buttons data
or
{
"error": {
"message": "(#100) param persistent_menu[0][call_to_actions] must be non-empty.",
"type": "OAuthException",
"code": 100,
"fbtrace_id": "AJtVczu7TEJJxbMfnO"
}
}
Examples
Create a Menu for All Users
buttons = {
"default": [
["postback", "Button 1", "callback_text 1"],
["postback", "Button 2", "callback_text 2"],
["web_url", "Website", "https://mavibot.ai/"]
],
"en_EN": [
["postback", "Button", "callback_text 1"],
["postback", "Button 2", "callback_text 2"],
["web_url", "Website", "https://mavibot.ai/"]
]
}
response = fb_set_persistent_menu("123456789", buttons)
Create a Menu for All Users and Disable the Composer
buttons = {
"default": [
["postback", "Button 1", "callback_text 1"],
["postback", "Button 2", "callback_text 2"],
["web_url", "Website", "https://mavibot.ai/"]
],
"en_EN": [
["postback", "Button", "callback_text 1"],
["postback", "Button 2", "callback_text 2"],
["web_url", "Website", "https://mavibot.ai/"]
]
}
response = fb_set_persistent_menu("123456789", buttons, "", 1)
Create a Menu for the Current User
buttons = {
"default": [
["postback", "Button 1", "callback_text 1"],
["postback", "Button 2", "callback_text 2"],
["web_url", "Website", "https://mavibot.ai/"]
]
}
response = fb_set_persistent_menu("123456789", buttons, 1)
Create a User Menu and Disable the Composer
buttons = {
"default": [
["postback", "Button 1", "callback_text 1"],
["postback", "Button 2", "callback_text 2"],
["web_url", "Website", "https://mavibot.ai/"]
]
}
response = fb_set_persistent_menu("123456789", buttons, 1, 1)
Delete a Persistent Menu
Delete the Page-Level Menu
response = fb_delete_persistent_menu(group_id)
Successful response:
{"result":"success"}
Possible error:
Bot not found
Delete a User-Level Menu
response = fb_delete_persistent_menu(group_id, 1)
Successful response:
{"result":"success"}
Possible error:
Bot not found