KoboToolbox and ODK: building survey forms with XLSForm
Write a household survey once, as a spreadsheet, and run it on Android phones with no network: skip logic, range checks, Hindi and English labels, a household roster. KoboToolbox and ODK both read the same XLSForm standard. Python cells on this page check a form for common mistakes and check a downloaded dataset against the form's rules.
KoboToolbox, ODK Collect and ODK Central
Most household surveys in South Asian programmes are now collected on Android phones. Two families of free tools dominate, and they are closely related.
- ODK is open source software. Its documentation describes three parts: ODK Collect, an Android app that fills forms offline and sends them when a connection is found; ODK Central, the server where you upload forms, manage users and download submissions; and Web Forms, for filling a form in a browser. The Collect source code is published under the Apache License 2.0.
- KoboToolbox is a hosted service run by Kobo, a nonprofit. Its own Android app, KoboCollect, is described in the KoboToolbox glossary as the app "used for mobile data collection, allowing enumerators to download forms, complete them offline, and submit data when connected". KoboToolbox also has a point-and-click Formbuilder.
- XLSForm is the shared language. The XLSForm reference defines a form as an Excel workbook with a survey sheet, a choices sheet and a settings sheet. KoboToolbox and ODK Central both accept the same file, so a form you write here works on either.
What it costs, checked 6 October 2026
- KoboToolbox Community plan: free for organisations in its Nonprofit category, which the pricing page says "includes nonprofits, government agencies, UN organizations, and educational institutions". It allows 5,000 submissions a month and 1 GB of file storage, with unlimited projects and data collectors. Private companies, for-profit organisations and personal use fall in the Other category, where the same plan is listed at US$99 a month (US$88 a month billed yearly) and a smaller Starter plan at US$25 a month.
- ODK: the ODK home page says "ODK is open-source software. If you're technical, you can self-host and self-support it for free." Its paid hosting, ODK Cloud, lists a Standard plan at US$199 a month (the figure shown with yearly billing; the page says paying yearly saves up to 20%) with 10,000 submissions a month, and says data can be stored in the US, the EU or India.
Which KoboToolbox server
KoboToolbox runs two public servers with the same features. The account guide (updated 3 October 2026) calls the Global server (kf.kobotoolbox.org) the one "used by most KoboToolbox users"; the glossary says it is hosted in the United States. The European Union server (eu.kobotoolbox.org) is "hosted in Ireland". Projects cannot be moved between them, so choose before you build.
kobo.humanitarianresponse.info, the KoboToolbox server owned by UN OCHA. Kobo announced on 1 September 2023 that it had taken full responsibility for that server, which became the European Union server at eu.kobotoolbox.org. The old addresses forwarded until 29 February 2024. If an old form or phone still points at a humanitarianresponse.info address, change it to the EU server's addresses.The three sheets of an XLSForm
An XLSForm is an ordinary .xlsx workbook. Each row of the survey sheet is one question; each row of the choices sheet is one answer option; the settings sheet names and versions the form. Formatting, colours and column order are ignored, so you can shade and freeze rows to make the sheet readable.
The survey sheet
Three columns are required: type, name and label. The grey box shows the form this course uses. Each column below is explained in the next module.
sheet: survey
type name label relevant constraint constraint_message required choice_filter
select_one state state State yes
select_one district district District yes state=${state}
select_one area area Is this household rural or urban? yes
integer hh_size How many people usually live in this household? . >= 1 and . <= 30 Enter a number from 1 to 30 yes
decimal land_acres How many acres of land does the household own? ${area} = 'rural' . >= 0 and . <= 100 Enter 0 to 100 acres yes
select_one yes_no has_bank_account Does anyone in the household have a bank account? yes
select_one yes_no received_transfer Did the household receive a cash transfer in the last 12 months? yes
integer transfer_amount How much did the household receive in total (Rs)? ${received_transfer} = 'yes' . > 0 Enter an amount above zero yes
type:integer,decimal,text,date,geopoint,note(shows text, takes no answer),select_one listnameandselect_multiple listname.name: the variable name in your data. The XLSForm reference says names must be unique, must start with a letter or the_character, may contain only letters, digits, hyphens,_and periods, and are case-sensitive.label: the question exactly as the enumerator reads it.hintadds smaller guidance text under it.
The choices sheet
Three required columns: list_name, name and label. The word after select_one in the survey sheet must match a list_name exactly. The name column is what is saved in the data, so keep it short, lower case and free of spaces; the reference warns that choice names for select_multiple must not contain spaces, because a space separates the selected answers.
sheet: choices list_name name label state state bihar Bihar state kerala Kerala district gaya Gaya bihar district purnia Purnia bihar district kozhikode Kozhikode kerala district wayanad Wayanad kerala area rural Rural area urban Urban yes_no yes Yes yes_no no No
The settings sheet
Optional, but the reference recommends form_title, form_id and version at minimum. A common convention for version is yyyymmddrr: 2026100601 is the first revision of 6 October 2026. Change it every time you change the form, so you can tell which version produced each submission. instance_name builds a readable name for each submission from its answers.
sheet: settings
form_title form_id version instance_name
Household baseline 2026 hh_baseline_2026 2026100601 concat(${district}, '-', ${hh_size})
Check a form before you upload it
The cell below holds the same survey and choices sheets as CSV text and checks four mistakes that are easy to make by hand: duplicate or invalid names, a select pointing at a list that does not exist, a ${name} that refers to a question not yet asked, and a skip rule comparing a select with a choice name it does not have.
The form has 8 questions, 10 choices in 4 lists, and the check reports no problems.
${area} = 'rural' to ${area} = 'Rural' and run again. The check reports that area's choices are ['rural', 'urban']. The capital R is the label; the data holds the name. This mistake hides a question from every enumerator and raises no error on the phone. Then change hh_size in the first column of its row to hh size and see what the name check says.Skip logic, constraints and calculations
These columns are where a form stops entry errors before they reach your data. Every expression refers to an earlier answer as ${name}.
relevant: show the question only when the expression is true.${area} = 'rural'asks about land only in rural households.constraint: reject an answer unless the expression is true. The dot stands for the answer being entered:. >= 1 and . <= 30.constraint_message: what the enumerator sees when the constraint fails. Write it as an instruction ("Enter a number from 1 to 30").required:yesstops the enumerator moving on without an answer.required_messagecustomises the warning.choice_filter: narrows a choice list using an earlier answer. Add a column (herestate) to the choices sheet, thenstate=${state}on the district question shows only districts of the chosen state. The XLSForm reference calls these cascading selects.calculation, with typecalculate: computes a value from earlier answers. The reference notes that a calculation with no label and no hint is hidden.
sheet: survey
type name label calculation
integer hh_size How many people usually live here?
integer monthly_exp Total household spending last month (Rs)?
calculate pc_exp ${monthly_exp} div ${hh_size}
note pc_note Spending per person: ${pc_exp} rupees. Is that right?
Showing a derived figure in a note is one of the cheapest checks you can add: an enumerator who sees "Spending per person: 23 rupees" knows something was typed wrong. In ODK expressions, div is division.
Repeat groups: one set of questions per household member
Wrap questions between begin repeat and end repeat rows to ask them once per member, plot or child. repeat_count fixes the number of repeats; the XLSForm reference shows it set from an earlier answer, so the roster opens exactly ${hh_size} times. begin group and end group group questions on one screen without repeating them.
sheet: survey (a household roster)
type name label repeat_count relevant constraint
integer hh_size How many people usually live here? . >= 1 and . <= 30
begin repeat member Household member ${hh_size}
text member_name First name of this member
integer age Age in completed years . >= 0 and . <= 110
select_one yes_no in_school Is this member attending school? ${age} >= 5 and ${age} <= 17
end repeat
Run the same rules on the data you download
Constraints catch errors at entry, but not every error: a form version without the constraint, an answer edited on the server, a submission sent twice. The cell applies the form's rules to households.csv (illustrative data, invented for teaching: 240 households in ten real district names, with made-up answers). It then plants five entry errors and one duplicate submission in a practice copy and runs the same check.
The original file has 240 rows and 0 problems. The practice copy has 241 rows and 7 problems: the two out-of-range household sizes, the negative land, the urban household reporting land, the Y that should be Yes, and household 200 listed twice (one row per copy).
monthly_pc_exp above Rs 15,000 as "check with the enumerator". Write it as "pc_exp above 15000": df["monthly_pc_exp"] > 15000, inside rules and run again. A flag to check is different from an error: a large value can be true. Look at how many households it flags in the original file before you decide on the cut-off.Hindi and English in one form
One form can carry every language your enumerators use. The XLSForm reference names each language column label::language (code). The ODK form language guide explains: "Each language column adds two colons and the language name, followed by the two letter language code in parentheses", for example label::English (en). For Hindi the code is hi, so the column is label::Hindi (hi); Bengali is bn, Tamil ta, Telugu te, Marathi mr, Urdu ur.
sheet: survey type name label::English (en) label::Hindi (hi) integer hh_size How many people usually live in this household? इस परिवार में आमतौर पर कितने लोग रहते हैं? select_one yes_no has_bank Does anyone in the household have a bank account? क्या परिवार में किसी का बैंक खाता है? sheet: choices list_name name label::English (en) label::Hindi (hi) yes_no yes Yes हाँ yes_no no No नहीं sheet: settings form_title form_id version default_language Household baseline 2026 hh_baseline_2026 2026100601 Hindi (hi)
- The same suffix works on
hint,constraint_message,required_messageand media columns, and on the choices sheet'slabel. default_languageon the settings sheet sets the language the form opens in. Without it, the ODK guide says the form opens in the first language defined.- There is no fallback language. The ODK guide warns that if a column has language versions, a plain
labelcolumn is treated as a separate language and listed as Default in the language menu. Translate every column or none. - In KoboToolbox,
form_titlecannot take a language suffix; the XLSForm guide says translating it produces an error.
A translation added by hand is easy to leave half-finished: someone adds a question in English during the pilot and forgets the Hindi. The cell finds every row with English text and no Hindi.
It reports one gap: the shg_member question has an English label and no Hindi. The hh_size row passes because both its label and its constraint message are translated.
shg_member (between the two commas after the English text) and run again. Then rename the column label::Hindi (hi) in the choices text to label::Hindi and see what the check says. Have a fluent speaker who did not write the translation read every label aloud during the pilot; a check like this one finds missing text and cannot judge whether the Hindi is right.Deploy, collect offline and download
Upload and deploy in KoboToolbox
- On the Projects page, select NEW, then Upload an XLSForm, and choose your .xlsx file (from the KoboToolbox XLSForm guide, updated 28 August 2026).
- Enter the project details and click Create project.
- Click Preview and fill the form yourself, trying wrong answers on purpose to see each constraint message.
- Deploy the form. To change it later, open the FORM page, click Replace form, upload the new .xlsx and redeploy. Raise
versionfirst.
Set up phones
- Install KoboCollect from the Google Play Store. The setup guide (updated 23 April 2026) says newer versions require Android 8.0 or higher; older phones can install the last version that supports them.
- Enter the server URL, which differs from the login address:
https://kc.kobotoolbox.org/for the Global server andhttps://kc-eu.kobotoolbox.org/for the EU server. The project's FORM tab also shows it under Collect data. - Enter the enumerator's username and password. Once one phone is set up, its QR code configures the rest of the team's phones with the same settings.
- Select Download form and tick the form. ODK Collect uses the same menu; it is on Google Play too.
Collecting with no network
Once the blank form is on the phone, no connection is needed to fill it. The ODK Collect guide explains the cycle: a form saved part-way is a draft; tapping Finalize at the end locks it; finalized forms wait in Ready to send until the phone is online, then go to the server. Ask enumerators to sync every evening they have signal, so a lost phone loses one day's work at most.
Download the data
- Open the project and go to DATA > Downloads (export guide, updated 6 May 2026).
- Choose the type: XLS (recommended when the form has repeats), CSV, SPSS Labels, GeoJSON, GPS coordinates (KML) or media attachments (ZIP).
- Choose the value and header format. Labels is the default: question text as headers and choice labels as values. XML values and headers gives the
namecolumns and choice names. Pick XML values for analysis: question text makes poor column names, and labels change between languages. - Click EXPORT, then DOWNLOAD when the file appears in the list.
A daily check by field team
During fieldwork, download every day and compare teams. Large differences between teams working in similar areas are often a training problem. The cell joins households.csv to districts.csv (both invented for teaching) to get each household's field team.
All 240 rows join, with no unmatched districts. Team A covers four districts and 96 interviews; Teams B and C cover three districts and 72 interviews each. Read the three percentages side by side: here the bank account share runs from 84.4% to 88.9% across teams and the transfer share from 33.3% to 41.7%. In real fieldwork, a gap far wider than this deserves a phone call to the supervisor.
groupby("field_team") to groupby(["field_team", "area"]) and run again. Teams cover different mixes of rural and urban households, and a difference that disappears within area was a difference in where they worked.Data protection: encryption, access and the DPDP Act
A household survey holds names, phone numbers, locations, caste and income. Three layers protect it: who can see submissions, whether the server can read them, and what the law requires of you.
Who can see submissions
In KoboToolbox, open the project's SETTINGS page and select Sharing. The permissions guide lists separate permissions to view the form, edit the form, view, add, edit, validate and delete submissions, and manage the project. Enumerators need Add submissions only. Permissions can also be limited by row, so a district coordinator sees only submissions from their own enumerators.
Encrypted forms
The XLSForm reference says encryption keeps finalized records private while they are "stored on the device and server as well as during transport", and that encrypted records "are completely inaccessible to anyone not possessing the private key". You make a key pair, put the public key in the form and keep the private key.
# From the ODK documentation on encrypted forms. Run in a terminal (macOS, Linux) # or after installing OpenSSL on Windows. openssl genpkey -out MyPrivateKey.pem -outform PEM -algorithm RSA -pkeyopt rsa_keygen_bits:2048 openssl rsa -in MyPrivateKey.pem -pubout -out MyPublicKey.pem # Paste the text of MyPublicKey.pem, without the BEGIN and END lines and without line breaks, # into the public_key column. Keep MyPrivateKey.pem off shared drives and out of email.
sheet: settings form_title form_id version submission_url public_key Household baseline 2026 hh_baseline_2026 2026100602 https://kc.kobotoolbox.org/submission MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... (your whole key on one line)
- KoboToolbox's encryption guide (updated 22 July 2026) gives
https://kc.kobotoolbox.org/submissionas thesubmission_urlfor the Global server and the kc-eu address for the EU server. - After deployment, anything that reads the data inside KoboToolbox stops working, including the map view and exports. You download and decrypt on your own computer with ODK Briefcase and the private key.
- ODK Central can manage encryption for a project; the ODK encryption guide says Central's managed option lets you download a decrypted file without another tool.
- Lose the private key and the data is gone. Keep two copies, offline, with named custodians.
The DPDP Act 2023
India's Digital Personal Data Protection Act, 2023 (published 11 August 2023) applies to digital personal data, and a phone survey is digital from the first answer. The organisation that decides why and how the data is processed is the Data Fiduciary; the respondent is the Data Principal. The duties below, the exemption and the penalties apply from 13 May 2027 (notification G.S.R. 843(E), 13 November 2025), so design forms to them now. Sections that matter for a survey:
- Section 5: a request for consent must come with or after a notice telling the respondent what personal data is collected and why, and how to exercise their rights.
- Section 6(1): consent must be "free, specific, informed, unconditional and unambiguous with a clear affirmative action", limited to the data necessary for the stated purpose. Put the notice and a consent question at the start of the form and end the form if the answer is no (a
relevanton every later group does this). - Section 8(5): the Data Fiduciary must take "reasonable security safeguards to prevent personal data breach", including for processing done on its behalf by a Data Processor such as a survey firm or a hosting service. The Schedule to the Act sets a penalty for breaching this duty that may extend to Rs 250 crore.
- Section 17(2)(b): the Act's provisions do not apply to processing "necessary for research, archiving or statistical purposes if the personal data is not to be used to take any decision specific to a Data Principal and such processing is carried on in accordance with such standards as may be prescribed".
Share a file without identities
Before you share data with an analyst, replace the identifier with a code only the data manager can reverse, and coarsen exact values that could identify a household. The cell does both on households.csv (invented data) with a keyed hash.
The shared file keeps all 240 rows with a 10-character pid in place of hh_id, every pid is unique, and land is reported in four bands. The key table linking pid to hh_id stays with the data manager.
KEY and run again: every pid changes. That is why the key must be kept, and kept apart from the data. A keyed code makes the file pseudonymous; a village name, a household size and a caste together can still point to one family, so check small groups before you publish anything.Pilot testing a form
Every form has errors that only show up when a real enumerator asks a real respondent. A pilot finds them while they are still cheap to fix.
- Desk test. Fill the form yourself in Preview, once with ordinary answers and once trying to break every constraint. Check that each skip opens and closes when it should.
- Phone test. Install the form on the cheapest phone your team will use, switch on airplane mode, fill five forms, then sync. This tests offline storage, the screen size and the Hindi font on that phone.
- Field pilot. Interview 15 to 30 households outside the sample, in each language. Note every question respondents ask to have repeated, and every answer that did not fit the choices.
- Check the data. Download the pilot submissions as XML values and run your checks (module 3) on them. A constraint that never fires may be too loose; one that fires often may be wrong, or the question may be unclear.
- Fix and version. Change the form, raise
version, replace the form, delete the pilot submissions or mark them, and record each change and its reason in a change log.
What to look for in pilot data
- Many answers of "other": the choice list is missing a common answer.
- Answers piling up at the edge of a constraint (exactly 30 members, exactly 100 acres): the limit is probably wrong or enumerators are using it to get past the screen.
- A question skipped far more or less often than you expected: check the
relevantexpression and the choice names it compares. - Interview length by enumerator: the XLSForm metadata types
startandendrecord the start and end date and time of the survey; add them as rows in the survey sheet if your form does not have them.
start, end and a consent question select_one yes_no named consent. Wrap the rest of the form in begin group and end group rows with ${consent} = 'yes' in the group's relevant. Upload it to KoboToolbox and test that answering no ends the interview.Where next
Spreadsheets for M&E
Build indicator tables from the data you downloaded.
pandas for development data
Clean, check and summarise survey exports in Python.
OpenRefine
Fix district and village names typed five different ways.
Survey Design 101
Questions, sampling and piloting before you build the form.
Data Protection and the DPDP Act
What the law asks of you when you collect personal data.