About this marketing preferences & opt-in flow
Meta's WhatsApp Business Messaging Policy requires an opt-in before you send marketing messages, and it expects that opt-in to be clear: the person should understand they are agreeing to receive messages on WhatsApp, and from which business. A vague checkbox buried in a checkout page is a weak basis for a broadcast list. This flow records the opt-in inside WhatsApp itself, in the contact's own words and taps, with a timestamp you get from the webhook.
It also collects preferences that make the opt-in worth having. Topics tell you which segment a contact belongs to, so a customer who only wants event news does not get every discount blast. Frequency and preferred time of day give you a ceiling and a send window per contact. Contacts who get fewer, more relevant messages block and report less often, which protects your number's quality rating and messaging limits.
The consent checkbox is deliberately optional and unticked. A contact can submit their preferences and still say no, and your handler should treat anything other than an explicit true as no consent. That way the form never pressures anyone into opting in just to finish it.
Fields this flow returns
When the customer taps the final button, the complete action sends these keys back in response_json. Fields from earlier screens are pulled in with global references (${screen.SCREEN_ID.form.field}), so nothing is lost between screens.
| Key | Component | Screen | Required | Returns | Example |
|---|---|---|---|---|---|
topicsoffers, new_services, events, tips, loyalty_rewards |
CheckboxGroup | MESSAGE_PREFERENCES | No | array of ids | ["offers","events"] |
message_frequencyweekly, twice_monthly, monthly, major_only |
RadioButtonsGroup | MESSAGE_PREFERENCES | Yes | item id | "monthly" |
preferred_timemorning, afternoon, evening, no_preference |
RadioButtonsGroup | MESSAGE_PREFERENCES | No | item id | "evening" |
marketing_consent |
OptIn | MESSAGE_PREFERENCES | No | boolean | true |
Optional fields the customer leaves empty may be missing from response_json or arrive empty. Treat every optional key as nullable in your handler.
Send the Marketing Preferences & Opt-In flow without touching code
You do not need to be technical to use WhatsApp Flows. Connect your WhatsApp number, set the flow up in our drag-and-drop editor and send it to customers in a few clicks. No JSON, no API calls, no WhatsApp Manager.
Connect your number
Log in with Facebook and connect your WhatsApp number in a few minutes. No API keys or servers to set up.
Set up the flow
Start from a ready-made form or import this one, then drag fields in, change the wording and try it on a live phone preview. Click Publish when it looks right.
Send it anywhere
Send it from any chat in the Team Inbox, on web or mobile, send it automatically from an automation, or broadcast it to a list.
Get the answers
Every answer is saved on the customer's profile and chat, and your team can be notified the moment a form comes in.
Sample webhook payload (nfm_reply)
This is what your webhook receives when a customer submits the flow. response_json is a JSON string: parse it, then match flow_token to the record you created when you sent the message. The customer's WhatsApp number is in messages[0].from.
{
"flow_token": "bk_8f2c41",
"topics": [
"offers",
"events"
],
"message_frequency": "monthly",
"preferred_time": "evening",
"marketing_consent": true
}
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "WHATSAPP_BUSINESS_ACCOUNT_ID",
"changes": [
{
"field": "messages",
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "15550001234",
"phone_number_id": "PHONE_NUMBER_ID"
},
"contacts": [
{
"profile": {
"name": "Alex Morgan"
},
"wa_id": "14155550123"
}
],
"messages": [
{
"context": {
"from": "15550001234",
"id": "wamid.SENT_FLOW_MESSAGE_ID"
},
"from": "14155550123",
"id": "wamid.INCOMING_MESSAGE_ID",
"timestamp": "1760000000",
"type": "interactive",
"interactive": {
"type": "nfm_reply",
"nfm_reply": {
"name": "flow",
"body": "Sent",
"response_json": "{\"flow_token\":\"bk_8f2c41\",\"topics\":[\"offers\",\"events\"],\"message_frequency\":\"monthly\",\"preferred_time\":\"evening\",\"marketing_consent\":true}"
}
}
}
]
}
}
]
}
]
}
Deploy with the WhatsApp Cloud API
Prefer code over WhatsApp Manager? Save the template as marketing-preferences.json and run these calls with a system user token that has whatsapp_business_management and whatsapp_business_messaging permissions.
1. Create the flow
curl -X POST 'https://graph.facebook.com/v23.0/{WABA_ID}/flows' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-H 'Content-Type: application/json' \
-d '{"name": "marketing_preferences", "categories": ["SIGN_UP"]}'
# => {"id": "{FLOW_ID}"}2. Upload the Flow JSON
curl -X POST 'https://graph.facebook.com/v23.0/{FLOW_ID}/assets' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F '[email protected];type=application/json' \
-F 'name=flow.json' \
-F 'asset_type=FLOW_JSON'
# => {"success": true, "validation_errors": []}3. Publish it
curl -X POST 'https://graph.facebook.com/v23.0/{FLOW_ID}/publish' \
-H 'Authorization: Bearer {ACCESS_TOKEN}'Publishing is permanent: a published flow cannot be edited. To change it later, create a new flow (or clone it with clone_flow_id) and publish the new version.
4. Send it to a customer
Inside the 24-hour customer service window, send an interactive flow message. Outside it, create a message template with a Flow button that points to this flow, and send the template instead.
{
"messaging_product": "whatsapp",
"recipient_type": "individual",
"to": "14155550123",
"type": "interactive",
"interactive": {
"type": "flow",
"header": {
"type": "text",
"text": "Choose what you hear from us"
},
"body": {
"text": "Pick the updates you actually want and how often. You can change your mind at any time by replying STOP."
},
"footer": {
"text": "You can opt out at any time"
},
"action": {
"name": "flow",
"parameters": {
"flow_message_version": "3",
"flow_token": "bk_8f2c41",
"flow_id": "YOUR_FLOW_ID",
"flow_cta": "Set my preferences",
"flow_action": "navigate",
"flow_action_payload": {
"screen": "MESSAGE_PREFERENCES"
}
}
}
}
}curl -X POST 'https://graph.facebook.com/v23.0/{PHONE_NUMBER_ID}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-H 'Content-Type: application/json' \
-d @send-marketing-preferences.jsonWhen to send it
After a first purchase or visit
Inside the 24-hour window after a service conversation, ask whether the customer would like offers and updates, instead of silently adding them to a broadcast list.
Before relaunching an old list
If numbers were collected on paper or at a till without a clear WhatsApp opt-in, send the form when each contact next messages you, and broadcast only to those who tick the box.
When someone replies "too many messages"
Offer the preference form instead of an all-or-nothing unsubscribe. Many contacts would rather drop to monthly than leave completely.
New branch or product line
When you add a service, let existing opted-in contacts add the new topic rather than assuming everyone wants to hear about it.
How to customise this template
- Replace "Your Business" in the OptIn label with your actual business name as customers know it. The opt-in should name the business that will be messaging them.
- Keep the topic ids aligned with the tags or segments you broadcast to, for example offers, events and tips. Then a submission can be turned into tags without a lookup table.
- Point the EmbeddedLink at your real privacy policy, and make sure that page explains how you use WhatsApp numbers and how to opt out.
- If you only send one kind of message, remove the topics CheckboxGroup and keep frequency and time. A single-topic list does not need a preference question.
Open this template in the Flow Builder to make these changes visually. The builder keeps field names unique and regenerates the completion payload for you.
Common mistakes to avoid
- Never pre-tick or require the marketing OptIn. Consent that cannot be refused is not meaningful, and a required checkbox forces people who only wanted to set preferences to either lie or abandon the form.
- Store the evidence: keep the flow_token, the submission timestamp, the contact's number and the exact OptIn wording at the time. If you edit the label later, older consents were given against the old text.
- Opt-outs must be honoured wherever they come from. A "STOP" typed in chat, a block, or an unticked box on a later submission should all remove the contact from marketing sends, whatever this form said before.
- Frequency is a promise. If a contact chooses "Monthly" and receives three broadcasts that week, expect blocks and reports, which lower your number's quality rating.
Keep consent and contact data in one place
In Whautomate, import this flow into the built-in flow editor, click Publish and send it from the Team Inbox, an automation or a Flow-button template. Answers are saved on the client's profile, tags are added on submit, and automations can manage your suppression list so opted-out contacts stop receiving broadcasts.
- Tags added automatically on submit
- Suppression list for opt-outs
- Every answer kept on the client profile
7-day free trial, no credit card required.