
🤖 Konfiguracja stałego menu i przycisków dla bota Facebook Messenger
Uruchomił Pan bota w Facebook Messengerze, odpowiada on na wiadomości, ale czegoś brakuje. Użytkownik wchodzi na czat i widzi puste okno. Nie ma menu, podpowiedzi ani przycisku „Rozpocznij". Pierwsze dotknięcie i cisza. Ludzie po prostu nie rozumieją, co Pana bot potrafi.
Trzy komponenty przekształcają bezimiennego bota w czytelny interfejs: stałe menu z szybkimi akcjami, przycisk „Rozpocznij" do pierwszego kontaktu oraz tekst powitania, który wita użytkownika po imieniu. Dawniej wszystko to konfigurowało się przez przestarzały parametr thread_settings. Obecnie Meta przeniosła zarządzanie na jednolity Messenger Profile API, a stare wywołania cURL z tutoriali z 2017 roku po prostu nie działają.
W tym poradniku przedstawiam aktualne podejście do konfiguracji stałego menu, przycisku Get Started oraz powitania przez Messenger Profile API. Z działającymi przykładami cURL i PHP-owym handlerem POSTBACK, który rozróżnia kliknięcia w pozycje menu.
💡 Szybki przegląd:
- Skonfigurować stałe menu przez
persistent_menuw Messenger Profile API: do 20 pozycji, lokalizacja, wyłączenie kompozytora - Dodać przycisk „Rozpocznij" przez parametr
get_started: przy pierwszym dotknięciu Facebook zwraca PSID użytkownika - Ustawić tekst powitania przez
greeting: szablony{{user_first_name}}działają również w 2026 roku - Napisać PHP-owy handler POSTBACK: switch po
payloadrozróżnia, którą pozycję menu kliknął użytkownik - Uwzględnić limity: 10 wywołań Profile API na 10 minut na stronę, do 24 godzin na odświeżenie cache menu
Co się zmieniło: Thread Settings → Messenger Profile API
Do 2020 roku menu, przycisk „Rozpocznij" i powitanie konfigurowało się osobnymi żądaniami POST do endpointu /me/thread_settings. Typ ustawienia podawało się w treści przez setting_type: call_to_actions dla menu, greeting dla powitania. W 2026 roku to podejście nie działa, endpoint został usunięty z dokumentacji.
Obecnie wszystkie właściwości bota ustawia się przez Messenger Profile API, jeden endpoint:
1 POST https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN
Treść żądania to obiekt JSON z potrzebnymi właściwościami: persistent_menu dla menu, get_started dla przycisku „Rozpocznij", greeting dla powitania, ice_breakers i whitelisted_domains. Można je przesłać razem lub osobno. Profil jest nadpisywany, nie należy przesyłać właściwości, jeśli nie chce Pan jej zmieniać.
Oficjalna dokumentacja: Persistent Menu na Meta for Developers. Wersja API jest aktualizowana co pół roku, proszę sprawdzać aktualną przez Changelog.
Wymagania do działania menu, aktualne na czerwiec 2026:
- Strona na Facebooku jest opublikowana, bot jest przełączony w tryb „public" w ustawieniach aplikacji
- Aplikacja ma uprawnienie
pages_messaging - Użytkownik uruchamia Messenger w wersji 106 lub wyższej
- Przycisk „Rozpocznij" jest skonfigurowany (bez niego menu się nie wyświetla)
- Ma Pan rolę administratora strony

