Images in XLSForm Questions and Choices: ODK, Kobo
To add a picture to an XLSForm question, type its file name, such as muac_tape.png, in the image column of that row; to give each answer option its own picture, add an image column to the choices sheet with one file name per choice. ODK Collect, KoboToolbox and SurveyCTO show the picture with the question or the option, and every example below compiles with pyxform and ODK Validate, the same check ODK Central runs when you upload a form.
What is the syntax for an image in a question?
Add a column called image to the survey sheet and type the file name in the row of the question that needs the picture:
| type | name | label | image |
|---|---|---|---|
| integer | muac_mm | Read the MUAC tape at the middle of the upper arm and enter the value in mm. | muac_tape.png |
| select_one yes_no | oedema | Press both feet with your thumbs for 3 seconds. Does a dent stay on both feet? | oedema_check.png |
| list_name | name | label |
|---|---|---|
| yes_no | 1 | Yes |
| yes_no | 0 | No |
The picture shows below the question text, and the enumerator answers as usual. Three rules decide whether it appears:
- The cell holds a file name, not a path. Type
muac_tape.png, neverC:\Pictures\muac_tape.pngor a web address. - The name must match the uploaded file exactly, case included.
MUAC_Tape.PNGis a different file. - The column can also be called
media::image. Both spellings compile to the same form.
The image column works on any row type, notes included. A note with a picture and no question is how you show a logo or an instruction card; see adding a logo to an XLSForm.
How do I add pictures to answer choices?
Add an image column to the choices sheet. Each choice row gets its own file name, and a choice with an empty cell simply shows no picture:
| type | name | label |
|---|---|---|
| select_one toilet_type | toilet | What kind of toilet facility do members of this household usually use? |
| list_name | name | label | image |
|---|---|---|---|
| toilet_type | 1 | Flush or pour-flush toilet | flush_toilet.png |
| toilet_type | 2 | Pit latrine with slab | pit_slab.png |
| toilet_type | 3 | Pit latrine without slab or open pit | pit_open.png |
| toilet_type | 4 | Composting toilet | composting.png |
| toilet_type | 5 | Bucket or hanging toilet | bucket.png |
| toilet_type | 6 | No facility (bush or field) | no_facility.png |
| toilet_type | -96 | Other |
Pictures help most when the words are not enough: toilet and water source types, food items, crop diseases, livestock breeds or stages of a building. The respondent can point at the right picture instead of guessing what "pit latrine with slab" means.
Keep a text label on every choice, even when you only want the picture to show. A choice with an image and an empty label still compiles, but pyxform warns On the 'choices' sheet, the 'label' value is invalid. Choices should have a label. The label is also what you read in the exported data and in screen readers.
How do I show the choice pictures as a grid?
A long list of pictures, one under the other, makes the enumerator scroll. The columns-2 appearance lays the choices out in two columns, and no-buttons drops the radio buttons or check boxes so each picture becomes the button:
| type | name | label | appearance |
|---|---|---|---|
| select_multiple food_group | foods_eaten | Which of these foods did the child eat yesterday? Tap every picture that applies. | columns-2 no-buttons |
| list_name | name | label | image |
|---|---|---|---|
| food_group | 1 | Grains roots and tubers | grains.png |
| food_group | 2 | Beans peas and lentils | pulses.png |
| food_group | 3 | Milk and dairy | dairy.png |
| food_group | 4 | Meat fish and poultry | meat_fish.png |
| food_group | 5 | Eggs | eggs.png |
| food_group | 6 | Dark green leafy vegetables | leafy_greens.png |
| food_group | 7 | Other fruits and vegetables | fruit_veg.png |
How the layouts differ in ODK Collect:
| Appearance | What the enumerator sees |
|---|---|
| None | One picture per row, with its label and a radio button or check box |
columns-2, columns-3 and so on (columns-n) | That many columns, each with label and button |
columns | As many columns as the screen width allows |
columns-pack | As many choices per line as fit, in uneven columns |
no-buttons | Only the pictures, without the label or the button; add a columns appearance for a grid |
The ODK documentation notes that more than two columns can feel crowded on a small phone screen, and small pictures are easy to mix up. Other select appearances, such as minimal and likert, are in the XLSForm appearance column guide.
How do I let the enumerator zoom into a picture?
Add a big-image column with a larger, more detailed copy. The small file from the image column shows in the form; tapping it opens the big one full screen, where the enumerator can pan and zoom:
| type | name | label | image | big-image |
|---|---|---|---|---|
| note | catchment_map | Your enumeration area is marked in red. Tap the map to make it bigger. | ea_map_small.jpg | ea_map_large.jpg |
| select_one yes_no | in_ea | Is this household inside the area marked in red? |
big-image also works on the choices sheet, for example a close-up of a leaf disease next to each choice. It does not work with the no-buttons appearance: those choices show no media buttons, so there is nothing to tap.
How do I use a different picture for each language?
When the picture holds text, such as a show card with written answers, name an image column per language, the same way as the label columns. The picture changes when the enumerator switches language:
| type | name | label::English (en) | label::French (fr) | image::English (en) | image::French (fr) |
|---|---|---|---|---|---|
| note | ladder_card | Show the respondent the card and ask them to point at their answer. | Montrez la carte à la personne interrogée et demandez-lui de montrer sa réponse. | ladder_en.png | ladder_fr.png |
| integer | ladder_step | Which step of the ladder are you on today? (0 to 10) | Sur quelle marche de l'échelle êtes-vous aujourd'hui ? (0 à 10) |
On the choices sheet, use the same pattern: label::English (en), label::French (fr), image::English (en) and image::French (fr). If the labels have languages but the image column does not, the form still compiles, but pyxform warns Language 'English (en)' is missing the choices image column. Name both columns the same way. A picture without words still needs an image:: column per language; put the same file name in each. Setting up the language columns is covered in adding languages to an ODK form.
Can I add audio or video instead of a picture?
Yes. The audio and video columns work like image, on the survey sheet and on the choices sheet, and a row can have all three. Collect shows a play button next to the text:
| type | name | label | audio | video |
|---|---|---|---|---|
| note | consent_audio | Play the consent statement to the respondent in their language. | consent_statement.mp3 | |
| note | ors_demo | Watch how to prepare the oral rehydration solution before you show the mother. | ors_demo.mp4 | |
| select_one yes_no | consent | Does the respondent agree to take part? |
Audio helps respondents who cannot read: they can listen to each option instead. Keep recordings short and files small, because every phone downloads them with the form.
What if the image names are only in a CSV file?
ODK Central asks for the files that the XLSForm names. If image names live only inside an attached CSV, for example a product list, Central does not list them and you cannot attach them. The workaround the ODK team suggests in its forum is a hidden question whose choices name every image:
| type | name | label | relevant |
|---|---|---|---|
| select_one product_photos | media_list | Product photos used by the price list | false() |
| text | shop_id | Enter the shop ID from the listing sheet. |
| list_name | name | label | image |
|---|---|---|---|
| product_photos | 1 | Rice | rice_5kg.jpg |
| product_photos | 2 | Lentils | lentils_1kg.jpg |
| product_photos | 3 | Cooking oil | oil_1l.jpg |
relevant is false(), so the question never shows and stays empty in the data, but Central now asks for the three files and Collect downloads them with the form.
What size and format should the images be?
Use PNG or JPG, and keep each file small: every phone downloads every image with the form, often over mobile data. The ODK documentation's advice for images in forms:
- Make all images the same size, for example 300 x 300 pixels.
- Keep the background simple, with even space around the subject.
- Use icons from one library, in one style, so no picture stands out more than the others.
- Test in light and dark mode. A transparent PNG with dark lines can disappear on a dark screen.
Avoid SVG files in the image column. In ODK forum tests, SVG pictures could not be zoomed in Collect and opened badly in some phones' default viewers. SVG is right only for the image-map appearance, where the enumerator taps regions of the picture.
Common mistakes with images in XLSForm
Most of these compile without an error. They show up on the phone or in ODK Central:
| You wrote | Write instead | What you will see |
|---|---|---|
| A choice with an image and no label | Keep the label; no-buttons hides it on screen | On the 'choices' sheet, the 'label' value is invalid. Choices should have a label. |
label::English (en) with a plain image column on choices | image::English (en) next to label::English (en) | Language 'English (en)' is missing the choices image column. |
image::English (en) with a plain label column on choices | Name the label and image columns the same way | Language 'English (en)' is missing the choices label column. |
A column called images or picture | image or media::image | No error and no pictures; the column is ignored |
Pit_Slab.PNG in the cell, pit_slab.png uploaded | The exact file name, case included | ODK Central lists the file as still expected |
| One choice image not uploaded | Attach every file before publishing | Collect may show another choice's picture in that place |
big-image with no-buttons | Drop no-buttons, or drop big-image | No error; the large image cannot be opened |
A PNG with the image-map appearance | An SVG with an id on each tappable region | No error at upload; nothing to tap on the phone |
For other messages, see common XLSForm errors, or paste the form into the free XLSForm validator.
Does this work the same in ODK, KoboToolbox and SurveyCTO?
The idea is the same everywhere: a file name in a media column, and the file uploaded with the form. The column names and the upload step differ:
| Platform | Media columns | Where you upload the files |
|---|---|---|
| ODK Central (Collect and Web Forms) | image or media::image, big-image, audio, video | Attach them to the form draft before publishing |
| KoboToolbox (KoboCollect and web forms) | image or media::image, audio, video | Project Settings > Media, then redeploy |
| SurveyCTO | media:image, plus the audio and video columns in its template | Attach them with the form definition |
SurveyCTO's own form template spells the columns with a single colon. ODK Web Forms has added media support in stages, so open the web form preview as well as Collect before fieldwork. In KoboToolbox, if a picture shows in the preview but not in the deployed form, first check that the file under Settings > Media has exactly the name in the cell.
When are pictures worth adding?
Add them where they change the answer: items that have no local name, categories respondents confuse, and questions for people who cannot read. A WASH survey that shows a photo of each toilet type gets fewer "other, specify" answers than one that only lists the names. Leave them out of questions the words already answer, because each picture adds download size and screen space.
You can ask for it in plain language instead: "add a picture to each toilet type choice and show them as a two-column grid". LooprAI writes the image column and the appearance and compiles the form with pyxform before anything is saved; then attach the image files in the form's media.
Next: XLSForm appearance column →
Frequently Asked Questions
How do I add an image to a question in ODK?
Add an image column to the survey sheet and type the file name, such as muac_tape.png, in the question's row. Upload the XLSForm to ODK Central, attach the image to the draft when Central lists it as expected, then publish.
How do I put images on select_one choices?
Add an image column to the choices sheet and type one file name in each choice row. Keep the text label too. Upload every image with the form; a choice whose image cell is empty shows only its label.
Why are my choice images not showing in KoboToolbox?
Usually the file names do not match. Check that each name in the image column matches a file under the project's Settings > Media exactly, case included, and that you redeployed after uploading. Also check the column is called image or media::image.
Can the enumerator zoom into an image?
Yes. Add a big-image column with a larger copy of the picture. Collect shows the small image from the image column, and tapping it opens the big one full screen with pan and zoom. It does not work with the no-buttons appearance.
Do I need a separate image for each language?
Only when the picture holds text, such as a show card. Then add image::English (en) and image::French (fr) columns next to the matching label columns. A picture without words can use the same file name in every language's image column.
No Credit Card Required
Build the form first. Add hosting when you need it.
Start free with LooprAI, then deploy a managed ODK Central server or run DataSnap checks when your project is ready.
Automation handles the mechanical work.
Researchers decide what the evidence means.