WhatsApp Flows 可改善並簡化企業蒐集顧客資料的流程。您的機構可輕鬆地透過顧客互動擷取結構化資訊,從而讓顧客在 WhatsApp 享有更優良的用戶體驗。WhatsApp Flows 特別適合用來蒐集開發潛在顧客資料、執行問卷調查、協助客戶預約服務、提交顧客問題和疑慮等等。
最令人雀躍的是,您可以為顧客提供所有這些選項,而無需構建複雜的應用程式和後端:您只需使用 WhatsApp 作為前端,並採用 Webhook 以 JSON 訊息形式擷取回應、處理資訊並檢索所需資料。
此教學導覽會以一間虛構公司為例,探索如何使用 Webhooks 在 WhatsApp 設定顧客問卷調查。此問卷調查將蒐集各類意見,例如顧客如何發掘到這間公司,以及他們喜歡的巡迴活動類型,以便此公司為現有及未來客戶提供更出色的服務。
若要使用此功能,請確保您具備下列條件:
若您想預覽此專案,可查看完整程式碼。
您可透過兩種方式來建立流程:使用流程建造工具用戶介面 或 Flows API。此教學導覽使用 Flows API 以程式輔助的方式來設定問卷調查。
若要建立流程以使用來自您伺服器的動態資料,您可以建立一個端點,將問卷調查連結至自家伺服器。您可使用此端點來控制各個流程畫面之間的導覽邏輯、填入來自您伺服器的流程資料,或根據用戶互動顯示/隱藏畫面上的元件。
本文的問卷調查流程範例並未使用任何端點,這是因為其與伺服器之間沒有交換動態資料。我們將使用聊天室 Webhook 來擷取問卷調查中的資訊。此外,您可以透過 WhatsApp 管理工具將流程附加至訊息範本。
首先,建立 Flask 應用程式以與 Flows API 互動。在終端上運行以下指令以建立虛擬環境。
python -m venv venv
接著,使用下方指令來啟用此環境。
source venv/bin/activate
接下來,使用以下指令安裝所需套件。
pip install requests flask python-dotenv
您需要使用 Flask 來建立路線並與 Flows API 互動、使用 requests 來傳送 HTTP 要求,並使用 python-dotenv 來載入環境變數。
現在,建立名為 .env 的環境檔案,並貼上下列資訊。
VERIFY_TOKEN = ACCESS_TOKEN = WHATSAPP_BUSINESS_ACCOUNT_ID = PHONE_NUMBER_ID =
您可以根據自家開發人員帳戶資訊來分配相應的值。VERIFY_TOKEN
可使用任何字串。WHATSAPP_BUSINESS_ACCOUNT_ID
和 PHONE_NUMBER_ID
變數是 Meta 為您帳戶自動產生的不重複識別碼。The ACCESS_TOKEN
會用於驗證和批准 API 要求。
若要從您 Meta 應用程式的管理中心存取此資訊,請在左側導覽面板中點擊「WhatsApp」>「API 設定」,如下方螢幕截圖所示。
最後,在同一個目錄中建立名為 main.py 的檔案,以包含用於建立流程和 Webhook 的 Python 邏輯。
若要構建流程,請先將下列套件加入 main.py
。
import os import uuid import requests from dotenv import load_dotenv from flask import Flask, request, make_response, json
接下來,將下列程式碼片段加入 main.py
以初始化變數。此程式碼片段亦可啟動 Flask 並呼叫 load_dotenv()
方法,以助載入變數。
app = Flask(__name__) load_dotenv() PHONE_NUMBER_ID = os.getenv('PHONE_NUMBER_ID') VERIFY_TOKEN = os.getenv('VERIFY_TOKEN') ACCESS_TOKEN = os.getenv('ACCESS_TOKEN') WHATSAPP_BUSINESS_ACCOUNT_ID = os.getenv('WHATSAPP_BUSINESS_ACCOUNT_ID') created_flow_id = "" messaging_url = f"https://graph.facebook.com/v18.0/{PHONE_NUMBER_ID}/messages" auth_header = {"Authorization": f"Bearer {ACCESS_TOKEN}"} messaging_headers = { "Content-Type": "application/json", "Authorization": f"Bearer {ACCESS_TOKEN}", }
接著,新增下列路線以處理建立流程之事宜。
@app.route("/create-flow", methods=["POST"]) def create_flow(): flow_base_url = ( f"https://graph.facebook.com/v18.0/{WHATSAPP_BUSINESS_ACCOUNT_ID}/flows" ) flow_creation_payload = {"name": "<FLOW-NAME>", "categories": '["SURVEY"]'} flow_create_response = requests.request( "POST", flow_base_url, headers=auth_header, data=flow_creation_payload ) try: global created_flow_id created_flow_id = flow_create_response.json()["id"] graph_assets_url = f"https://graph.facebook.com/v18.0/{created_flow_id}/assets" upload_flow_json(graph_assets_url) publish_flow(created_flow_id) print("FLOW CREATED!") return make_response("FLOW CREATED", 200) except: return make_response("ERROR", 500)
此函數會呼叫 Flows 端點 (flow_base_url)
,同時傳遞含有名稱和流程類別的裝載 (flow_creation_payload)
。可用於類別的值包括:SIGN_UP
、SIGN_IN
、APPOINTMENT_BOOKING
、LEAD_GENERATION
、CONTACT_US
、CUSTOMER_SUPPORT
、SURVEY
或 OTHER
。
使用您所需的名稱(例如 survey_flow)來替換 <FLOW-NAME>
。
程式碼建立流程後,便會擷取 created_flow_id
以用於上載其 JSON 主體。
使用這些內容建立 survey.json
檔案。此 JSON 會包含流程的結構。
接著,將下列程式碼貼至 main.py
檔案。
def upload_flow_json(graph_assets_url): flow_asset_payload = {"name": "flow.json", "asset_type": "FLOW_JSON"} files = [("file", ("survey.json", open("survey.json", "rb"), "application/json"))] res = requests.request( "POST", graph_assets_url, headers=auth_header, data=flow_asset_payload, files=files, ) print(res.json())
此函數會將 JSON 資料從 survey.json
上載至流程資產端點。
在下方程式碼片段中,當用戶觸發點擊操作時便會啟動 on-click-action
,以擷取裝載中的資料。"name": "complete"
欄位代表流程已完成並將關閉,且系統會將裝載傳送至您的 Webhook 伺服器。
... "on-click-action": { "name": "complete", "payload": { "source": "${form.source}", "tour_type": "${form.tour_type}", "tour_quality": "${form.tour_quality}", "decision_influencer": "${form.decision_influencer}", "tour_guides": "${form.tour_guides}", "aspects_enjoyed": "${form.aspects_enjoyed}", "improvements": "${form.improvements}", "recommend": "${form.recommend}", "return_booking": "${form.return_booking}" } } ...
裝載物件中的值可能會與流程元件(類似 HTML 表格中的元素名稱)或資料物件對應。與此等裝載值相關的鍵稱為「name」,其分配方式與您在程式語言中分配變數的方法類似。
data-source
元素亦包含充當值鍵的編號。程式碼會針對用戶選項傳送這些編號。舉例來說,若用戶為下方的 data-source
選擇 Likely
,則程式碼會傳送 1
。您收到資料後,便可配對資料來源。
... { "type": "RadioButtonsGroup", "required": true, "name": "return_booking", "data-source": [ { "id": "0", "title": "Very likely" }, { "id": "1", "title": "Likely" }, { "id": "2", "title": "Undecided" }, { "id": "3", "title": "Unlikely" }, { "id": "4", "title": "Very likely" } ] } ...
流程有一個包含 9 條選擇題的畫面,如下所示。
您可以查閱開發人員文件,探索各項 JSON 元素的詳細資訊。
接下來,將下方函數貼至 main.py
檔案,以加入流程發佈邏輯。已發佈的流程屬於正式版本,因此您無法再對其作出變更。
def publish_flow(flow_id): flow_publish_url = f"https://graph.facebook.com/v18.0/{flow_id}/publish" requests.request("POST", flow_publish_url, headers=auth_header)
此函數會調用發佈端點,同時傳遞流程編號。
將以下函數貼至 main.py
檔案,以將流程傳送至 WhatsApp 用戶。此函數會呼叫雲端 API 的訊息端點,同時傳遞裝載。
def send_flow(flow_id, recipient_phone_number): # Generate a random UUID for the flow token flow_token = str(uuid.uuid4()) flow_payload = json.dumps( { "type": "flow", "header": {"type": "text", "text": "Survey"}, "body": { "text": "Your insights are invaluable to us – please take a moment to share your feedback in our survey." }, "footer": {"text": "Click the button below to proceed"}, "action": { "name": "flow", "parameters": { "flow_message_version": "3", "flow_token": flow_token, "flow_id": flow_id, "flow_cta": "Proceed", "flow_action": "navigate", "flow_action_payload": {"screen": "SURVEY_SCREEN"}, }, }, } ) payload = json.dumps( { "messaging_product": "whatsapp", "recipient_type": "individual", "to": str(recipient_phone_number), "type": "interactive", "interactive": json.loads(flow_payload), } ) requests.request("POST", messaging_url, headers=messaging_headers, data=payload) print("MESSAGE SENT")
流程裝載會包含流程詳細資訊。action.parameters.flow_token
欄位會用於傳遞流程訊息的不重複識別碼;當流程完成後,系統便會將此識別碼從用戶端傳輸至您的 Webhook。在此教學導覽中,我們會使用隨機編號(uuid)。程式碼將 action.parameters.flow_action_payload.screen
設為 SURVEY_SCREEN
,後者是您希望在用戶點擊 action.parameters.flow_cta
時顯示的畫面之編號。
Webhook 邏輯簡明易懂。它有 2 個函數 webhook_get
和 webhook_post
,分別負責處理 GET
和 POST
要求。將 Webhook 加至您的 Meta 應用程式時,程式碼會使用 GET
要求。若要求成功,便會傳回要求的 hub.challenge
。POST
要求會用於將訊息裝載打印至終端。
@app.route("/webhook", methods=["GET"]) def webhook_get(): if ( request.args.get("hub.mode") == "subscribe" and request.args.get("hub.verify_token") == VERIFY_TOKEN ): return make_response(request.args.get("hub.challenge"), 200) else: return make_response("Success", 403)
POST
要求會用於擷取並處理訊息裝載。由於此程式碼僅用於處理訊息裝載,因此擷取任何其他裝載時會出現錯誤。因此,您可使用 messages
陳述式來檢查是否存在 if
主體。如果發現存在 messages
JSON 主體,僅當 messages
裝載中存在 text
主體時,您才需要執行另一項檢查以擷取發件人的手機號碼。
@app.route("/webhook", methods=["POST"]) def webhook_post(): # checking if there is a messages body in the payload if ( json.loads(request.get_data())["entry"][0]["changes"][0]["value"].get( "messages" ) ) is not None: """ checking if there is a text body in the messages payload so that the sender's phone number can be extracted from the message """ if ( json.loads(request.get_data())["entry"][0]["changes"][0]["value"][ "messages" ][0].get("text") ) is not None: user_phone_number = json.loads(request.get_data())["entry"][0]["changes"][ 0 ]["value"]["contacts"][0]["wa_id"] send_flow(created_flow_id, user_phone_number) else: flow_reply_processor(request) return make_response("PROCESSED", 200)
此外,您應使用下方名為 flow_reply_processor
的協助工具函數,從流程中擷取回覆並將其傳回給用戶。由於從 RadioButtonsGroups
擷取資料時流程回覆會包含用戶所選的選項編號,因此此函數會將編號與相應字串值配對。
def flow_reply_processor(request): flow_response = json.loads(request.get_data())["entry"][0]["changes"][0]["value"][ "messages" ][0]["interactive"]["nfm_reply"]["response_json"] flow_data = json.loads(flow_response) source_id = flow_data["source"] tour_type_id = flow_data["tour_type"] tour_quality_id = flow_data["tour_quality"] decision_influencer_id = flow_data["decision_influencer"] tour_guides_id = flow_data["tour_guides"] aspects_enjoyed_id = flow_data["aspects_enjoyed"] improvements_id = flow_data["improvements"] recommend_id = flow_data["recommend"] return_booking_id = flow_data["return_booking"] match source_id: case "0": source = "Online search" case "1": source = "Social media" case "2": source = "Referral from a friend/family" case "3": source = "Advertisement" case "4": source = "Others" match tour_type_id: case "0": tour_type = "Cultural tour" case "1": tour_type = "Adventure tour" case "2": tour_type = "Historical tour" case "3": tour_type = "Wildlife tour" match tour_quality_id: case "0": tour_quality = "1 - Poor" case "1": tour_quality = "2 - Below Average" case "2": tour_quality = "3 - Average" case "3": tour_quality = "4 - Good" case "4": tour_quality = "5 - Excellent" match decision_influencer_id: case "0": decision_influencer = "Positive reviews" case "1": decision_influencer = "Pricing" case "2": decision_influencer = "Tour destinations offered" case "3": decision_influencer = "Reputation" match tour_guides_id: case "0": tour_guides = "Knowledgeable and friendly" case "1": tour_guides = "Knowledgeable but not friendly" case "2": tour_guides = "Friendly but not knowledgeable" case "3": tour_guides = "Neither of the two" case "4": tour_guides = "I didn’t interact with them" match aspects_enjoyed_id: case "0": aspects_enjoyed = "Tourist attractions visited" case "1": aspects_enjoyed = "Tour guide's commentary" case "2": aspects_enjoyed = "Group dynamics/interaction" case "3": aspects_enjoyed = "Activities offered" match improvements_id: case "0": improvements = "Tour itinerary" case "1": improvements = "Communication before the tour" case "2": improvements = "Transportation arrangements" case "3": improvements = "Advertisement" case "4": improvements = "Accommodation quality" match recommend_id: case "0": recommend = "Yes, definitely" case "1": recommend = "Yes, but with reservations" case "2": recommend = "No, I would not" match return_booking_id: case "0": return_booking = "Very likely" case "1": return_booking = "Likely" case "2": return_booking = "Undecided" case "3": return_booking = "Unlikely" reply = ( f"Thanks for taking the survey! Your response has been recorded. This is what we received:\n\n" f"*How did you hear about our tour company?*\n{source}\n\n" f"*Which type of tour did you recently experience with us?*\n{tour_type}\n\n" f"*On a scale of 1 to 5, how would you rate the overall quality of the tour?*\n{tour_quality}\n\n" f"*What influenced your decision to choose our tour company?*\n{decision_influencer}\n\n" f"*How knowledgeable and friendly were our tour guides?*\n{tour_guides}\n\n" f"*What aspects of the tour did you find most enjoyable?*\n{aspects_enjoyed}\n\n" f"*Were there any aspects of the tour that could be improved?*\n{improvements}\n\n" f"*Would you recommend our tour company to a friend or family member?*\n{recommend}\n\n" f"*How likely are you to book another tour with us in the future?*\n{return_booking}" ) user_phone_number = json.loads(request.get_data())["entry"][0]["changes"][0][ "value" ]["contacts"][0]["wa_id"] send_message(reply, user_phone_number) After the extraction, the following send_message function sends the responses to the sender. def send_message(message, phone_number): payload = json.dumps( { "messaging_product": "whatsapp", "to": str(phone_number), "type": "text", "text": {"preview_url": False, "body": message}, } ) requests.request("POST", messaging_url, headers=messaging_headers, data=payload) print("MESSAGE SENT")
此函數會使用雲端 API 短訊端點來傳送回覆。
應用程式需要處於運作狀態,您才能在 Meta for Developers 主控台配置 Webhook。因此,請在您的終端使用指令 flask --app main run --port 5000
以執行程式碼。若一切設定正確,您應該會在終端看到 * Running on http://127.0.0.1:5000
訊息。
接下來,在您的終端執行指令 ngrok
http 5000
,以取得與您應用程式相應的網址。複製此連結。
在 Meta for Developers 主控台中,於左側導覽面板中的「WhatsApp」下方,點擊「配置」。
在「Webhook」小卡片中,點擊「編輯」。然後,在「回調網址」欄位中的對話框中,加入所複製的網址並附加 /webhook
。在「驗證憑證」欄位中,加入 .env
檔案的 TOKEN
變數所提供的憑證。
完成後,點擊「驗證並儲存」。對話框會隨即關閉。點擊「管理」並檢查「訊息」欄位。此資訊應與下方圖像類似,當中包含「回調網址」、「驗證憑證」下方的隱藏資訊,以及列於「Webhook」欄位下方的訊息。
Webhook 現已就緒。
在新終端實例中,執行下方的 cURL 指令以建立流程。
curl --location --request POST 'http://127.0.0.1:5000/create-flow'
在顯示 Webhook 輸出的終端實例中,您應該會看到一則如下所示的訊息。
當用戶向您的 WhatsApp 手機號碼傳送訊息時,對方所收到的回覆會是您的流程,如下方螢幕截圖中所示。
完成問卷調查後,用戶會收到包含其回答的回覆。
只要用戶向您的手機號碼傳送訊息,便會觸發流程。您可以針對自己的使用案例來自訂程式碼,以僅在特定情況下才傳送問卷調查流程,例如在用戶與您的企業聊天後才傳送此流程。
WhatsApp Flows 透過互動式介面蒐集結構化資料,例如上述虛構旅行社的問卷調查回覆,從而改善用戶體驗。此企業僅建立 Flask 應用程式、執行 Python 程式碼以透過 WhatsApp Flows API 產生並部署流程、設定 Webhook 以偵聽傳入訊息,以及運行應用程式,以蒐集問卷調查回覆。
透過 WhatsApp Flows,您的機構可以輕鬆快速地蒐集資料,進而提高顧客互動的完成率。使用類似程序來設定您自己的問卷調查、提供顧客支援、協助他們預約服務等等。
請即繼續探索 WhatsApp Flows 的無限潛力。立即試用。