How-To · Stata

Published November 2026 · 11 min read

How to Automatically Code Open-Ended Responses in Stata: .dta In, .dta Out

Stata is excellent at everything that happens after a variable is numeric. Open-ended survey answers are not numeric. They sit in a str or strL variable, and the usual options are a wall of strpos() rules or an export to Excel for hand-coding that strips your labels on the way back. This tutorial shows a third option: upload the .dta, approve a codeframe, and get the same .dta back with labelled 0/1 category variables you can drop straight into tabstat, logit or mrtab.

Sample files for this tutorial

A fictional library patron survey with 240 respondents, labelled categorical variables and two open-ended string variables.


The Input: What's in the .dta

Run use library_survey_2026.dta, clear and describe, and you will see this structure:

Variable Kind Value label Variable label
resp_idnumericRespondent ID
branchnumeric1 Central … 4 WestgateBranch visited most often
age_groupnumeric1 18-29 … 99 Prefer not to sayAge group
satisfactionnumeric1 Very dissatisfied … 5 Very satisfiedOverall satisfaction with the library
q_improvestringWhat one thing would most improve your library?
q_reasonstringWhy did you give that rating?

The Do-It-Yourself Approach, and Where It Breaks

Most Stata users start with pattern matching:

gen txt = lower(q_improve)
gen byte hours   = strpos(txt, "hour") | strpos(txt, "close") | strpos(txt, "open")
gen byte quiet   = ustrregexm(txt, "quiet|silent")
gen byte parking = strpos(txt, "park") > 0

Then you list q_improve if hours, and the trouble starts:

  • "The car park closes before the library does" matches both hours and parking. It is about parking.
  • "Stay open past 6pm so I can come after work" is caught only because you added open, and that same stem will catch "open-plan seating" or "more open space" in the next survey.
  • "It gets very noisy after school" never says "quiet", so the quiet-space flag misses it.

Each fix adds another clause, and the rule set only works for this one question. It is also hard to defend in a methods section: "we flagged answers containing 'close'" invites the obvious follow-up question.

The AI-Assisted Workflow

  1. Upload the .dta (up to 20 MB). Variable labels and value labels are read along with the data.
  2. Pick the string variables to code. The picker shows each variable's label and a sample answer. Add a line of context per question if it helps ("library patrons; keep building issues separate from digital services").
  3. Get a proposed codeframe. The AI reads up to 200 answers and suggests four to seven non-overlapping categories (5 credits per question on packs, included on monthly plans). Or skip that step for free and type the codeframe you already have.
  4. Edit and approve it. Rename, merge, split, delete, or ask AI refine to rework it. The order you leave them in is the order of the output variables.
  5. Classification runs in the background at 1 credit per non-empty answer. Blank answers are free. An answer can get more than one code.
  6. Check and edit the codes. Flagged low-confidence answers come first, and you can recode one response or a filtered group in one step. Edits go straight into the .dta, and a review log records AI vs. final codes.
  7. Download updated_library_survey_2026.dta.

The Output: New Variables in the Same .dta

Open library_survey_2026_coded.dta and describe q_improve_c01-q_improve_none:

Variable Values Variable label
q_improve_c010 No / 1 YesWhat one thing would most improve your library?: Longer opening hours
q_improve_c020 No / 1 Yes…: More books and new titles
q_improve_c030 No / 1 Yes…: Quieter study space
q_improve_c040 No / 1 Yes…: Better Wi-Fi and computers
q_improve_c050 No / 1 Yes…: More events and activities
q_improve_c060 No / 1 Yes…: Parking and access
q_improve_none0 No / 1 Yes…: none of the above
  • Names fit Stata's rules. They are built from your variable name plus _c01, _c02… and stay inside the 32-character limit. A long source name is shortened, and clashes with existing variables are avoided. The category text lives in the variable label.
  • Consecutive and numbered, so varlist ranges like q_improve_c01-q_improve_c06 and wildcards like q_improve_c* work.
  • Labels carry over. Every original variable keeps its variable label and value label.
  • q_improve_none is 1 for answers that fit no category and for blank answers. Restrict to q_improve != "" when you want "% of those who answered".

A Do-File for the Coded Data

use "updated_library_survey_2026.dta", clear

* Stata has no user-missing values: turn 99 (Prefer not to say) into .a
mvdecode age_group, mv(99=.a)

* Share of respondents (who answered) mentioning each theme
summarize q_improve_c01-q_improve_c06 if q_improve != ""

* Theme shares by branch
tabstat q_improve_c01-q_improve_c06 if q_improve != "", ///
    by(branch) statistics(mean) format(%4.2f)

* One multiple-response table (user-written: ssc install mrtab)
mrtab q_improve_c01-q_improve_c06 if q_improve != ""

* Do people who want better Wi-Fi rate the library lower?
regress satisfaction i.q_improve_c04 i.branch if q_improve != ""

* Read the verbatims behind a code before you report it
list resp_id q_improve if q_improve_c04 == 1, noobs clean

The tabstat line on the sample file gives the share of answering respondents in each branch who raised each theme:

ThemeCentralNorthsideRiversideWestgate
c01 Opening hours0.300.240.200.24
c02 Books and titles0.180.100.050.12
c03 Quiet space0.240.160.270.20
c04 Wi-Fi and computers0.140.290.270.29
c05 Events0.180.140.200.09
c06 Parking and access0.220.240.230.12

Central patrons are the ones asking for longer hours. The other three branches have a Wi-Fi and computers problem. That is the kind of finding the open-ended question exists to surface, and it took one line of Stata once the coding was done. (Branch subsamples here are small, so treat it as an illustration, not a significance test.)

Making It Reproducible

Stata users care about reproducibility, and AI coding raises fair questions. Three habits answer most of them:

  • Save the codeframe with the project. Keep the approved category list (in order) in your project folder next to the do-file. On Research Pro it can be saved as a versioned codebook and loaded into the next run in one click.
  • Keep the coded .dta as a frozen input. Treat updated_*.dta like raw data. Every downstream step lives in the do-file.
  • Report a validation check. Hand-code a random subsample (sample 60, count on a copy) and report agreement with the AI codes. Typical agreement is typically 85–95% agreement with human coders, depending on how clear your categories are.

Frequently Asked Questions

Does it work with strL variables and long answers?

Yes. Any string variable can be coded. Answers longer than 5,000 characters are truncated before classification, which in practice only affects essay-length responses.

Can I code several open-ended variables in one go?

Yes. Select them all. Each gets its own codeframe and its own block of _c01… variables.

What does a typical study cost?

1 credit = one classified response to one question. A 1,000-respondent survey with two open ends is about 2,000 credits. Packs start at $25 for 850 credits, and monthly plans start at $100 for 4,000 credits. 80 free credits come with every new account.

The short version

Replace fragile strpos() rules with an AI pass over a codeframe you approve. Upload the .dta, download the .dta with labelled _c01… variables, and analyze with the commands you already use.

Try It on the Sample .dta

80 free credits, no credit card. Upload the sample, then your own data.

The SurveyCat Team

SurveyCat is a self-serve verbatim coding tool for researchers, analysts and agencies. It reads and writes Stata, SPSS, Excel and CSV so coding fits the workflow you already have.

Related reading

AI Coding of Open-Ended Survey Responses in SPSS
How to Reuse a Codebook Across Survey Waves
AI Tools for Academic Research Survey Analysis