Skip to content

Surveys, NPS and quizzes

Paid add-on. A form can analyse its answers: distributions for a survey, a Net Promoter Score, or a numeric mark for a quiz. The reports live on a dedicated screen and export to CSV and PDF.

This document describes what the module guarantees and what it refuses. The user guide gives the short version, under “Measuring answers”.

The idea

The setting lives in the form’s settings, under survey. There is no configuration table: a form exported and re-imported takes its questionnaire with it, and a duplicated form duplicates it.

{
  "survey": {
    "enabled": true,
    "mode": "quiz",
    "pass_percent": 60,
    "privacy_threshold": 5,
    "questions": [
      { "field": "q_safety", "weight": 2, "points": { "report": 1, "gloves": 0 } }
    ]
  }
}

Three modes: survey, nps, quiz. An unknown value does not fall back to the most harmless one — a corrupted or forged setting produces no analysis at all, because an analysis quietly different from what is configured is worse than a missing one: it looks right.

The fields that can be analysed

Choices (select, radio, checkbox), numbers (rating, range, number, nps) and text (text, textarea).

The list is a whitelist. A password, a file, a signature, a payment are not on it — and will not appear on it through an oversight, since it is inclusion that opens, not omission. Fields the core declares sensitive are set aside a second time, so that a type added to this list tomorrow stops being aggregated without anyone having to think about it.

A text question carries a volume and nothing else. Aggregating free text means reading it, and a word cloud surfaces fragments of individual answers — a proper name, a town, a recognisable turn of phrase — in a report that promises precisely not to. Only the number of people who answered is kept; the text stays in the submission.

A quiz’s score

The maximum follows what the respondent saw. Conditional logic is the source of truth and the server has already resolved it: a question that was skipped is absent from the retained values, and counts towards neither the score nor the maximum. Counting it would penalise somebody for a question they never saw, and two respondents following two branches would no longer have comparable percentages — when the percentage is what makes them comparable.

It is the presence of the key that counts, not the value: a question shown and then left empty counts towards the maximum and earns zero. That is a failure on that question, not an absent question.

Negative points lower the score, never the maximum: nobody is obliged to incur a penalty, and including it would make a perfect paper come out below a hundred per cent. The total is floored at zero.

Three states, one of which is not a failure: passed, failed, and unscored — there was nothing to mark. Conflating them would show a failure to somebody who never sat the test, and would drag down a report’s pass rate for papers that do not belong in it.

NPS

NPS = 100 × (promoters − detractors) / valid answers

promoters  : 9–10
passives   : 7–8
detractors : 0–6

The mode requires the Recommendation (NPS) field, and only that one. The core’s rating field starts at one, and a slider is configured however you like: accepting either would mean computing an NPS on a scale that is not the formula’s, for a score that would always look like an NPS.

A mark outside the scale is set aside rather than clamped into range: the denominator counts only valid answers, which is what the formula designates. Zero answers yields an absence of score, never zero — a null NPS is a real result, and showing it for a form with no answers would pass an absence of data off as average satisfaction.

Questionnaire versions

schema_hash is a SHA-256 of the questionnaire’s meaning: mode, questions, options, points, weightings, pass mark. Changing an option’s label changes the fingerprint, because it changes what the answer means.

The privacy threshold is not part of it: it governs what is shown, not what was asked. Putting it in would cut the series in two the day an administrator moves the threshold from five to ten, without a single question having changed.

Every result carries a snapshot of the labels and scales of its time. A report on last year’s answers therefore carries last year’s wording: re-reading the current configuration would mean a simple rename rewrote history, and nobody would know that the series before and the series after do not measure the same thing.

The “all versions” filter exists, and the label says what it does: it adds up series that are not comparable.

The privacy threshold

Five answers by default, adjustable per form, never below three. Below that, a distribution designates somebody.

It applies at two levels: to the whole report, which then shows only a volume, and to each question taken on its own — an optional question may have received only two answers in a report counting fifty.

When the report is hidden, the link to the submissions disappears too: a report that announces it protects small groups must not offer, right next to it, the means of reading them one by one.

The decision is carried by the report, not by the display. The page, the CSV and the PDF read the same object. A rule written into the page’s template would be bypassed by the first export that came along, and a file in circulation is the worst kind of leak.

What the tables keep

No address, no name, no IP address, no user agent, no field content. answer_key carries an option’s technical value — yes, pro_plan, 8 — never its wording. entry_id is enough to find the submission again, for whoever already has the right to read it.

Reports exclude spam, trashed entries and drafts. The status is not copied: every aggregate joins the submissions table and reads the real status, so that an entry classed as spam leaves the report that very instant, with no catch-up task.

Deleting a submission erases its result and its answers. A daily task also removes results whose submission disappeared by other means — a direct SQL query, a site migration, or a deletion while the add-on was deactivated.

The charts

There are none, in the sense that there is nothing extra to describe. The bars are backgrounds laid into the cells of a table that carries the figures: the width gives the order of magnitude, the number gives the measurement. A screen reader reads numbers because there have only ever been numbers, and the table stays whole in print as in the PDF.

No colour carries meaning: two series are told apart by their column.

The exports

The CSV carries a header — form, version, period, generation date, threshold — then the summary, the segments or score bands, one row per question and per answer, and the daily series. It begins with a BOM, without which Excel reads UTF-8 as Latin-1 and mangles every accent from the first line.

The PDF rests on the same engine as the signed receipts, isolated behind PdfEngineInterface. It is produced on demand and sent as a download; nothing is written to disk, a report dropped into the uploads being an address to guess.

Neither contains an individual answer. Exporting the submissions remains the explicit path to answer data, with its own rights.

What the module does not do

No shared question bank, no random draw, no time limit, no multiple attempts, no manual marking, no certificate. No advanced statistical model, no demographic weighting, no text analysis. No individual ranking, no public display of names or answers. No comparison between forms: that would require a contract on questions and versions that V1 does not establish.

Calculated fields, repeaters and sensitive values cannot carry a scale.

Rights

Configuring it requires solis_forms_manage_forms. The reports follow solis_forms_view_entries and the author restriction: a user limited to their own forms can neither select nor guess the results of somebody else’s, and the check is applied to the query, not to the display.