Survey authoring

Data & flows

Dayalogs separates runtime data sources from the flow controls that use them. First you decide where respondent context comes from, then you decide how that context changes what the survey shows.

How they fit together — start with contact structured data, survey variables, URL parameters or API calls, then use repeats and visibility rules to turn that context into a dynamic survey.

About the examples — they explain how the feature works. In normal use, Dayalogs or your AI assistant prepares this structure for you and you review the result rather than writing every field by hand.

Structured audience data

Use structured data already stored on the contact record to drive the survey.

API calls

Load structured data from your own systems before the survey starts, without exposing credentials in the browser.

Flow controls

Use visibility rules and repeats to decide what appears and how many times it appears.

Live survey data does not have to come from an API — repeats and conditions can also use structured data already stored on the contact record, such as products, children, locations, or purchases attached to a personalized link.

Data sources

Data in Dayalogs can already be present on the personalized contact, can arrive through the survey URL, can be stored in survey variables, or can be fetched from an external API. The flow tools later in this guide can use these sources together.

Structured audience data

Personalized links in Dayalogs can carry more than simple fields like name or email. A contact record can also contain structured data, including grouped values and lists, and the survey can read that data directly.

This is useful when the survey already knows something about the respondent before the first page: a list of recent purchases, household members, stores, classes, employees, children, or products that should drive the flow.

  • Use scalar contact values for interpolation and simple conditions.
  • Use contact arrays when a repeat needs one iteration per item.
  • Use grouped values when several pieces of information belong together, such as one product’s name, category and price.

For example, a contact could include a last_products list, and the survey could ask one follow-up per product without calling any external API. In practice, this means many surveys can run entirely from the data already attached to the personalized link.

Survey variables and URL parameters

Survey variables are named, non-visible values inside the survey definition. They are useful when you want to normalize one value once and then reuse it in interpolation, conditions, endings, or exports.

URL parameters arrive through the survey link and are available through @urlparams. That makes them useful for campaign identifiers, partner codes, panel respondent ids, channel tags, or any other external context passed in the URL.

  • Use @urlparams when the value comes from the incoming survey link.
  • Use survey variables when you want one internal name the rest of the survey can reuse.
  • Use a variable when several blocks, conditions or endings should refer to the same normalized value.

A common pattern is to read @urlparams.gid or @contact.department once, map it into a survey variable, and then reuse that variable across the survey instead of repeating the original path everywhere.

API calls

An API call lets the survey fetch structured data from one of your systems before the respondent sees the first question. The call runs server-side, so you can use secrets or auth headers without exposing them in the public page.

That returned data can then be reused in question text, visibility rules, or repeats.

API calls are only one source of live data. If the same information is already present on the contact used by a personalized link, the survey can read it directly without making a call.

JSON markup
{
  "id": "responsable",
  "alias": "v_responsable",
  "type": "json",
  "source": {
    "type": "api",
    "method": "GET",
    "url": "https://example.test/api/household",
    "headers": { "X-SURVEY-SECRET": "example-api-secret" },
    "query": { "id": "{{ @contact.id }}" },
    "response_path": "response"
  }
}
  • API secrets live in the survey definition, usually as an auth token or custom header. The call still runs server-side, so the secret is not exposed in the public survey page.
  • Treat survey files and version history as sensitive when they contain API credentials.
  • Use response_path when the useful data is inside a deeper level of the API response.
  • For non-critical calls, consider a fallback instead of making the survey hard-fail.

Flow controls

Once that data exists, Dayalogs uses two main tools to turn it into respondent-specific behavior: visibility rules and repeats.

Conditional questions

visible_if is the main tool for conditional flow in Dayalogs. It uses positive logic: if you omit it, the item is shown; if you add it, the item is shown only when the expression is true.

Use it when part of the survey is only relevant to some respondents: a follow-up after a low score, a whole section for one audience segment, or a branch driven by URL, contact, or API data.

  • Put it on a question when you only want to gate one field.
  • Put it on a block when you want to gate a whole subtree of questions or nested blocks.
  • Use presentation on the block to control whether its direct questions share a screen; presentation never owns flow logic.
JSON markup
{
  "id": "p24_reason",
  "type": "text",
  "title": "What went wrong?",
  "visible_if": { "question": "p24_recommend", "op": "eq", "value": 1 }
}

