WhatsApp Flows 优化并简化了企业收集客户数据的方式。您的企业可以从与客户的互动中轻松获取结构化信息,而客户则可在 WhatsApp 中获得良好的用户体验。WhatsApp Flows 非常适合用来收集潜在客户数据、开展调查、帮助客户预约、提交客户问题和疑虑等等。
最重要的是,您无需构建复杂的应用程序和后端,即可为客户提供所有这些选项:只需将 WhatsApp 用作前端,然后使用 Webhook 捕获 JSON 消息形式的响应、处理信息和检索所需数据即可。
本教程以一家虚构的公司为例,探讨如何使用 Webhooks 在 WhatsApp 上创建客户调查问卷。调查问卷将收集客户的反馈信息,例如客户是如何发现公司的,以及他们偏爱哪种类型的旅行,这样公司便可更好地为新老顾客提供服务。
要继续操作,请确保您拥有以下内容:
如果您想预览项目,可以查看完整代码。
创建 Flow 有两种方法:使用 Flow Builder UI 或 Flows API。本教程使用 Flows API 以编程方式创建调查问卷。
要构建使用服务器中动态数据的 Flow,您可以创建一个端点,该端点将调查问卷连接到您自己的服务器。您可以使用端点控制多个 Flow 屏幕之间的导航逻辑,从您的服务器填充 Flow 数据,或根据用户互动情况在屏幕上显示/隐藏组件。
将要讨论的调查问卷 Flow 示例不使用任何端点,因为该调查问卷 Flow 与服务器之间没有动态数据交换。您将使用聊天 Webhook 来捕获调查问卷中的信息。此外,您可以通过 WhatsApp 管理工具将 Flows 附加到消息模板。
首先,创建一个 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 的文件,以包含用于创建 Flows 和 Webhook 的 Python 逻辑。
要创建 Flow,首先需要将以下项目包添加到 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}", }
然后,添加以下路由来处理 Flow 创建操作。
@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 类别的有效负载 (flow_creation_payload)
。此类别的可用值包括:SIGN_UP
、SIGN_IN
、APPOINTMENT_BOOKING
、LEAD_GENERATION
、CONTACT_US
、CUSTOMER_SUPPORT
、SURVEY
或 OTHER
。
将 <FLOW-NAME>
替换为您所需的名称 — 例如,survey_flow。
代码创建 Flow 后,它会提取 created_flow_id
以上传其 JSON 正文。
使用这些内容创建一个 survey.json
文件。JSON 包含 Flow 的结构。
然后,将以下代码粘贴到 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
上传到 Flow 资产端点。
在下面的代码片段中,当用户触发点击操作时,该代码片段会启动 on-click-action
,捕获有效负载中的数据。"name": "complete"
字段表示 Flow 已完成。它将关闭,有效负载将被发送到您的 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}" } } ...
有效负载对象内的值可能对应于 Flow 组件(类似于 HTML 表单中的元素名称)或数据对象。与这些有效负载值关联的键称为名称,类似于在编程语言中分配变量的方式。
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" } ] } ...
该 Flow 有一个包含九道单选题的屏幕,如下所示。
您可以阅读开发者文档,详细了解 JSON 元素。
接下来,将以下函数粘贴到 main.py
文件中以添加发布 Flow 的逻辑。已发布的 Flow 处于可投入使用状态,因此您将无法进行后续更改。
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)
该函数在传入 Flow 编号时将调用发布端点。
将以下函数粘贴到 main.py
文件中,以便将 Flow 发送给 WhatsApp 用户。该函数在传入 Flow 有效负载时将调用云端 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")
Flow 有效负载包含 Flow 详细信息。您可以借助 action.parameters.flow_token
字段传递 Flow 消息的唯一标识符,该消息将在 Flow 完成后从客户端传输到您的 Webhook。在本教程中,您将使用随机编号 (uuid)。该代码将 action.parameters.flow_action_payload.screen
设置为 SURVEY_SCREEN
,这是您希望用户点击 action.parameters.flow_cta
后显示的屏幕的编号。
Webhook 逻辑非常简单。它有两个函数: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
请求将提取并处理消息有效负载。由于代码只满足消息有效负载,因此它在捕获任何其他有效负载时会引发错误。出于这一原因,您可以使用 if
语句来检查是否存在 messages
正文。检查 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
的辅助函数从 Flow 中提取响应并将其发回给用户。由于从 RadioButtonsGroups
捕获数据时 Flow 响应包含所选选项编号,因此该函数会将此编号与相应的字符串值进行匹配。
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 开发者控制台中配置 Webhook 之前,需要运行应用程序。因此,请在终端中使用命令 flask --app main run --port 5000
来运行代码。如果一切设置正确,您应在终端中看到 * Running on http://127.0.0.1:5000
消息。
接下来,在终端中运行命令 ngrok
http 5000
以获取映射到您应用程序的网址。复制该链接。
在 Meta 开发者控制台左侧导航窗口中的 WhatsApp 下方,点击配置。
在 Webhook 图卡中,点击编辑。然后,在回调网址字段的对话框中,添加复制的网址并附加 /webhook
。在验证口令字段中,添加 .env
文件的 TOKEN
变量中的口令。
完成后,点击验证并保存。对话框将关闭。点击管理并检查消息字段。此信息应与下图所示内容类似,其中包含回调网址、验证口令下方的隐藏信息,以及 Webhook 字段下方列出的消息。
Webhook 现已准备就绪。
在新的终端实例中,运行下方的 cURL 命令来创建 Flow。
curl --location --request POST 'http://127.0.0.1:5000/create-flow'
在显示 Webhook 输出的终端实例中,您应该会看到一条类似于下图所示的消息。
当用户给您的 WhatsApp 电话号码发消息时,他们会收到 Flow 作为回复,如下方截图所示。
完成调查问卷后,他们会收到包含答案的回复。
用户给您电话号码发送的任何消息都将触发 Flow。对于您的用例,可自定义代码以仅在特定情况下发送调查问卷 Flow,例如在用户与您聊天之后。
WhatsApp Flows 可通过互动界面收集结构化数据(例如假设的旅游公司的调查问卷回复),以此来增强用户体验。这家公司只需创建一个 Flask 应用,使用 Python 代码来生成,并通过 WhatsApp Flows API 部署 Flows,设置 Webhook 以监听传入消息,并运行应用程序以启用调查问卷回复收集功能。
WhatsApp Flows 可让您的组织快速、轻松地收集数据,这有助于提高客户互动的完成率。您可以使用类似流程创建自己的调查问卷、提供客户支持、帮助他们进行预约等等。
继续探索 WhatsApp Flows 的潜力。马上试试。