WhatsApp NPS Survey Flow Template

A two-screen Net Promoter Score survey. Screen one asks the standard 0 to 10 "how likely are you to recommend us" question; screen two asks for the main reason, an open comment and permission to follow up.

2 screens 4 fields returned Flow JSON 7.2 Survey Clinics, Gyms, Studios, Stores, Tutors

Use Try it to fill the flow and see the exact response_json it returns.

nps-survey.json Open in Flow Builder
{
  "version": "7.2",
  "screens": [
    {
      "id": "SCORE",
      "title": "Quick question",
      "data": {},
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "Form",
            "name": "form_score",
            "children": [
              {
                "type": "TextHeading",
                "text": "How likely are you to recommend us to a friend or colleague?"
              },
              {
                "type": "TextCaption",
                "text": "0 means not at all likely, 10 means extremely likely."
              },
              {
                "type": "RadioButtonsGroup",
                "name": "recommend_score",
                "label": "Your score",
                "data-source": [
                  {
                    "id": "score_10",
                    "title": "10 - Extremely likely"
                  },
                  {
                    "id": "score_9",
                    "title": "9"
                  },
                  {
                    "id": "score_8",
                    "title": "8"
                  },
                  {
                    "id": "score_7",
                    "title": "7"
                  },
                  {
                    "id": "score_6",
                    "title": "6"
                  },
                  {
                    "id": "score_5",
                    "title": "5"
                  },
                  {
                    "id": "score_4",
                    "title": "4"
                  },
                  {
                    "id": "score_3",
                    "title": "3"
                  },
                  {
                    "id": "score_2",
                    "title": "2"
                  },
                  {
                    "id": "score_1",
                    "title": "1"
                  },
                  {
                    "id": "score_0",
                    "title": "0 - Not at all likely"
                  }
                ],
                "required": true
              },
              {
                "type": "Footer",
                "label": "Next",
                "on-click-action": {
                  "name": "navigate",
                  "next": {
                    "type": "screen",
                    "name": "REASON"
                  },
                  "payload": {}
                }
              }
            ]
          }
        ]
      }
    },
    {
      "id": "REASON",
      "title": "Tell us why",
      "terminal": true,
      "data": {},
      "layout": {
        "type": "SingleColumnLayout",
        "children": [
          {
            "type": "Form",
            "name": "form_reason",
            "children": [
              {
                "type": "TextSubheading",
                "text": "What is the main reason for your score?"
              },
              {
                "type": "RadioButtonsGroup",
                "name": "main_reason",
                "label": "Main reason",
                "data-source": [
                  {
                    "id": "service_quality",
                    "title": "Quality of the service"
                  },
                  {
                    "id": "staff",
                    "title": "The team"
                  },
                  {
                    "id": "results",
                    "title": "Results I got"
                  },
                  {
                    "id": "price_value",
                    "title": "Price and value"
                  },
                  {
                    "id": "convenience",
                    "title": "Location and opening hours"
                  },
                  {
                    "id": "booking_experience",
                    "title": "Booking and communication"
                  },
                  {
                    "id": "other",
                    "title": "Something else"
                  }
                ],
                "required": true
              },
              {
                "type": "TextArea",
                "name": "reason_comment",
                "label": "Tell us more",
                "helper-text": "What should we keep doing, or change?",
                "max-length": 600
              },
              {
                "type": "OptIn",
                "name": "contact_ok",
                "label": "OK to contact me about my feedback"
              },
              {
                "type": "Footer",
                "label": "Submit",
                "on-click-action": {
                  "name": "complete",
                  "payload": {
                    "recommend_score": "${screen.SCORE.form.recommend_score}",
                    "main_reason": "${form.main_reason}",
                    "reason_comment": "${form.reason_comment}",
                    "contact_ok": "${form.contact_ok}"
                  }
                }
              }
            ]
          }
        ]
      }
    }
  ]
}

Raw JSON for scripts: curl -s https://whautomate.com/whatsapp-flow-templates/nps-survey.json

Import in 60 seconds
  1. Copy the JSON above (or edit it first in the Flow Builder).
  2. In WhatsApp Manager, open Account tools > Flows, create a flow and choose Survey as the category.
  3. Paste into the JSON editor, check the preview, then Publish.
  4. Send it with the Flow ID, as an interactive message or through a template's Flow button.

Not technical? Skip the JSON and send it from Whautomate with a drag-and-drop editor.

About this nps survey flow

Net Promoter Score measures loyalty rather than satisfaction with a single visit. It asks one question on a 0 to 10 scale, how likely the person is to recommend you, and sorts everyone into three groups: promoters (9 and 10), passives (7 and 8) and detractors (0 to 6). Your NPS is the percentage of promoters minus the percentage of detractors, so it runs from -100 to +100. Passives count toward the total but not toward either side.

WhatsApp has no native slider, so the score is an 11-item radio list with ids score_0 to score_10. Only the two ends carry words ("0 - Not at all likely", "10 - Extremely likely"), which matches the standard NPS wording and avoids nudging people toward the middle. Your handler reads the id, strips "score_" and gets an integer.

The second screen is where the score becomes useful. A single "main reason" radio gives you a clean category to slice by, the comment captures the specifics, and an opt-in records whether the person is happy for someone to contact them. That last answer matters most for detractors: a quick, permitted follow-up call often recovers the relationship.

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.

KeyComponentScreenRequiredReturnsExample
recommend_score
score_10, score_9, score_8, score_7, score_6, score_5, score_4, score_3, score_2, score_1, score_0
RadioButtonsGroup SCORE Yes item id "score_9"
main_reason
service_quality, staff, results, price_value, convenience, booking_experience, other
RadioButtonsGroup REASON Yes item id "staff"
reason_comment TextArea REASON No string "The coaches remember my goals and adjust every session."
contact_ok OptIn REASON 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.

