Documentation

Number Question

When and Why to Use

Use this when you need a numeric input within a defined range. It's best for:

  • Age, year, count, or frequency questions
  • Questions that require range-based recoding (e.g. age bands)
  • Validating attention checks with specific values

Supports optional recoding and validation logic. Returns an IntResponse, which behaves like a standard Python integer.

Other Names and Formats

A Number Question is also called a numeric entry question, numerical input question, number entry question, numeric open-ended question, or integer input. Respondents enter a whole number within the configured range, such as an age, count, year, or frequency.

Chat Experience

  • Respondent is shown a numeric input with increment/decrement buttons.
  • Range boundaries are visible.
  • If input is outside the range or invalid, an error message appears inline.
With an imageWithout an image
Markdown ImagesPlain Text

Traditional Experience

  • Same as chat, but with more space for contextual text or images.
  • Navigation and focus-friendly for web-based interactions.
With an imageWith markdownMobile optimized
Text ImagesMarkdown Many OptionsNumber Question Figure 01

Configuration Options

OptionTypeRequiredDefaultDescription
questionstringyes-The prompt shown to the user
imageMediaItemno-Optional image from s.media
image_sizeTuple[int, int]no(600, 600)Bounding box size for a displayed image
min_maxTuple[int, int]no(1, 10)The inclusive numeric range for answers
style"input" | "button"no"input""button" shows recode ranges as buttons, storing the midpoint
defaultint | List[int]norandom between rangeDefault value for test data, or a list of candidate values — each simulated respondent picks one at random
recodesdict[str, str]no-Map ranges or percentages to buckets
custom_validatorCallable[[int], str | None]no-Called with the parsed integer; return an error message to reject
input_prefixstrno-Display-only text before the numeric input; input style only
input_suffixstrno-Display-only text after the numeric input; input style only
number_secondsintno0Seconds to wait before allowing the respondent to continue
tagss.tag()no-Used to fill tokens in text and for reporting groupings
idstringno-Optional stable identifier for this question

Example Code

Simple numeric:

Code
s.numeric_question("What year were you born in?", min_max=(1900, 2024))

With recodes:

Code
s.numeric_question( "How old are you?", min_max=(18, 100), recodes={ "18-25": "18-25", "26-54": "26-54", "55-74": "55-74", "75-100": "75+" } )

With percentage-based recodes:

Code
s.numeric_question( "How many times have you visited our website?", min_max=(0, 100), recodes={ "0-30%": "Low", "31-70%": "Medium", "71-100%": "High" } )

With custom validator:

Code
s.numeric_question( "How old are you?", min_max=(0, 200), custom_validator=lambda x: "Are you sure that you're 150 years old?" if x > 150 else None )

As range buttons:

Code
s.numeric_question( "How old are you?", min_max=(18, 100), style="button", recodes={ "18-34": "18-34", "35-54": "35-54", "55-100": "55+" } )

With style="button", the recode ranges are shown as buttons instead of a numeric input, and the selected range stores its integer midpoint as the underlying value. Button style requires explicit finite-range recode keys — percentage and open-ended keys (like "0-50%" or "65+") are not supported in button style.

Display a prefix or suffix

Use input_prefix and input_suffix with the default style="input" to display a currency symbol or short unit beside the input:

Code
s.numeric_question( "What is your monthly rent, in pounds?", min_max=(0, 10000), input_prefix="£", input_suffix=" per month", )

These are display-only labels. Entering 1200 stores the number 1200; the prefix and suffix are not part of the response and do not change numeric validation or recoding. Include the currency or unit in the question wording too, so the meaning is clear across survey channels.

Chat-style numeric input with a euro prefix, the value 1500 and a per-month suffix

Recoding Numeric Responses

Sometimes it's useful to group numeric values into labeled categories - for instance, turning income ranges into brackets like "Low", "Middle", and "High". You define a set of rules that map numeric ranges to labels. Supported formats include:

  1. Fixed Ranges (e.g. "0-49" → "Low")
  2. Percentage Ranges (e.g. "0-25%")→ Interpreted relative to a known min and max.
  3. Open-ended Ranges (e.g. "80+")→ Interpreted as "80 and above".

Example 1: Satisfaction Score (0-100)

Code
_recodes = { "0-25%": "Very Dissatisfied", "25-50%": "Dissatisfied", "50-75%": "Satisfied", "75-100%": "Very Satisfied" }

This scales the numeric value based on known min/max and assigns the appropriate label.

Example 2: Age Brackets

Code
_recodes = { "0-17": "Underage", "18-64": "Adult", "65+": "Senior" }

In this case, "65+" means any value 65 or greater gets labeled "Senior".

What If No Match?

If the value doesn't fall into any defined range, the original number is returned unchanged.