1. Stałe menu (persistent_menu)
Menu znajduje się po lewej stronie pola wprowadzania, użytkownik klika ikonę „hamburger" i widzi listę akcji. To nawigacja najwyższego poziomu: „Pomoc", „Katalog", „Wsparcie". Do 20 pozycji, ale Meta zaleca ograniczenie się do pięciu dla lepszego UX.
Każda pozycja to obiekt z type (postback lub web_url), title (do 30 znaków) oraz albo payload, albo url. Emoji w tytułach działają, proszę kopiować z getemoji.com.
Ustawianie menu. Proszę wysłać POST do Messenger Profile API:
1 curl -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": "🆘 Помощь", 10 "payload": "HELP_PAYLOAD" 11 }, 12 { 13 "type": "postback", 14 "title": "📰 Новости", 15 "payload": "LATEST_POSTS_PAYLOAD" 16 }, 17 { 18 "type": "web_url", 19 "title": "🌐 Сайт", 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"
Pomyślna odpowiedź: {"result": "success"}. Menu nie pojawi się od razu, cache po stronie klienta odświeża się do 24 godzin. Podczas testowania proszę usunąć konwersację i zacząć od nowa, aby zobaczyć zmiany natychmiast.
Usuwanie menu. DELETE z parametrem fields:
1 curl -X DELETE "https://graph.facebook.com/v22.0/me/messenger_profile?fields=persistent_menu&access_token=PAGE_ACCESS_TOKEN"
Wyłączanie kompozytora. Jeśli bot działa tylko przez menu i przyciski, proszę ustawić "composer_input_disabled": true. Pole wprowadzania zniknie, użytkownik wchodzi w interakcję wyłącznie przez pozycje menu i przyciski postback. Przydatne dla botów FAQ i katalogów.
Lokalizacja. Proszę dodać obiekty z kluczem locale dla każdego języka. Obiekt z "locale": "default" jest obowiązkowy, działa jako fallback:
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 }
Menu użytkownika. Przez endpoint /me/custom_user_settings można nadpisać menu dla konkretnego użytkownika po PSID. Limit: 10 wywołań na użytkownika na 10 minut. Po usunięciu menu użytkownika przywracane jest menu strony.
2. Obsługa POSTBACK w PHP
Gdy użytkownik kliknie pozycję menu z type: "postback", Facebook wysyła na Pana webhook zdarzenie messaging_postbacks. W treści żądania znajduje się obiekt postback z polem payload, które Pan zdefiniował podczas konfiguracji menu.
Procedura obsługi w PHP odczytuje przychodzący JSON z php://input, wyodrębnia payload i za pomocą switch określa, którą akcję wykonać. Poniżej aktualny kod na rok 2026 z endpointem v22.0:
1 <?php 2 // Читаем входящий запрос от Facebook 3 $input = json_decode(file_get_contents('php://input'), true); 4 5 // Извлекаем данные получателя и отправителя 6 $page_id = $input['entry'][0]['id']; 7 $sender = $input['entry'][0]['messaging'][0]['sender']['id']; 8 9 // Определяем, сообщение или postback 10 $message = $input['entry'][0]['messaging'][0]['message']['text'] ?? ''; 11 $postback = $input['entry'][0]['messaging'][0]['postback']['payload'] ?? ''; 12 13 if ($message || $postback) { 14 15 if ($message) { 16 $reply = 'Получено сообщение: ' . $message; 17 } else { 18 switch ($postback) { 19 case 'HELP_PAYLOAD': 20 $reply = 'Вы нажали кнопку «Помощь». Чем могу помочь?'; 21 break; 22 23 case 'LATEST_POSTS_PAYLOAD': 24 $reply = 'Вот свежие публикации за эту неделю.'; 25 break; 26 27 default: 28 $reply = 'Действие не распознано. Попробуйте ещё раз.'; 29 } 30 } 31 32 // Формируем ответ 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 // Отправляем через 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 }
Co się zmieniło. Wersję API w URL podniesiono z v2.7 do v22.0. Zamiast ręcznego składania ciągu JSON stosowane jest json_encode(), co zmniejsza ryzyko popsucia escapowania. Dodano blok default w switch dla nierozpoznanych payloadów. Konstrukcja ?? (null coalescing) jest czystsza niż stare isset() z operatorami trójargumentowymi.
Gdzie umieścić. Kod trafia do pliku, na który wskazuje webhook URL aplikacji Facebook. Zazwyczaj jest to webhook.php w katalogu głównym witryny. Proszę się upewnić, że metoda GET na ten sam adres URL obsługuje weryfikację webhooka przez hub_challenge.
Ważne. Access token proszę przechowywać w zmiennych środowiskowych lub konfiguracji, nie w kodzie. Do pracy lokalnej proszę używać pliku .env z PAGE_ACCESS_TOKEN=....
3. Przycisk „Rozpocznij" (get_started)
Przycisk pojawia się na ekranie powitalnym podczas pierwszego kontaktu użytkownika ze stroną. Po kliknięciu Facebook wysyła messaging_postbacks z payloadem, który Pan wskazał. W odpowiedzi można przywitać użytkownika po imieniu lub pokazać menu z przycisków.
Bez skonfigurowanego przycisku „Rozpocznij" stałe menu nie jest wyświetlane, jest to obowiązkowy wymóg platformy.
Instalacja:
1 curl -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"
Payload, dowolny ciąg do 1000 znaków. W procedurze obsługi PHP proszę dodać case 'GET_STARTED_PAYLOAD' w switch i zwrócić spersonalizowane powitanie.
Usunięcie:
1 curl -X DELETE "https://graph.facebook.com/v22.0/me/messenger_profile?fields=get_started&access_token=PAGE_ACCESS_TOKEN"
4. Tekst powitania (greeting)
Powitanie jest wyświetlane w pustym czacie przed pierwszą wiadomością. Obsługuje szablony {{user_first_name}} {{user_last_name}} i {{user_full_name}}. Personalizacja za pomocą imienia zwiększa zaangażowanie, użytkownik widzi, że bot zwraca się bezpośrednio do niego.
Instalacja:
1 curl -X POST -H "Content-Type: application/json" -d '{ 2 "greeting": [ 3 { 4 "locale": "default", 5 "text": "Привет, {{user_first_name}}! Я бот-помощник. Задайте вопрос или откройте меню слева." 6 } 7 ] 8 }' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"
Tekst powitania obsługuje również lokalizację, proszę dodawać obiekty z kluczem locale.
Usunięcie:
1 curl -X DELETE "https://graph.facebook.com/v22.0/me/messenger_profile?fields=greeting&access_token=PAGE_ACCESS_TOKEN"
5. Ice Breakers: częste pytania przed pierwszą wiadomością
Ice Breakers to stosunkowo nowa funkcja Messenger Platform. Są to przyciski z gotowymi pytaniami, które pojawiają się, zanim użytkownik cokolwiek napisze. Kliknięcie wysyła tekst w imieniu użytkownika i uruchamia dialog.
Jest to wygodne przy wdrażaniu: zamiast pustego okna osoba widzi „Co potrafisz?", „Gdzie jest moje zamówienie?", „Skontaktuj się z pomocą techniczną" i rozpoczyna dialog jednym dotknięciem.
Instalacja:
1 curl -X POST -H "Content-Type: application/json" -d '{ 2 "ice_breakers": [ 3 { 4 "question": "Что ты умеешь?", 5 "payload": "ICE_CAPABILITIES" 6 }, 7 { 8 "question": "Где мой заказ?", 9 "payload": "ICE_ORDER_STATUS" 10 } 11 ] 12 }' "https://graph.facebook.com/v22.0/me/messenger_profile?access_token=PAGE_ACCESS_TOKEN"
Do 4 pytań, maksymalnie 80 znaków na pytanie. Payload jest obsługiwany w tej samej procedurze PHP przez switch.
⁉️🤔 Często zadawane pytania
Dlaczego menu nie pojawia się, mimo że zapytanie zwróciło success?
Główne przyczyny: nieskonfigurowany przycisk „Rozpocznij", nieopublikowana strona, aplikacja w trybie deweloperskim, użytkownik korzysta ze starej wersji Messengera lub Facebook Mobile Browser. Menu jest lokalnie buforowane, aktualizacja po stronie klienta trwa do 24 godzin. W celu przetestowania proszę usunąć konwersację z botem i rozpocząć ją od nowa. Jeśli menu nadal nie jest widoczne, proszę sprawdzić wszystkie punkty: strona jest opublikowana, bot jest publiczny, uzyskano uprawnienie
pages_messaging, przycisk „Rozpocznij" jest skonfigurowany.
Czy można utworzyć menu zagnieżdżone?
Tak, poprzez parametr
call_to_actionswewnątrz elementu menu. Zagnieżdżanie obsługuje jeden poziom, podmenu rozwija się po kliknięciu elementu nadrzędnego. Format jest analogiczny do menu głównego: tablica obiektów ztype,titleorazpayload/url. Element nadrzędny z zagnieżdżonym menu nie może być typuweb_url, tylkopostback. Maksymalna głębokość to jeden poziom. Jest to ograniczenie platformy, nie można go obejść.
Czym menu na poziomie użytkownika różni się od menu na poziomie strony?
Menu na poziomie strony jest jedno dla wszystkich użytkowników strony. Menu na poziomie użytkownika poprzez
/me/custom_user_settingspozwala pokazywać różne elementy różnym osobom: nowym, „Co potrafię", powracającym, „Historia zamówień". Menu na poziomie użytkownika aktualizuje się w czasie rzeczywistym, menu strony, z opóźnieniem do 24 godzin. Limit: 10 wywołań na użytkownika w ciągu 10 minut. Po usunięciu menu użytkownika automatycznie przywracane jest menu strony.
Jak sprawdzić, czy webhook odbiera POSTBACK?
Proszę włączyć tryb debugowania w ustawieniach aplikacji Facebook i kliknąć element menu w czacie z botem. W logach pojawi się wpis z polem
postback.payload. Alternatywnie można dodaćerror_log(print_r($input, true))na początku handlera i obserwować logi serwera. Do lokalnego developmentu proszę używać ngrok: udostępnia on publiczny adres HTTPS na Pana/Pani localhost z ważnym certyfikatem.
Czy trzeba aktualizować kod, gdy zmienia się wersja API?
Tak, dwa razy w roku. Meta wydaje nową wersję API co pół roku, stare wyłącza 2 lata po premierze następcy. Proszę śledzić Changelog Messenger Platform. W kodzie wystarczy zmienić numer wersji w adresie URL, logika wywołań zmienia się rzadko. Planowane wyłączenia: v19.0, styczeń 2026, v20.0, maj 2026, v21.0, październik 2026. Wersja v22.0 jest aktywna do maja 2027. Proszę ustawić w kodzie zmienną
$api_version.
Co robić z botem po konfiguracji: checklista
Menu, przycisk i powitanie to fundament, a nie finał. Gdy podstawowa mechanika działa, trzy kroki przekształcają bota z wizytówki w użyteczne narzędzie:
Proszę podłączyć analitykę. Facebook Messenger Insights pokazuje otwarcia, wysłane i odebrane wiadomości, aktywne dialogi. Bez tych danych nie dowiedzą się Państwo, z których elementów menu użytkownicy rzeczywiście korzystają.
Proszę skonfigurować odpowiedź fallback. Gdy użytkownik wpisze tekst nieprzewidziany w scenariuszu, bot powinien odpowiedzieć sensownie, a nie milczeć. Proszę dodać w handlerze gałąź default z propozycją otwarcia menu lub kontaktu z człowiekiem.
Proszę aktualizować menu sezonowo. Promocje, nowe produkty, wyprzedaże świąteczne, proszę zmieniać elementy menu w ciągu roku. Poprzez Messenger Profile API robi się to jednym żądaniem POST.
Jeśli bot obsługuje zamówienia lub zbiera kontakty, proszę skonfigurować domenę w whitelisted_domains dla poprawnego działania WebView wewnątrz Messengera. Proszę też nie zapominać o limitach częstotliwości: 10 wywołań Profile API w ciągu 10 minut na stronę. Wsadowe aktualizacje menu dla tysięcy użytkowników proszę umieszczać w kolejce z opóźnieniem.