No developer needed

Send the NPS Survey 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.

1

Connect your number

Log in with Facebook and connect your WhatsApp number in a few minutes. No API keys or servers to set up.

2

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.

3

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.

4

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.

7-day free trial, no credit card required.

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.

response_json (parsed)
{
  "flow_token": "bk_8f2c41",
  "recommend_score": "score_9",
  "main_reason": "staff",
  "reason_comment": "The coaches remember my goals and adjust every session.",
  "contact_ok": true
}
POST your-webhook (full event)
{
  "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\",\"recommend_score\":\"score_9\",\"main_reason\":\"staff\",\"reason_comment\":\"The coaches remember my goals and adjust every session.\",\"contact_ok\":true}"
                  }
                }
              }
            ]
          }
        }
      ]
    }
  ]
}

Deploy with the WhatsApp Cloud API

Prefer code over WhatsApp Manager? Save the template as nps-survey.json and run these calls with a system user token that has whatsapp_business_management and whatsapp_business_messaging permissions.

1. Create the flow

bash
curl -X POST 'https://graph.facebook.com/v23.0/{WABA_ID}/flows' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{"name": "nps_survey", "categories": ["SURVEY"]}'
# => {"id": "{FLOW_ID}"}

2. Upload the Flow JSON

bash
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

bash
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.

send-nps-survey.json
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "14155550123",
  "type": "interactive",
  "interactive": {
    "type": "flow",
    "header": {
      "type": "text",
      "text": "One quick question"
    },
    "body": {
      "text": "How likely are you to recommend us to a friend? Your answer takes two taps and shapes what we change next."
    },
    "footer": {
      "text": "Reply STOP to opt out"
    },
    "action": {
      "name": "flow",
      "parameters": {
        "flow_message_version": "3",
        "flow_token": "bk_8f2c41",
        "flow_id": "YOUR_FLOW_ID",
        "flow_cta": "Give your score",
        "flow_action": "navigate",
        "flow_action_payload": {
          "screen": "SCORE"
        }
      }
    }
  }
}
bash
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-nps-survey.json

When to send it

Quarterly relationship check

Send it to active clients every three months. NPS tracks the overall relationship, so it works best on a steady schedule rather than after every visit.

After a milestone

The tenth class, the end of a treatment course or a membership anniversary are natural points to ask whether someone would recommend you.

Before a referral push

Run NPS first, then send your referral offer only to people who scored 9 or 10. Promoters are the ones who actually refer.

After a service change

When you move location, change prices or restructure the timetable, compare NPS before and after to see how regulars took it.

How to customise this template

  • Replace the main reason options with the drivers you actually control: for a gym "Class variety" and "Coaches", for a tutor "Progress made" and "Lesson scheduling".
  • Keep the ids score_0 to score_10 exactly as they are. Changing them breaks the parsing that turns ids into numbers.
  • If you only want reasons from detractors, you still need to show screen two to everyone in a static flow. Keep the reason field required anyway: promoters' reasons tell you what to protect.
  • Change the TextHeading to name what they would recommend ("our studio", "our tutoring") if you run more than one brand from the same number.

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

  • Do not average the scores. NPS is promoters percentage minus detractors percentage; an average of 7.8 and an NPS of +12 describe very different situations.
  • Do not relabel the middle options with words like "Good" or "Okay". Standard NPS labels only the ends, and extra labels make your score incomparable with benchmarks.
  • Surveying the same person too often lowers response rates and drags scores down. Leave at least 90 days between NPS sends to one contact.
  • Respect the contact_ok answer. If someone leaves it unticked, do not call them about their score, even if it was a 0.

Send it automatically after every visit

In Whautomate, import this flow into the built-in flow editor and click Publish. Attach it to a message template's Flow button and send it from an automation when an appointment is created or updated, or as a broadcast to a segment. Every response is saved on the client's profile, and a "WhatsApp Flow form is submitted" automation can alert your team the moment a low score comes in.

  • Automations on appointment, class and order updates
  • Alert staff on low scores automatically
  • Responses saved to the client profile and exportable

7-day free trial, no credit card required.

Frequently asked questions

Parse recommend_score to an integer. Count 9 and 10 as promoters, 0 to 6 as detractors, and 7 and 8 as passives. NPS = (promoters / total x 100) - (detractors / total x 100). With 60 promoters, 25 passives and 15 detractors out of 100, NPS is 45.
A number TextInput lets people type 11 or leave it blank, and the keyboard hides half the screen. An 11-item RadioButtonsGroup guarantees a valid 0 to 10 answer and takes one tap.
Not in a static flow. Branching on the answer needs conditional components or a data_exchange endpoint. This template shows the same follow-up to everyone, which keeps it free to run and still gives you reasons from every group.
An nfm_reply message whose response_json holds the flow_token, recommend_score (for example "score_9"), main_reason (an item id), reason_comment (a string) and contact_ok (true or false).
Yes for scheduled sends, because most recipients will not have messaged you in the last 24 hours. Attach the flow to a template's Flow button. Meta assigns the category on review, and NPS requests are frequently classed as marketing.

The Complete Omnichannel Customer Engagement Platform

Go beyond free tools. Automate conversations, build AI chatbots, send broadcast campaigns, book appointments, sell products, and manage every messaging channel from one powerful platform. Trusted by thousands of businesses worldwide.

  • WhatsApp, Instagram, Messenger, Telegram & Live Chat
  • AI chatbots & no-code automation
  • Broadcast campaigns & analytics
  • Appointment & class booking
  • E-commerce, Shopify & WooCommerce integration
  • CRM, invoicing & payment collection

No credit card required. Free 7-day trial. Visit our pricing page for plans.