SmartSurvey Scripting
A complete reference for writing survey logic — skip conditions, validations, display rules, and expressions — for CAPI, CAWI, and CATI surveys.
Q1=1&Q2>3) and are evaluated left-to-right with AND/OR precedence.How the Engine Works
Every condition in SmartSurvey — whether it's a skip, a validation, or a display rule — is an expression string. The engine converts it to postfix notation, then evaluates it against current response data using a stack-based algorithm.
-- General expression format -- Q1=1 -- Q1 has value 1 Q1=1&Q2!=3 -- Q1=1 AND Q2 is not 3 Q1=1|Q2=2 -- Q1=1 OR Q2=2 numberofresponse[Q3]>=2 -- Q3 has 2 or more selected answers totalof[Q4]<=100 -- numeric total of Q4 ≤ 100
Quick Navigation
Key Concepts
| Concept | Meaning | Example |
|---|---|---|
| Q Reference | Reference a question by its Question ID (qid field) | Q1, Q12, Q101 |
| AND operator | & — both conditions must be true | Q1=1&Q2=2 |
| OR operator | | — at least one condition must be true | Q1=1|Q1=2 |
| Comparison | Compare a Q value to a number or attribute code | Q3>=18 |
| Function call | Built-in functions for counts, sums, dates | numberofresponse[Q2]>1 |
| Attribute value | For single/multiple choice — value is the attribute_value code | Q5=3 (code 3 selected) |
Question Types
SmartSurvey supports 21 question types identified by a numeric qtype code. Use the correct type when referencing questions in logic expressions — some functions apply only to specific types.
Quick Reference
| ID | Name | Category | Directive | Use in Expressions |
|---|---|---|---|---|
| 1 | Single Response | Choice | *SR | Q1=value |
| 2 | Multiple Response | Choice | *MR | Q2=value, numberofresponse[Q2] |
| 3 | Text Response | Text | *OPEN | lengthof[Q3], substrof[Q3,0,2] |
| 4 | Numeric Response | Numeric | *NUMBER | Q4>=18, valueof[Q4] |
| 5 | Ranking | Choice | *RANK | valueof[Q5.1] |
| 6 | Image | Media | *PICT | No response — display only |
| 7 | Single Grid | Grid | *GRIDSR | valueof[Q7.row] |
| 8 | Multiple Grid | Grid | *GRIDMR | numberofresponse[Q8] |
| 9 | Media | Media | *INFO | No response — stimulus only |
| 12 | List Text | Text | *OPEN (list) | lengthof[Q12] |
| 13 | List Numeric | Numeric | *NUMBER (list) | sumof[Q13], totalof[Q13] |
| 14 | Date | Date/Time | *DATE | datevalueof[Q14] |
| 15 | Time | Date/Time | *TIME | timediffof[Q15,Q16] |
| 16 | Capture Image | Media | *CAPTUREIMAGE | No expression — CAPI only |
| 17 | Numeric with Total | Numeric | *NUMLISTTOTAL | totalof[Q17]=100 |
| 22 | AutoComplete | Choice | *SR (autocomplete) | Q22=value |
| 24 | Dropdown | Choice | *SR (dropdown) | Q24=value |
| 32 | Scale N-Grid | Grid | *GRIDSR (scale) | valueof[Q32.row], maxvalueof[Q32] |
| 40 | MaxDiff | Advanced | *MAXDIFF | Best/worst coding — no direct expression |
| 41 | GPS Capture | Geo | *GPS | No expression — CAPI only |
| 48 | Compound | Advanced | *COMPOUND | Per sub-question reference |
| 49 | Info / Display | Display | *INFO | No response — display only |
Question Type Details & Examples
Presents a list of options where the respondent selects exactly one. The response is stored as the selected attribute_value code. Use in expressions by comparing Qx=code.
*QUESTION Q1 *SR What is your gender? 1:Male 2:Female 3:Prefer not to say
Q1=1 -- respondent is Male Q1=2 -- respondent is Female Q1!=3 -- respondent did not choose "Prefer not to say" Q1=1|Q1=2 -- Male or Female (either)
Presents a list of options where the respondent can select one or more. Check for a specific code with Qx=code, or count total selections with numberofresponse[Qx].
*QUESTION Q2 *MR Which of the following brands are you aware of? 1:Berger 2:Asian Paints 3:Nippon 4:Dulux 99:None of the above *DKCS "None" "99"
Q2=1 -- Berger was selected Q2=1&Q2=2 -- both Berger AND Asian Paints selected numberofresponse[Q2]>=2 -- at least 2 brands selected numberofresponse[Q2]=0 -- nothing selected (or only "None")
Free-text input field. Use lengthof[] to enforce character limits and substrof[] to inspect content. Add *MANDATORY to require a non-empty answer.
*QUESTION Q3 *OPEN *MANDATORY Please describe your main reason for choosing this brand.
lengthof[Q3]>=10 -- at least 10 characters entered lengthof[Q3]=11 -- exactly 11 chars (e.g. mobile number) substrof[Q3,0,2]="01" -- starts with "01" (BD mobile prefix)
Single numeric entry field. Use *MIN and *MAX to constrain the allowed range. Reference directly in expressions with comparison operators.
*QUESTION Q4 *NUMBER *MIN 15 *MAX 99 How old are you? (years)
Q4>=18 -- adult (18 or older) Q4>=18&Q4<=35 -- 18–35 age bracket Q4<18 -- under 18 → screen out valueof[Q4]>=18 -- same using valueof[] function
Respondent orders items by preference (1st, 2nd, 3rd…). Use valueof[Qx.n] to retrieve the attribute code at rank position n.
*QUESTION Q5 *RANK Please rank these brands from most preferred (1) to least preferred (3). 1:Berger 2:Asian Paints 3:Nippon
valueof[Q5.1]=2 -- 1st choice is Asian Paints (code 2) valueof[Q5.2]=1 -- 2nd choice is Berger (code 1) valueof[Q5.1]!=3 -- top choice is not Nippon
Matrix question with rows (sub-questions) and columns (scale options). Single Grid allows one column selection per row; Multiple Grid allows several. Use valueof[Qx.row] to read a specific row's answer.
*GRIDLIST "SatisfactionScale" 1:Very Dissatisfied 2:Dissatisfied 3:Neutral 4:Satisfied 5:Very Satisfied *QUESTION Q7 *GRIDSR *USEGRIDLIST "SatisfactionScale" Rate your satisfaction with each aspect: 1:Product Quality 2:Price / Value 3:Customer Service 4:Delivery Speed
valueof[Q7.1]>=4 -- row 1 (Product Quality) rated 4 or 5 valueof[Q7.3]=1 -- row 3 (Customer Service) rated "Very Dissatisfied" valueof[Q7.2]>=4 & valueof[Q7.4]>=4 -- rows 2 and 4 both rated 4 or above
Collects a text or numeric entry for each row/attribute in the list. List Numeric entries can be summed with sumof[] or validated with totalof[].
*QUESTION Q13 *NUMBER *MIN 0 *MAX 100 What percentage of your paint purchases are from each channel? 1:Hardware Store 2:Distributor 3:Direct from Brand 4:Online
totalof[Q13]=100 -- all channel percentages sum to 100 valueof[Q13.1]>=50 -- Hardware Store accounts for 50%+ of purchases
Date picker input (YYYY-MM-DD). Use datevalueof[] to convert the date to a comparable numeric value (YYYYMMDD format) for age checks and eligibility filters.
*QUESTION Q14 *DATE What is your date of birth?
datevalueof[Q14]<20080101 -- born before 2008 (aged 18+ in 2026) datevalueof[Q14]>=19710101 -- born 1971 or later datevalueof[Q14]>=19710101&datevalueof[Q14]<=20011231 -- target age 25–55 (born 1971–2001)
Time picker input (HH:MM, 24-hour). Typically used as a hidden question auto-filled with timeof[Now] to record interview start/end times. Use timediffof[] for duration calculations.
*QUESTION QStartTime *TIME *DUMMY2 *INCLUDE QStartTime TimeOf[Now] -- auto-fill at interview start *QUESTION QEndTime *TIME *DUMMY2 *INCLUDE QEndTime TimeOf[Now] -- auto-fill at interview end
timediffof[QStartTime,QEndTime]>=20 -- interview at least 20 minutes timediffof[QStartTime,QEndTime]<=90 -- interview within 90 minutes
Multiple numeric fields where entries must sum to a target (usually 100). The running total is shown to the respondent in real time. Validate the total with totalof[].
*QUESTION Q17 *NUMLISTTOTAL *MIN 0 *MAX 100 Distribute 100 points across these paint attributes based on importance: 1:Coverage 2:Durability 3:Colour Range 4:Price 5:Brand Trust
totalof[Q17]=100 -- all entries must sum to exactly 100 valueof[Q17.1]>=30 -- Coverage given 30+ points
Both are single-response variants. AutoComplete (22) lets the respondent search a large list by typing. Dropdown (24) shows a select list. Both return one attribute_value code, used identically to a regular *SR in expressions.
*QUESTION Q22 *SR -- AutoComplete (large brand list) Which brand of cigarette did you purchase today? *USELIST "CigaretteBrandList" *QUESTION Q24 *SR -- Dropdown Select your division: 1:Dhaka 2:Chittagong 3:Rajshahi 4:Sylhet
Q22=5 -- brand code 5 selected via AutoComplete Q24=1 -- Dhaka division selected in Dropdown Q24=1|Q24=2 -- Dhaka or Chittagong
An N-point rating scale applied per row. Common for NPS, satisfaction ratings, and attribute evaluation grids. Use valueof[Qx.row] to read any row's score.
*GRIDLIST "Scale10" 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 8:8 9:9 10:10 *QUESTION Q32 *GRIDSR *USEGRIDLIST "Scale10" On a scale of 0–10, how likely are you to recommend each brand? 1:Berger 2:Asian Paints 3:Nippon
valueof[Q32.1]>=9 -- Berger NPS promoter (9 or 10) valueof[Q32.1]<=6 -- Berger NPS detractor (0–6) maxvalueof[Q32]>=9 -- at least one brand rated 9+ maxvalueindexof[Q32]=2 -- Asian Paints received the highest NPS
Field capture questions — CAPI mode only. Capture Image (16) opens the device camera or file browser to attach a photo. GPS (41) captures the device's current latitude and longitude. Neither produces a value usable in expressions.
*QUESTION QPhoto *CAPTUREIMAGE Please take a photo of the shop front. *QUESTION QLocation *GPS -- Captures GPS coordinates automatically (no question text needed)
Display-only block — shows text, instructions, or section introductions to the respondent. No response is captured. Supports HTML formatting. Use display conditions to show/hide info blocks dynamically.
*QUESTION QIntro *INFO <b>INTERVIEWER:</b> Read the following introduction to the respondent.<br> Thank you for agreeing to participate in this survey. It will take approximately 15 minutes. *QUESTION QSectionBreak *INFO <b>SECTION 2: BRAND USAGE</b> The following questions are about your usage of paint products.
Operators
Operators form the backbone of every condition expression. SmartSurvey supports 6 comparison operators and 2 logical connectors.
Comparison Operators
Logical Connectors
Operator Precedence
Expressions are evaluated left to right. There is no bracket grouping — structure your conditions accordingly.
-- Evaluated left to right: Q1=1&Q2=2|Q3=3 -- Reads as: ((Q1=1 AND Q2=2) OR Q3=3) -- To apply OR first, put OR conditions together: Q1=1|Q1=2&Q2=3 -- Reads as: Q1=1 OR Q1=2, then AND Q2=3
Built-in Functions
Functions allow you to compute derived values from responses — counting selections, summing numbers, extracting date parts, and more.
functionname[Qx] or functionname[Qx,param]. Function names are case-sensitive and must be written in lowercase.Returns the number of responses/selections made to a question. Most useful for Multiple Response (type 2) questions to enforce minimum/maximum selection counts.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | The question to count responses for |
numberofresponse[Q2]>=2 -- at least 2 options selected in Q2 numberofresponse[Q2]=3 -- exactly 3 selected numberofresponse[Q2]<=5 -- no more than 5 selected
Returns the sum of all numeric entries in a question. Applies to Numeric with Total (type 17) and List Numeric (type 13) questions where multiple values are entered.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Numeric or numeric-total question |
totalof[Q17]=100 -- budget allocation must sum to 100 totalof[Q17]<=500 -- total spend does not exceed 500
Returns the value of the nth response/attribute for a question. Used for Ranking (type 5), Grid questions, and Scale N-Grid (type 32) to get a specific position's value.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | The question to read from |
n | Integer | The position index (1-based) |
valueof[Q5.1]=3 -- first-ranked item in Q5 is brand code 3 valueof[Q32.2]>=4 -- row 2 of scale grid rated 4 or above
Returns the modulo (remainder) of a question's value divided by the divisor. Useful for alternating questionnaire versions or rotation logic.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Numeric question |
divisor | Integer | The divisor number |
modof[Q1,2]=0 -- respondent ID is even → show version A modof[Q1,2]=1 -- respondent ID is odd → show version B modof[Q1,3]=0 -- every 3rd respondent → rotation group C
Returns the sum of values across multiple questions. Use when respondents split a budget or allocation across separate questions and you need to validate the combined total.
| Parameter | Type | Description |
|---|---|---|
Qx, Qy, … | Question refs | Two or more numeric questions, comma-separated |
sumof[Q10,Q11,Q12]=100 -- Q10+Q11+Q12 must equal 100% sumof[Q10,Q11]<=1000 -- combined spend ≤ 1000 BDT
Extracts a substring from a text response. Useful for parsing structured codes, phone numbers, or postal codes entered in text fields.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Text question to extract from |
start | Integer | Start position (0-based) |
length | Integer | Number of characters to extract |
substrof[Q3,0,2]="01" -- phone starts with "01" (BD mobile) substrof[Q3,0,4]="1234" -- first 4 digits match a district code
Returns the character length of a text response. Use to enforce minimum or maximum word/character count for open-ended questions.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Text question to measure |
lengthof[Q3]>=10 -- response must be at least 10 characters lengthof[Q3]<=500 -- response cannot exceed 500 characters lengthof[Q3]=11 -- exactly 11 chars (e.g. phone number)
Parses and returns a comparable numeric date value from a Date question (type 14). Allows date comparisons like age thresholds or eligibility cutoffs.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Date question (type 14) |
datevalueof[Q14]<20060101 -- born before 2006 (aged 18+) datevalueof[Q14]>=19590101 -- born in 1959 or later
Returns the difference in minutes between two Time questions. Use for interview duration checks, time-window validations, or scheduling logic.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Start time question (type 15) |
Qy | Question ref | End time question (type 15) |
timediffof[Q15,Q16]>=20 -- interview lasted at least 20 min timediffof[Q15,Q16]<=90 -- interview completed within 90 min
Arithmetic Functions
Returns the result of subtracting Qy from Qx. Use to compute the difference between two numeric question values.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Minuend (value to subtract from) |
Qy | Question ref | Subtrahend (value to subtract) |
subtractof[Q10,Q11]>=0 -- Q10 is greater than or equal to Q11 subtractof[Q10,Q11]<=100 -- difference does not exceed 100
Returns the product of Qx multiplied by Qy. Useful for computing weighted scores or scaled values from two numeric inputs.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | First factor |
Qy | Question ref | Second factor |
multiplyof[Q5,Q6]>=1000 -- product of Q5 and Q6 is at least 1000
Returns the result of dividing Qx by Qy. Use for ratio comparisons and percentage calculations. Ensure Qy cannot be zero to avoid division errors.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Dividend |
Qy | Question ref | Divisor (must not be zero) |
divideof[Q10,Q11]>=2 -- Q10 is at least double Q11 divideof[Q10,Q11]<=1 -- Q10 is not greater than Q11
Advanced Value Functions
Returns the maximum value across all entries in a grid or multi-entry numeric question. Use to find the highest rating or score given by the respondent.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Grid or multi-numeric question |
maxvalueof[Q20]>=4 -- at least one row was rated 4 or above maxvalueof[Q20]=5 -- the highest rating given was exactly 5
Returns the 1-based row/position index of the maximum value in a grid or multi-entry question. Use to identify which item received the highest rating.
| Parameter | Type | Description |
|---|---|---|
Qx | Question ref | Grid or multi-numeric question |
maxvalueindexof[Q20]=2 -- row 2 has the highest rating in Q20 maxvalueindexof[Q20]!=1 -- the top-rated item is not row 1
Wraps a literal text value as a string for comparison. Required when comparing a question response or system value against a text constant — for example when using useridof[] or languageof[].
| Parameter | Type | Description |
|---|---|---|
value | String literal | The text constant to compare against (no quotes needed) |
useridof[Interview]=stringof[dhaka_fi01] -- interviewer is dhaka_fi01 languageof[Interview]=stringof[bn] -- interview language is Bengali
System & Admin Functions
Returns the login username of the currently logged-in field interviewer. Use to route different interviewers to different question sets, sample blocks, or geographic quotas.
| Parameter | Type | Description |
|---|---|---|
Interview | Keyword | Fixed keyword — always write exactly Interview |
stringof[].useridof[Interview]=stringof[dhaka_fi01] -- route Dhaka FI to Dhaka sample useridof[Interview]=stringof[ctg_fi01] -- route Chittagong FI to Ctg sample useridof[Interview]!=stringof[supervisor1] -- exclude supervisor account
Returns the language code of the current interview session. Use to conditionally include language-specific attributes or show language-appropriate content.
| Parameter | Type | Description |
|---|---|---|
Interview | Keyword | Fixed keyword — always write exactly Interview |
en, bn, ar). Always compare using stringof[].languageof[Interview]=stringof[bn] -- session is in Bengali languageof[Interview]=stringof[en] -- session is in English -- Often used with *INCLUDE to load language-specific attribute lists
Captures the current system time at the moment the question is reached. Used as an auto-fill value to record interview start and end times for Length of Interview (LOI) calculations. Always pair with timediffof[] for duration checks.
| Parameter | Type | Description |
|---|---|---|
Now | Keyword | Fixed keyword — always write exactly Now |
timeof[Now] is used as an auto-fill value on a hidden Time question — not inside a condition expression. The captured time question is then referenced in timediffof[].-- Auto-record interview start time into hidden QStartTime *INCLUDE QStartTime TimeOf[Now] -- Auto-record end time into QEndTime (at end of survey) *INCLUDE QEndTime TimeOf[Now] -- Validate interview duration is between 20 and 90 minutes timediffof[QStartTime,QEndTime]>=20&timediffof[QStartTime,QEndTime]<=90
Captures today's date at the moment the question is reached. Used to auto-record the interview date for quality control and tracking. Written as an auto-fill on a hidden Date question.
| Parameter | Type | Description |
|---|---|---|
Today | Keyword | Fixed keyword — always write exactly Today |
-- Auto-record today's date into hidden QDate (Date, type 14) *INCLUDE QDate DateOf[Today]