You can also combine conditions with all, any, and not, or check live values instead of answers with var.

Available comparison operators

The same comparison options are available for answers and live values. What matters is the kind of value you are comparing.

Operators
Use with
Meaning
answered, not_answered
Any answer or live value
Checks presence only. These operators do not take a value.
eq, not_eq
Scalar values: single choice, text, number, boolean, URL/contact/API scalar fields
Simple equality or inequality against one value.
in, not_in
Scalar values, or arrays when you want overlap semantics
Matches when the answer/value is one of the values in the provided array.
contains, not_contains
Array answers or array-based live values
Best for multi, rank, or JSON arrays where you want to test membership of one item.
lt, lte, gt, gte
Numeric values
Numeric comparisons. The referenced value and the comparison value must both behave numerically.
between, not_between
Numeric values
Inclusive range comparison using [min, max] as the value.
starts_with, not_starts_with
Text values
Checks whether a string begins with one prefix, or any prefix from a string array.
ends_with, not_ends_with
Text values
Checks whether a string ends with one suffix, or any suffix from a string array.
matches, not_matches
Text values
Full regular-expression match using a regex string without delimiters.

Practical rules: use contains for multi-select style arrays, in when your answer is scalar but the allowed set is plural, and the text operators only when the target is genuinely text. Negative range and text operators still require the referenced value to be present.

Repeats

A repeat loops a question or a block once per item in a list. Instead of hard-coding three versions of the same section, you declare the logic once and let Dayalogs run it once per child, product, selected option, or scale row.

Each iteration exposes a current_item object, so the repeated part can refer to the item currently in focus.

  • Use a repeated block for a group of questions.
  • Use a repeated question when only one field needs to loop.
  • Keep a repeated group inside one repeated block so its questions share the same iteration context.
JSON markup
{
  "type": "block",
  "id": "children_loop",
  "title": "Questions for {{ current_item.name }}",
  "repeat": {
    "source": { "type": "variable_path", "path": "family.children" },
    "as": "child"
  },
  "items": [
    { "type": "question", "question": "p10_child_score" }
  ]
}
        

The most common repeat sources are a list stored in a variable, a question count, selected or unselected options from an earlier answer, or the matching rows of a scale question.

That list can come either from an API call or from structured contact data already attached to the respondent. For example, if a personalized contact record includes a last_products list with each product’s name, category, and price, the survey can repeat once per item and ask whether the price of {{ current_item.price }} for {{ current_item.name }} felt right.

For question_scale repeats, the filtering happens in the repeat source itself. If you use a source like { "type": "question_scale", "question": "p4_teachers", "op": "gt", "value": 3 }, Dayalogs only creates repeat iterations for rows whose score is above 3. Inside each matched iteration, the selected score is available as current_item.value.

If you then add a visible_if using current_item.value inside that repeated flow, it acts as an extra condition on the already-filtered iteration; it does not broaden the repeat back out to all scale rows.

How they work together

The strongest pattern is to combine all four ideas. Start with structured respondent data from a contact record or an API call, repeat over the list you loaded, and then use visible_if inside that repeated flow to reveal only the relevant follow-ups.

A typical example would be: fetch a customer file, show the products attached to that customer, and ask a few targeted questions about their most recent purchases.

Gotchas

  • Conditions should reference earlier context. Avoid forward references in the flow.
  • Repeat paths must resolve to arrays. An object is not enough.
  • Live values are part of the survey setup. If an API response changes shape, your text, conditions, or repeats may need updating.
  • Keep the condition names consistent. Use the standard operator names like eq rather than inventing alternatives.

Quick reference

You want to...
Use...
Show a follow-up only after one answer
visible_if on the question itself.
Show or hide a whole section
visible_if on the block.
Ask the same thing once per child, store or product
A repeated block.
Ask one repeated field without a full section
A repeated question item.
Drive a survey from nested data already stored on the respondent
Structured audience data on the contact record.
Carry external identifiers from a panel or campaign link
@urlparams, optionally normalized into a survey variable.
Give one reusable name to a respondent-specific value
A survey variable.
Load respondent-specific data from your systems
An API call.
Repeat over products, children or purchases already stored on the contact
A repeat whose source points to structured contact data.
Combine data loading, loops and branching
API calls + repeats + visible_if.