Data export

Export survey data to SPSS

There are two ways to get an SPSS file out of a Siamang project, and the difference between them matters more than any documentation usually admits: one gives you numbers, the other gives you a codebook.

The one-click download: fast, unlabelled

In the project’s response database, choose Export → SPSS (.sav). You get a file that opens in SPSS immediately, with your variable names and the numeric codes as collected.

What it does not carry is metadata. Variable labels, value labels and measure levels are not written, so gender arrives as 1, 2, 3 and 99 with nothing to say that 99 was a refusal. For a quick look, or for handing data to someone who has the codebook already, that is fine.

The labelled export: a real codebook in the file

Because the questionnaire is code, the codebook is already declared — each variable knows its label, its value labels and which codes are missing and why:

gender = Variable(
    "gender", scale="nominal", label="Gender",
    labels={1: "Woman", 2: "Man", 3: "Non-binary", 99: "Prefer not to say"},
    # 99 is a refusal, not a category — analysis can exclude it cleanly.
    missing=(MissingValue(99, "Prefer not to say", kind="refusal"),),
)

An analysis script in the project can write that metadata into the file using the engine’s writer:

from siamang.io import SPSSWriter

SPSSWriter(survey_data).write("outputs/responses_labelled.sav")

That file carries the variable labels, the value labels, the user-missing ranges and the nominal/ordinal/scale measure levels. Opened in SPSS, the Variable View is populated rather than empty — and because the script ran in the sandbox against a pinned commit, the same script on the same commit produces the same file.

Which one to use

The download is immediate; the script takes a run, a few seconds. That is the only axis on which the button wins — the diagram further down is the rest of the comparison.

If the .sav is going to a colleague, a client or a journal replication package, use the script. If you just want to eyeball the data, use the button.

Why the metadata is the point

A survey dataset without its codebook is a table of integers, and reconstructing one after the fact is how analysis errors get made — a refusal counted as a category, an ordinal scale treated as continuous. Keeping the codebook in the instrument, and letting the export carry it, is the whole argument behind reproducible survey research.

The difference in one picture

Same variable, two files

The codebook is already declared in the questionnaire — labels, value labels, and which codes are missing and why. The only question is whether the export carries it, and that is decided by which route you take, not by the file extension.

This is why a .sav from a colleague sometimes opens with a populated Variable View and sometimes opens as a grid of integers.

Unlabelled versus labelled SPSS export The same gender variable, declared once in the questionnaire with value labels and 99 marked as a refusal. The one-click download writes bare codes 1, 2 and 99. An analysis script using SPSSWriter writes the value labels and keeps 99 typed as a refusal, so SPSS excludes it from analysis. Declared once, in the questionnaire gender: 1 Woman · 2 Man · 3 Non-binary 99 Prefer not to say — kind="refusal" Download button one click gender 1 2 99 no labels 99 is a category SPSSWriter, in a script runs on a pinned commit Gender Woman · Man Non-binary 99 = refusal, excluded Both open in SPSS. Only one has a Variable View. variable labels · value labels · measure · missing ranges Names truncate at 64 characters — the SPSS limit, not ours Timezone-aware timestamps are written as naive local values Either route: 100,000 rows per export
Before you rely on it

Limits and caveats

  • The one-click download is unlabelled. It writes the data and the variable names; variable labels, value labels and measure levels come from an analysis script using the engine's SPSSWriter.
  • Variable names are truncated to 64 characters, which is the SPSS limit, not ours.
  • Timezone-aware timestamps are written as naive local values — the offset is dropped rather than converted.
  • 100,000 rows per export. Larger tables need a connector or a script.
  • Non-scalar cells are flattened: nested values become JSON strings, and UUIDs and decimals become text.
FAQ

Questions

Why is my downloaded .sav missing the value labels?

Because the download button writes data, not metadata. It calls pyreadstat with the frame alone, so SPSS opens it with variable names and numeric codes but no labels. A labelled file comes from an analysis script — see below.

How do I get a labelled .sav then?

Write it from a script in your project using the engine's SPSSWriter, which passes column labels, value labels, missing ranges and measure levels through to the file. The script runs in the sandbox and the .sav lands in the run's outputs.

Does the codebook survive the round trip?

Through SPSSWriter, yes — that is what it is for. Variables carry their label, their value labels and their typed missing values (refusal, don't know, not applicable and so on) rather than a bare 99.

Can I get Stata instead?

Yes, .dta is supported, though today it is reachable through the export API rather than the download menu in the UI. Stata truncates variable names at 32 characters and prefixes any name starting with a digit.

Do I need a paid plan to export?

No. Exporting your own data is available on every plan including Free — it is not a feature we gate. Connectors, which push data into an external system, are the part that needs Plus or Pro.

See it on a real study

The demo is a complete study — questionnaire, responses, analysis — with no account and nothing to install.

Last reviewed 2026-08-17.