WhatsApp Flows mengoptimalkan dan menyederhanakan cara bisnis Anda mengumpulkan data pelanggan. Organisasi Anda bisa dengan mudah mendapatkan informasi terstruktur dari interaksi dengan pelanggan, yang nantinya, akan merasakan pengalaman pengguna yang positif di WhatsApp. WhatsApp Flows sangat cocok digunakan untuk mengumpulkan data penciptaan prospek, melakukan survei, membantu klien memesan janji temu, mengumpulkan pertanyaan dan masalah pelanggan, serta banyak lagi lainnya.
Istimewanya lagi, Anda bisa menawarkan semua opsi ini kepada pelanggan Anda tanpa harus membuat aplikasi yang rumit dan back end: Cukup gunakan WhatsApp sebagai front end dan gunakan webhook untuk mendapatkan tanggapan sebagai pesan JSON, memproses informasi, dan mengambil data yang Anda butuhkan.
Dengan menggunakan perusahaan fiktif sebagai contoh, tutorial ini akan menjelaskan cara menyiapkan survei pelanggan di WhatsApp menggunakan webhook. Survei ini akan mengumpulkan masukan seperti cara pelanggan menemukan perusahaan dan jenis tur pilihan mereka agar perusahaan bisa melayani klien saat ini dan mendatang dengan lebih baik.
Untuk melakukannya, pastikan Anda memiliki beberapa hal berikut:
Jika ingin melihat pratinjau proyek, Anda bisa melihat kode lengkapnya.
Ada dua cara untuk membuat Flow: menggunakan Flow Builder UI atau Flows API. Tutorial kali ini akan menggunakan Flows API untuk menyiapkan survei secara terprogram.
Untuk membuat Flow yang menggunakan data dinamis dari server Anda, Anda bisa membuat endpoint yang menghubungkan survei ke server milik Anda. Dengan menggunakan endpoint, Anda bisa mengontrol logika navigasi antara layar Flow, mengisi data Flow dari server Anda, atau menampilkan/menyembunyikan komponen di layar berdasarkan interaksi pengguna.
Contoh Flow survei yang akan dibahas tidak menggunakan endpoint apa pun karena tidak ada pertukaran data dinamis antara survei ini dan server. Anda akan menggunakan webhook obrolan untuk mendapatkan informasi dari survei. Selain itu, Anda bisa melampirkan Flows ke template pesan di Pengelola WhatsApp.
Pertama, buat aplikasi Flask untuk berinteraksi dengan Flows API. Jalankan perintah berikut di terminal Anda untuk membuat lingkungan virtual.
python -m venv venv
Lalu, gunakan perintah di bawah ini untuk mengaktifkan lingkungan tersebut.
source venv/bin/activate
Selanjutnya, gunakan perintah berikut untuk menginstal paket yang diperlukan.
pip install requests flask python-dotenv
Anda akan menggunakan Flask untuk membuat rute dan berinteraksi dengan Flows API, meminta untuk mengirimkan permintaan HTTP, dan python-dotenv untuk memuat variabel lingkungan.
Sekarang, buat file lingkungan bernama .env dan tempel informasi berikut.
VERIFY_TOKEN = ACCESS_TOKEN = WHATSAPP_BUSINESS_ACCOUNT_ID = PHONE_NUMBER_ID =
Tetapkan nilai berdasarkan informasi akun developer Anda. Anda bisa menggunakan string apa pun untuk VERIFY_TOKEN
. Variabel WHATSAPP_BUSINESS_ACCOUNT_ID
dan PHONE_NUMBER_ID
adalah pengidentifikasi unik akun Anda yang dibuat otomatis oleh Meta. The ACCESS_TOKEN
diperlukan untuk mengautentikasi dan mengotorisasi permintaan API.
Untuk mengakses informasi ini dari dasbor aplikasi Meta Anda, klik WhatsApp > Penyiapan API di panel navigasi kiri seperti pada cuplikan layar di bawah ini.
Terakhir, di direktori yang sama, buat file bernama main.py untuk menampung logika Python dalam membuat Flows dan webhook.
Untuk membuat Flow, pertama-tama, tambahkan paket ke main.py
.
import os import uuid import requests from dotenv import load_dotenv from flask import Flask, request, make_response, json
Selanjutnya, tambahkan snippet kode berikut ke main.py
untuk menginisialisasi variabel. Snippet juga akan memulai Flask dan memanggil metode load_dotenv()
untuk membantu memuat variabel.
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}", }
Kemudian, tambahkan rute berikut untuk menangani pembuatan 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)
Fungsi tersebut akan memanggil endpoint Flows (flow_base_url)
sekaligus meneruskan payload (flow_creation_payload)
yang berisi nama dan kategori Flow. Nilai yang bisa digunakan untuk kategori ini adalah: SIGN_UP
, SIGN_IN
, APPOINTMENT_BOOKING
, LEAD_GENERATION
, CONTACT_US
, CUSTOMER_SUPPORT
, SURVEY
, atau OTHER
.
Ganti <FLOW-NAME>
dengan nama yang diinginkan —misalnya, survey_flow.
Setelah membuat Flow, kode akan mengekstrak created_flow_id
untuk mengunggah isi JSON.
Buat file survey.json
dengan konten ini. JSON berisi struktur Flow.
Lalu, tempel kode berikut ke file main.py
tersebut.
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())
Fungsi itu akan mengunggah data JSON dari survey.json
ke endpoint aset Flow.
Dalam snippet kode di bawah ini, saat pengguna memicu tindakan klik, ini akan memulai on-click-action
yang mengambil data dalam payload. Kolom "name": "complete"
menunjukkan bahwa Flow selesai. Flow akan ditutup dan payload akan dikirim ke server webhook Anda.
... "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}" } } ...
Nilai dalam objek payload bisa berhubungan dengan komponen Flow (menyerupai nama elemen dalam formulir HTML) atau objek data. Kunci yang terkait dengan nilai payload ini disebut nama, mirip dengan cara Anda menetapkan variabel dalam bahasa pemrograman.
Elemen data-source
juga memuat ID yang bertindak sebagai kunci untuk nilai tersebut. Kode mengirimkan ID ini untuk pilihan. Misalnya, jika pengguna memilih Likely
untuk data-source
di bawah, kode itu akan mengirimkan 1
. Setelah menerima data, Anda bisa mencocokkan sumber data.
... { "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 memilih satu layar yang memuat sembilan pertanyaan dengan pilihan ganda, seperti di bawah ini.
Anda bisa mempelajari detail elemen JSON dalam dokumentasi developer.
Selanjutnya, tempel fungsi di bawah ini ke file main.py
untuk menambahkan logika untuk menerbitkan Flow. Flow yang diterbitkan sudah siap diproduksi sehingga Anda tidak akan bisa melakukan perubahan lebih lanjut.
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)
Fungsi ini memanggil endpoint penerbitan saat meneruskan ID Flow.
Tempel fungsi berikut ke dalam file main.py
untuk mengirimkan Flow ke pengguna WhatsApp. Fungsi ini akan memanggil endpoint pesan Cloud API saat meneruskan payload Flow.
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")
Payload Flow berisi detail Flow. Kolom action.parameters.flow_token
memungkinkan Anda meneruskan pengidentifikasi unik untuk pesan Flow yang akan dikirimkan dari klien ke webhook Anda begitu Flow selesai. Untuk tutorial ini, Anda akan menggunakan ID acak (uuid). Kode ini menetapkan action.parameters.flow_action_payload.screen
sebagai SURVEY_SCREEN
yang merupakan ID layar yang ingin Anda tampilkan ketika pengguna mengklik action.parameters.flow_cta
.
Logika webhook cukup sederhana. Logika ini memiliki dua fungsi, webhook_get
dan webhook_post
, yang masing-masing menangani permintaan GET
dan POST
. Kode ini menggunakan permintaan GET
saat menambahkan webhook ke aplikasi Meta Anda. Kode ini mengembalikan hub.challenge
permintaan jika berhasil. Permintaan POST
mencetak payload pesan ke terminal.
@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)
Permintaan POST
mengekstrak dan memproses payload pesan. Karena kode ini hanya menangani payload pesan, kode ini akan memunculkan kesalahan saat menangkap payload lainnya. Untuk alasan ini, gunakan pernyataan if
untuk memeriksa apakah terdapat isi messages
. Setelah memeriksa bahwa terdapat isi JSON messages
, pemeriksaan lain dilakukan untuk mengekstrak nomor telepon pengirim saja jika terdapat isi text
dalam payload messages
.
@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)
Selain itu, Anda harus menggunakan fungsi bantuan berikut yang disebut flow_reply_processor
untuk mengekstrak tanggapan dari Flow dan mengirimkannya kembali kepada pengguna. Karena tanggapan Flow berisi ID opsi yang dipilih saat mengambil data dari RadioButtonsGroups
, fungsi itu akan mencocokkan ID dengan nilai string yang sesuai.
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")
Fungsi ini mengirimkan tanggapan menggunakan endpoint pesan teks Cloud API.
Aplikasi harus dijalankan sebelum Anda mengonfigurasi webhook di konsol Meta untuk Developer. Oleh karena itu, gunakan perintah flask --app main run --port 5000
di terminal Anda untuk menjalankan kode. Anda akan melihat pesan * Running on http://127.0.0.1:5000
di terminal Anda jika semua penyiapan sudah benar.
Selanjutnya, jalankan perintah ngrok
http 5000
di terminal Anda untuk mendapatkan URL yang mengarah ke aplikasi Anda. Salin tautan tersebut.
Di konsol Meta untuk Developer, di bawah WhatsApp di panel navigasi kiri, klik Konfigurasi.
Di kartu Webhook, klik Edit. Lalu, di kotak dialog pada kolom URL Callback, tambahkan URL yang telah disalin dan tambahkan /webhook
. Di kolom Verifikasi token, tambahkan token dari variabel TOKEN
file .env
.
Setelah selesai, klik Verifikasi dan simpan. Kotak dialog akan tertutup. Klik Kelola dan centang kolom pesan. Informasinya harus mirip dengan gambar di bawah ini, yaitu URL Callback, informasi yang tersembunyi di bawah Verifikasi token, dan pesan yang tercantum di bawah kolom Webhook.
Webhook kini sudah siap.
Di instance terminal baru, jalankan perintah cURL berikut untuk membuat Flow.
curl --location --request POST 'http://127.0.0.1:5000/create-flow'
Di instance terminal yang menampilkan output webhook, Anda akan melihat pesan seperti yang ditampilkan di bawah ini.
Saat pengguna mengirimkan pesan ke nomor WhatsApp Anda, mereka menerima Flow sebagai balasan, seperti pada cuplikan layar di bawah.
Mereka menerima tanggapan dengan jawaban mereka setelah menyelesaikan survei.
Setiap pesan yang dikirim pengguna ke nomor Anda akan memicu Flow. Untuk kasus penggunaan Anda, sesuaikan kode hanya untuk mengirim Flow survei dalam situasi tertentu, misalnya, setelah pengguna mengobrol dengan bisnis Anda.
WhatsApp Flows meningkatkan pengalaman pengguna melalui antarmuka interaktif untuk mengumpulkan data terstruktur, seperti tanggapan survei untuk perusahaan tur hipotesis. Bisnis ini hanya membuat aplikasi Flask, menerapkan kode Python untuk membuat, dan menyebarkan Flows melalui WhatsApp Flows API, menyiapkan webhook untuk mendengarkan pesan masuk, serta menjalankan aplikasi untuk mengaktifkan pengumpulan tanggapan survei.
Dengan WhatsApp Flows, organisasi Anda bisa mengumpulkan data dengan cepat dan mudah, sehingga bisa menaikkan tingkat penyelesaian interaksi pelanggan. Gunakan proses serupa untuk menyiapkan survei Anda sendiri, menawarkan dukungan pelanggan, membantu pelanggan memesan janji temu, dan lainnya.
Terus pelajari potensi WhatsApp Flows. Coba sekarang.