Customer satisfaction survey template (with NPS)

Build & score

Short answer: this is a complete QuizGen JSON definition you can POST as-is — a CSAT survey built around a real Net Promoter Score question, a satisfaction rating, a driver question, and open feedback, with a branching follow-up so detractors and promoters each get asked the right thing. No form builder, no field-by-field rebuilding.

If you just want a quick post-purchase "how did we do?" without the NPS math, the customer feedback form template is the shorter version — one satisfaction scale, one driver, one open question. This one is for when you specifically want to track Net Promoter Score over time, alongside a fuller satisfaction read.

The template

{
  "schema_version": 1,
  "kind": "survey",
  "title": "Customer satisfaction survey",
  "description": "Two minutes. Your answers shape what we fix next.",
  "settings": {
    "collect_respondent": "email_optional",
    "autosave": true,
    "completion": { "message": "Thanks — we read every one of these." }
  },
  "sections": [
    {
      "key": "main",
      "questions": [
        { "id": "nps", "type": "scale", "required": true,
          "prompt": "How likely are you to recommend us to a friend or colleague?",
          "min": 0, "max": 10,
          "min_label": "Not at all likely", "max_label": "Extremely likely" },
        { "id": "satisfaction", "type": "rating", "required": true,
          "prompt": "Overall, how satisfied are you with us?", "max": 5 },
        { "id": "score_driver", "type": "choice",
          "prompt": "What mainly drove your score?",
          "options": [
            { "value": "product_quality", "label": "Product quality" },
            { "value": "customer_support", "label": "Customer support" },
            { "value": "price_value", "label": "Price / value" },
            { "value": "ease_of_use", "label": "Ease of use" },
            { "value": "other", "label": "Something else" }
          ] },
        { "id": "detractor_recovery", "type": "long_text",
          "prompt": "Sorry to hear that. What's the one thing we could do to earn a higher score from you?",
          "rows": 4,
          "show_if": { "question": "nps", "op": "lte", "value": 6 } },
        { "id": "promoter_referral", "type": "long_text",
          "prompt": "Glad to hear it! What would you tell a colleague who was considering us?",
          "rows": 4,
          "show_if": { "question": "nps", "op": "gte", "value": 9 } },
        { "id": "open_feedback", "type": "long_text",
          "prompt": "Anything else you'd like us to know?", "rows": 4 }
      ]
    }
  ]
}

Why NPS fits QuizGen exactly

The nps question above isn't a workaround — it's a native scale question with min: 0, max: 10. The wording is the canonical NPS phrasing, and min_label/max_label anchor the ends exactly the way the methodology expects. That's the whole question; everything else in the template exists to give that single number context.

What each piece is doing:

  • nps — the canonical 0–10 recommend question, required so every response has a score to bucket.
  • satisfaction as a rating (5 stars) rather than another 0–10 scale — it reads differently on the page and gives you a second, complementary number without the two questions blurring together.
  • score_driver — a choice you can aggregate ("support drove 40% of low scores this month") instead of parsing free text for a reason.
  • detractor_recovery and promoter_referral — both use show_if against the same nps question, but with opposite operators (lte 6 vs gte 9), so passives (7–8) see neither and go straight to open_feedback. Each respondent only ever sees one of the two branches, so it doesn't add to the questions anyone has to answer — a detractor gets a recovery prompt, a promoter gets asked for a referral-worthy line, and nobody sees an irrelevant question.
  • open_feedback — a catch-all that isn't conditional, so everyone gets a chance to say something you didn't ask about directly.

How NPS scoring actually works

QuizGen doesn't compute NPS for you automatically — it's honest to be explicit about that. What it does is store the raw 0–10 answer on every response (answers.nps), which is all the math needs:

  • Promoters: score 9–10
  • Passives: score 7–8
  • Detractors: score 0–6
  • NPS = % promoters − % detractors (a number from -100 to 100, not a percentage itself)

Pull the numbers with GET /quizzes/:id/responses, bucket each answers.nps value into promoter/passive/detractor, and do the subtraction — a few lines in a spreadsheet or a script. If you want it computed the moment each response lands instead of pulled on demand, a webhook posts each completed response to your endpoint and you run the same bucketing there.

If you want QuizGen to tag each response with its bucket automatically — useful for filtering responses without recomputing every time — you can attach an outcomes block that maps the nps answer value to a bucket key:

"outcomes": {
  "method": "points",
  "points": {
    "nps": { "0": 0, "1": 0, "2": 0, "3": 0, "4": 0, "5": 0, "6": 0,
              "7": 1, "8": 1, "9": 2, "10": 2 }
  },
  "buckets": [
    { "key": "detractor", "max": 0, "title": "Detractor", "body": "Score 0–6." },
    { "key": "passive", "min": 1, "max": 1, "title": "Passive", "body": "Score 7–8." },
    { "key": "promoter", "min": 2, "title": "Promoter", "body": "Score 9–10." }
  ]
}

Be clear with yourself about what this buys you: each response now carries an outcome field ("detractor" / "passive" / "promoter") you can filter or sort on directly, which is a convenience. It does not compute the NPS score itself — that subtraction is still something you (or your webhook handler) do across all responses. Treat outcomes here as per-response tagging, not an NPS calculator.

Let an AI assistant fill it in

Connect QuizGen's MCP server and say something like:

Read https://quizgen.dev/blog/customer-satisfaction-survey-template.md and create me this CSAT + NPS survey for [MY BUSINESS]. Change the score_driver options to match what we actually sell. Give me the live link.

The assistant adapts the options and prompts, POSTs the definition, and hands back a live URL — and can pull the NPS numbers back for you later in the same chat.

When something else is the better pick

If tracking NPS trend lines with automatic dashboards, industry benchmarks, and segment comparisons is the whole job, a dedicated NPS tool (Delighted, Wootric, or similar) will save you the spreadsheet math — that's what they're built for. QuizGen is the better fit when you want the survey to live alongside your other forms, want an AI assistant or your own code to create and read it, or don't want a subscription just to ask one number.

FAQ

Can I ask NPS without the rest of the CSAT questions? Yes — delete everything except the nps question. A single-question NPS survey is still a valid definition.

What if someone skips the NPS question? It's marked required: true here, so they can't submit without answering it — remove required if you'd rather let people skip it (their response just won't count toward NPS).

Can I send this by email instead of just sharing a link? Yes, on paid plans — POST /quizzes/:id/send emails it to a list, and GET /quizzes/:id/sends shows who's completed it.

Does the rating question have to be 5 stars? No — max on rating accepts 2–10; 5 is just the common default for a satisfaction score.

$ curl quizgen.dev/blog/customer-satisfaction-survey-template.md

This guide as raw markdown — no HTML for your agent to parse.

View .md

Keep reading