Decode answer values

For backend or app engineers who receive funnel answers as option IDs and want meaningful values. You'll have a tiny lookup — in any language — that turns interests=3,2 into ["Finance", "Wellness"]. You need the Variables Schema exported from your funnel (one click in the dashboard).

Why answers arrive as IDs#

When a visitor answers a choice question (single-select, multi-select, rating, slider), Zellify stores their pick as a short, stable option ID — "2", or ["3","2","4"] for multi-select — not the text they saw on screen. IDs are compact, never change when you edit option wording, and are safe to forward in a URL.

That trade-off is why you sometimes see interests=3,2 instead of words. The mapping from ID to meaning lives in the Variables Schema.

There are two places you'll receive these answers, and they differ in one important way:

SourceShapeAlready has the label?
Registration webhook answers{ "value": "2", "label": "1-5 years" } per questionYes — read label directly
Deep Link Button URL parameters?relationship_length=2&interests=3,2 (IDs only)No — you must decode
If you only consume the webhook, you may not need this: The Registration webhook already includes a label next to each value. The Deep Link Button forwards only IDs (URLs stay short), so decoding is required there — and it's also how you normalize answers to your own canonical values rather than Zellify's display text.

Step 1 — Export the Variables Schema#

The schema is a JSON array describing every question in your funnel: its name (the key you receive answers under), its questionType, and — for choice questions — the full list of options with id and label.

  1. Open Dashboard → Funnels
  2. Click Edit Funnel
  3. Open the Variables tab in the right sidebar
  4. Click Copy Variables Schema
  5. Save it next to your handler (e.g. variables-schema.json) and commit it
variables-schema.json
1[2  {3    "name": "primary_goal",4    "questionType": "singleselect",5    "questionText": "What's your main goal?",6    "options": [7      { "id": "1", "label": "Build a habit" },8      { "id": "2", "label": "Improve focus" },9      { "id": "3", "label": "Reduce stress" }10    ]11  },12  {13    "name": "relationship_length",14    "questionType": "singleselect",15    "questionText": "How long have you been together?",16    "options": [17      { "id": "1", "label": "Less than a year" },18      { "id": "2", "label": "1-5 years" },19      { "id": "3", "label": "6-10 years" }20    ]21  },22  {23    "name": "interests",24    "questionType": "multiselect",25    "questionText": "What are you interested in?",26    "options": [27      { "id": "1", "label": "Productivity" },28      { "id": "2", "label": "Wellness" },29      { "id": "3", "label": "Finance" },30      { "id": "4", "label": "Fitness" }31    ]32  }33]

The full field reference (including range and image/icon options) is in the Payload reference.

Step 2 — Decode, in three steps#

The logic is the same in every language:

  1. Index the schema by question name so you can find a question in O(1).
  2. For a choice question, build an id → label map from its options.
  3. For each incoming answer, split multi-values (an array, or a comma-joined string), then map each ID through that lookup, falling back to the raw ID if it's not found.

Questions with no options (email, text, number, range) have nothing to map — pass them through unchanged.

Decode to your own values, not just ours: Point the id → ... map at whatever your system uses — Zellify's display label, your own enum, a slug, a database key. The lookup doesn't care what the target is.

How each question type decodes#

questionTypeRaw value you receiveDecode to
email / textthe stringitself — no options
numberthe numberitself
singleselect / sliderone option ID, e.g. "2"options[id].label
multiselectIDs — array ["3","2"] (webhook) or comma string "3,2" (deep link)list of labels
range"from-to", e.g. "18-35"split on - for the bounds
consent / terms"1" or "0"options[id].label → e.g. "Accepted" / "Declined"

Worked example#

A Deep Link Button on your success page forwards three answers:

?primary_goal=1&relationship_length=2&interests=3,2

Decoded against the schema above:

ParameterRawDecoded
primary_goal1Build a habit
relationship_length21-5 years
interests3,2["Finance", "Wellness"]

Gotchas#

  • Multi-select arrives differently per source. The webhook gives an array (["3","2"]); the Deep Link Button gives a comma-joined string ("3,2"). The snippets above handle both.
  • Some options have no text label. Rating scales and image pickers can ship options with label: "" plus an image or icon field — the meaning is the picture the user saw, not text. There, the ID itself (e.g. "5" on a 1–7 scale) is usually the value you want; map it to your own wording if you need words.
  • Branching funnels → most keys are absent. If your funnel splits into paths, the schema lists every question across all paths, but a given visitor only answers the ones on their path. Treat a missing key as "not asked" — don't assume every schema entry shows up.
  • Don't split free text on commas. Decode by questionType (as the snippets do), not by blindly splitting every value — a text answer like "Doe, Jane" contains a comma but isn't a multi-value.
  • IDs are stable; the schema is a snapshot. Deleting an option never renumbers the others, and new options get the next free ID — so keying on IDs is safe. But labels and the set of questions change when you edit the funnel. Re-export and re-commit the schema whenever the funnel changes, and diff it like any generated artifact.
Payload reference
Full Variables Schema spec — every field, every question type, including range and image options.
Deep Link Button
The success-page component that forwards selected variables as URL parameters.
Registration webhook
Receive answers server-side, with a label already attached to each value.
app_user_id
The identifier that joins these answers back to the user in your system.