---
title: "How do you run a customer survey from your CRM and get the answers back onto the record?"
blueprint: 012
slug: customer-survey-answers-onto-the-record
category: Feedback
revised: 2026-09-10
platform: Coevera CRM (formerly Pipeliner CRM)
canonical: https://blueprints.coevera.com/blueprints/customer-survey-answers-onto-the-record/
publisher: Coevera
customer_data: none
---

# How do you run a customer survey from your CRM and get the answers back onto the record?

**Short answer.** Coevera has a native **online forms** subsystem, and the survey is a form. The
form definition names **exactly one entity type** it can attach to. A submission creates a
**response record** holding the answers, and the form's own settings decide what happens next:
link the response to the surveyed record, **write the answers onto it**, or create a new record.

Form submission is one of only **four** process trigger types — alongside record change, schedule
and manual — so a survey is a first-class automation event rather than something you detect after
the fact.

The caveat is the metric. The built-in **response rate is responses ÷ unique recipients**, so it
is blank for any form you published rather than emailed, and reads over 100% as soon as one
recipient answers twice.

## 01 · The business problem

There are moments when a customer will tell you something useful: just after a renewal, just after
a meeting, a few weeks after going live, at the point a relationship is being reviewed. Asking is
the easy half. The hard half is that the answer has to arrive where the person who acts on it
already works.

A satisfaction score in a spreadsheet is not an intervention. The manager who owns the
relationship opens the customer record, and if the record says nothing about the survey, the
survey did not happen. So the requirement is not "run a survey" — it is:

- ask at a moment triggered by something in the CRM,
- have every answer attributable to a specific customer, deal or contact,
- have the answers land on that record as values a report and a filter can see,
- alert the right person when a particular answer arrives,
- and know who was asked and has not replied.

That last one is the requirement people forget, and it is the one that decides whether the
exercise produces a follow-up list or a vanity number.

## 02 · Why the obvious approach fails

### A survey tool plus an integration

The default reach is a dedicated survey product with a CRM connector. It fails on attribution. The
connector matches responses to records on an email address, and an email address is exactly the
thing that does not survive a real send: the recipient forwards the invitation to a colleague,
answers from a personal address, or is one of four people at the same company. What arrives is a
response the CRM cannot place, and the usual outcome is a silently unmatched response — or worse,
one matched to the nearest wrong record.

### Building the questions as fields and mailing an edit link

The next idea is to put the questions on the customer record as fields and send the customer a
link to edit them. There is no such link. Record forms are internal; they exist behind
authentication and role permissions, and no configuration exposes one to an unauthenticated
respondent.

### Detecting a submission by watching a field

The received wisdom is to add a "terms accepted" or "survey completed" checkbox, make it mandatory
on the form, and hang a change-triggered process off it. This works, and it is genuinely the
pattern to use when a survey arrives from outside the platform. It is the wrong default here, for
three reasons:

- **It fires on the wrong record.** A change-triggered process on the account sees the account. It
  cannot see which form was answered or what the answers were, because those live on a separate
  response record.
- **A second submission may not fire it.** The sentinel field is already `true`. A repeat response
  changes nothing, so nothing runs.
- **It is unnecessary.** Form submission is a native trigger type. The sentinel is a workaround
  for a gap that is not there.

### One form for the whole customer journey

The last mistake is structural rather than mechanical: assuming one questionnaire can follow a
customer across the journey. A form definition names one entity type. A pre-meeting questionnaire
that must attach to a lead before conversion and an opportunity after it is two form definitions,
not one form with a switch.

## 03 · Data model

Three entities carry a survey, and the first thing to get straight is which one is which, because
the names are misleading.

| Entity | What it actually is | Key properties |
|---|---|---|
| **Online form type** | The **form definition** — the survey you designed | `name`, `entityType` (one only), the layout, a required `styleId`, a public `link` and `linkId`, `isEnabled`, `hasDraft`, and the counters `sentCount`, `sentUniqueCount`, `responseCount`, `responseRate`, `lastResponseDate` |
| **Online form** | A **single submitted response**. Not the form. | `answers`, `respondedBy`, `responseDate`, `onlineFormTypeId`, its own `customFields`, and `primaryAccount` / `primaryContact` / `primaryLead` / `primaryOpportunity` / `primaryQuote` / `primaryCustomEntity` |
| **Online form relation** | The join from one response to the records it concerns | `accountId`, `contactId`, `leadOpptyId`, `quoteId`, `projectId`, `customEntityId`, plus `isPrimary` |

> **Naming trap.** The entity called *online form* is a response, and the entity called *online
> form type* is the form. Everything reads correctly once you translate "type" as "definition" and
> "form" as "submission".

### What a response can attach to

The relation join carries account, contact, lead, opportunity, quote, project and custom entity,
with one of them flagged primary. So a single response can sit on the account *and* the deal it
was asked about, and the primary flag is what a report groups by.

A custom entity is admitted by both the entity-type enum and the relation. That is schema-verified
but not behaviour-verified — no live example of a custom-entity-bound form was available to read.
It matters because it is the opposite of the approval subsystem, which cannot target a custom
entity at all; see [Blueprint
001](https://blueprints.coevera.com/blueprints/one-entity-five-request-types/).

### The answers themselves

An answer is a pair: the id of the form field, and a **string** value. There is no typing in the
response. A rating of 4 arrives as text, a multi-select arrives as text, a date arrives as text.
Everything you intend to filter, average or chart has to be written out to a typed field on a
record — which is what §04 and §05 are for.

### Who was asked, and who answered

Responses roll up per form into four categories, and they are the reporting surface that matters
more than the response count:

| Category | What it gives you |
|---|---|
| `Sent` | Every record the form was sent to |
| `Responded` | Records that answered — records, not responses |
| `SentAndNotResponded` | **The chase list.** This is the one that makes a survey operational |
| `UnknownRespondents` | Responses that arrived but matched no record |

### The alternative that was rejected

Modelling a survey response as a custom entity is the reflex when a platform's native subsystem
looks thin. Here it costs more than it gives: you would rebuild the public URL, the send tracking,
the four roll-up categories, the unknown-respondent bucket, the response PDF and the submission
trigger, and you would still have no form renderer. The decision framework for that judgement is
[Blueprint 003](https://blueprints.coevera.com/blueprints/where-should-this-data-live/). A custom
entity is the right answer when what you need is a *reviewable* record with its own lifecycle and
owner — which a response is not. The response record does take custom fields of its own, so a
derived score can live on the response without a new entity.

## 04 · Field-level configuration

### The field types available on a form

Fifteen, and the absences matter as much as the presences:

| Group | Types |
|---|---|
| Text | single-line input, text area, email, phone |
| Numeric | integer, float, **rating** |
| Choice | dropdown, radio, multi-select checkbox, single checkbox |
| Temporal | date, date-time |
| Other | file upload, products & services |
| **Absent** | no lookup field, no currency field |

The products-and-services field is worth knowing about on a survey rather than an order form: it
turns "are you interested in additional services?" into a priced selection against a named price
list, so an expression of interest arrives already quantified. Pricing behaviour is in [Blueprint
007](https://blueprints.coevera.com/blueprints/pricing-one-product-many-prices/).

### What every form field carries

| Property | Purpose |
|---|---|
| `fieldId` | The CRM field this question maps to |
| `required`, `visible`, `readOnly` | Standard; `visible: false` is load-bearing — see below |
| `prefillEnabled`, `prefillType` | `Field` draws from a record field, `Custom` uses a fixed value |
| `prefillFieldId`, `prefillLookupFieldId` | Which record field, optionally across a lookup |
| `conditionalRulesFilter` | A normal field filter — this is how a question appears only when an earlier answer warrants it |
| `name` | The question label, and it is **HTML**. Paste from a document and the pasted colours travel with it |

### Rating fields

A rating field is bounded by `valueFrom` and `valueTo` with `valueFromLabel` and `valueToLabel` as
anchors. A net-promoter question is `0`–`10` labelled *Most unlikely* / *Most likely*; a
satisfaction question is `1`–`5`; a traffic-light is `1`–`3`. Same field type, three surveys. Pick
the bounds once — changing them later invalidates comparison with every response already
collected, and nothing warns you.

### How the response finds its record — the central decision

Three settings on the form, and choosing between them is the whole design:

| Situation | Setting | How identity arrives |
|---|---|---|
| Sent to a known person about a known record | `linkRecordEnabled` | From the send itself. No answer is needed to establish identity, and autolink stays off |
| Published on a page or embedded in an email | `autolinkEnabled` + `autolinkFormFieldId` + `autolinkRecordFieldId` | One form field is matched against one record field |
| The respondent is not in the CRM yet | `createRecordEnabled` | A new record is created from the answers |

The elegant part is how prefill and autolink combine. Put an email field on the form, **prefill it
from the record's email field**, and set **autolink to match that same form field against that
same record field**. Sent from the record, it arrives pre-filled and attaches instantly. Reached
cold from a published link, the respondent types their address and it attaches anyway. One
configuration, both paths.

Alongside it, carry the identity you actually trust in **hidden prefilled fields**: `visible:
false`, `prefillEnabled: true`, pointed at the account name and the account identifier. They never
render, they travel in the link, and they give the response an identity that does not depend on
what the respondent typed.

### Writing answers onto the surveyed record

With `updateRecordEnabled`, the form carries an update template — an ordinary record template
whose values are `ppl-tag` references to *form fields*:

```
{"customFields": {
  "cfLikelyToRecommend":
    "<ppl-tag data-id=\"{rating-form-field-id}\" data-relation-type=\"Responses\"></ppl-tag>",
  "cfSurveyDateFilled":
    "<ppl-tag data-id=\"CurrentDate\"></ppl-tag>",
  "cfSurveyRespondent":
    "<ppl-tag data-id=\"{first-name-field-id}\" data-relation-type=\"Responses\"></ppl-tag> <ppl-tag data-id=\"{last-name-field-id}\" data-relation-type=\"Responses\"></ppl-tag>",
  "cfSurveysCompleted": ["{option-uuid}"]
}}
```

- `data-relation-type="Responses"` is what pulls the value from the submission.
- `CurrentDate` is a built-in tag — stamp the submission date here, not in a process.
- Two tags in one target value **concatenate**, which is how first and last name become one field.
- A dropdown or multi-select target is set by **option UUID**, never by label.
- Every key in the template is part of the write. Keep it to the fields you intend to change: a
  key carrying an empty value is still in the payload. Whether an empty value clears the target
  field or is skipped was not tested.

### The rest of the settings worth setting deliberately

| Setting | Why it matters for a survey |
|---|---|
| `limitToSingleResponse`, `checkForExistingResponse` | Both default off. Leaving them off is what lets one recipient answer repeatedly — and what breaks the response rate (§06) |
| `notificationRecipientType` | `Owner` \| `PrimaryRecordOwner` \| `Custom`. `PrimaryRecordOwner` mails the owner of the record the response attached to — the relationship manager. A bare alert needs no process at all |
| `attachResponseAsPdf` | Files the completed questionnaire on the record as a document. This is what makes the survey auditable a year later |
| `responseAcceptanceDateLimitEnabled` + date | Closes the survey on a date with your own title and message, instead of collecting stragglers into a period you already reported |
| `responseAcceptanceThresholdType` | `TotalResponses` \| `CustomCondition` \| `ProductsLimits` — capacity limits, for a survey that doubles as a registration |
| `recordIdentificationEnabled` | Asks the respondent to identify their own record when autolink cannot |
| `confirmationPageType` | `ConfirmationPage` \| `ExternalUrl` |
| `attachFiles`, `maxTotalUploadedFilesSize` | Needed if any question invites an attachment |

## 05 · Automation & logic

### Submission is a trigger type

The platform has exactly four process trigger types: record change, schedule, manual, and **online
form submission**. A survey response is therefore a first-class event, not something inferred from
a field that moved.

The trigger names three things, and the first one surprises people:

| Property | Value | Consequence |
|---|---|---|
| `entityType` | the response | **The process runs on the response record**, not on the customer. Its filters read answers |
| `recordType` | account, opportunity, lead, … | What the response attached to, so actions can reach the customer record through the relation |
| `onlineForms` | a **list** of form ids | One process can serve many forms — a family of sibling questionnaires shares one automation |

That list is the useful part. Where a survey is fanned out as several near-identical forms — one
per department, one per audience — the whole set can hang off a single process rather than one
process per form.

### One form, several processes

The reverse is also true, and it is not a smell. A process carries exactly one filter at its root,
and that filter's branches are **first-match-wins**. So four independent things to do with one
submission — acknowledge it, route the rating, open a task if a meeting was requested, notify a
product owner if a feature was named — are four processes, because any one of them can be true at
the same time as the others. This is the same constraint that decides process counts everywhere
else in the platform; [Blueprint
011](https://blueprints.coevera.com/blueprints/keeping-hundreds-of-automations-maintainable/)
covers it and the naming discipline that keeps such a family legible.

### The rating router

The pattern that earns its keep: filter on the rating band, and send a different message per band.
A low score mails the relationship owner immediately; a high score mails whoever collects
references. Both are branches of one filter, because a response has exactly one rating — this is a
genuine set of alternatives, so one process is correct.

### Turning answers into structure

Two routes, with very different costs:

| Route | Cost | Use when |
|---|---|---|
| The form's own update template (§04) | Declarative, one write, no process | The answers belong on the surveyed record as its current state — latest score, date last surveyed, latest verbatim |
| A process creating a related record per answer | **One node per answer.** A twenty-question survey is a twenty-node process, and it grows every time a question is added | Each answer must be its own reviewable row with a history — where the second survey must not overwrite the first |

Reach for the template first. The related-record route is the right answer when history matters,
but it is the expensive one and it is where survey automation becomes unmaintainable fastest.

### Sending the thing

A form has a public link, so sending is an ordinary email action carrying that link with the
prefill parameters. The consequence is that **the send is the identity**: a process that mails the
link from the record is also what puts that record in the `Sent` category, which is what makes
`SentAndNotResponded` — the chase list — exist at all. A survey published on a web page has no
chase list, by construction.

## 06 · Limits & trade-offs

> **The built-in response rate is responses ÷ unique recipients.** It is not a response rate in
> the sense anyone means it. It is blank for every form that was never emailed, and it exceeds
> 100% as soon as one recipient submits twice — which nothing prevents, because
> `limitToSingleResponse` is off by default.

In a production estate of 74 form definitions with three years of history, the arithmetic held
exactly on all 30 forms reporting a rate, and:

- **10 of those 30 reported over 100%.**
- **44 forms reported no rate at all** — 21 of which were holding **491 responses** between them.
  A form that is published rather than sent has a divisor of zero, so it has no rate, however many
  people answered.

Treat the figure as meaningful only for a form that is sent rather than published *and* limits
each recipient to one response. Otherwise compute your own rate from the `Sent` and `Responded`
categories, and be aware that `Responded` counts *records*, not responses.

### Other limits, in the order they bite

- **A form belongs to one entity type.** A questionnaire that must attach to a lead before
  conversion and an opportunity after it is two definitions, two answer mappings, and either two
  processes or one process naming both forms. There is no inheritance between them: a question
  added to one is not added to the other.
- **A public form with autolink and record-update both enabled is a write endpoint.** Anyone who
  supplies a value matching the autolink record field writes to that record. If the matching field
  is an email address, the form is only as safe as the guessability of your customers' email
  addresses. Keep public forms to `createRecordEnabled` and reconcile, or autolink on a value that
  only the intended recipient could hold.
- **Unmatched responses are preserved, but nothing works them.** They land in `UnknownRespondents`
  — which is much better than being discarded or misattached, and on one live embedded survey held
  **10 of 39 responses**. But it is a bucket, not a queue: no owner, no task, no ageing. Give it a
  human and a cadence, or it becomes a place where customer feedback goes to be counted and not
  read.
- **Answers are strings.** Nothing about a response is typed or aggregatable in place. Anything to
  be charted, averaged or filtered has to be written to a typed field by the template or a process
  — which means a question nobody mapped is a question nobody can report on, even though the
  answer is stored.
- **A response outlives the record it points at.** Both the response and the per-record summary
  carry an availability flag, so a deleted or inaccessible record leaves responses pointing at
  nothing. Survey history is not a reason to keep a record, and deleting a record does not clean
  up its responses.
- **The platform's summarised response value cannot be relied on.** The field exists on both the
  form and the per-record summary, and it was **null on every one of the 74 forms** examined.
  Compute the score you care about into a field of your own; do not build a report on that
  property.
- **Disabling a form retains its responses.** Eleven disabled forms in the estate still held
  responses. Disabling is therefore safe as an archival step — but it is not a delete, and the
  responses stay attached to their records and visible in reports.
- **Rating bounds are not versioned.** Changing `valueFrom` or `valueTo` silently makes new
  responses incomparable with old ones. Nothing marks the discontinuity.

### The trade-off worth stating plainly

Native forms buy attribution, a submission trigger, a chase list and an answer-to-field mapping
that needs no code. What they do not buy is a survey platform: there is no panel management, no
reminder scheduling of their own, no cross-form benchmarking, and no statistical analysis. If the
requirement is a research instrument, this is the wrong tool. If the requirement is that the
account record knows what the customer said and someone gets told — which is nearly always the
actual requirement — it is the right one, and it is the only option where the answer lands on the
record without an integration in between.

## 07 · Verification

Read from a live production space on 2026-09-10: 74 form definitions accumulated over three years,
their settings, their field-level configuration, their response roll-ups, and the processes
triggered by them.

- **The response-rate formula was checked arithmetically** against every form reporting one — 30
  forms, zero mismatches with responses ÷ unique recipients × 100. The 44 forms reporting no rate
  all had zero recorded sends.
- **The four roll-up categories were read per form**, and one embedded survey is what pinned the
  arithmetic down: 170 sent, 155 sent-and-not-responded, 23 responded, 10 unknown respondents,
  against a response count of 39. Responded plus unknown does not equal the response count because
  `Responded` counts records; sent minus not-responded does not equal responded because eight
  respondents were never sent it and arrived through the embed.
- **Two contrasting live configurations were read in full.** An embedded survey with
  `autolinkEnabled` and `updateRecordEnabled` on and `linkRecordEnabled` off; and a sent fan-out
  with `linkRecordEnabled` on and both of the others off — identity from the send in one case,
  from an answer in the other.
- **The update template was read verbatim** from a live form, which is where the `ppl-tag` shape,
  the `Responses` relation type, the `CurrentDate` tag, tag concatenation into a single target and
  option-UUID dropdown targets all come from.
- **Form-triggered automation was counted:** 32 processes in the space use the online-form
  trigger, every one of them with the response as its trigger entity. One is bound to six sibling
  forms at once; one form is served by four separate processes.
- **Conditional question visibility was confirmed in use** — a products-and-services question on a
  live survey carries a field filter and appears only when an earlier answer warrants it.

**Not observed, and stated as such:**

- The public submission path itself — every finding here is read from stored configuration and
  stored results, not from a submission made for the purpose.
- A populated summarised response value. It was null everywhere it appears.
- A custom-entity-bound form. Schema-verified but not behaviour-verified.
- Whether an empty value in the update template clears the target field or is skipped.
- Whether a disabled form's public link rejects new submissions, as distinct from retaining the
  old ones — which was verified.

### What would signal a regression

- **A send-only form's rate dropping below the number of responses you can see** means sends have
  stopped being recorded, which silently destroys the chase list.
- **A rising unknown-respondent count** is the single most useful alarm here: it means the
  identity path — prefill, autolink, or the send itself — has broken, and it will show up as "the
  survey is working fine" on every other measure.
- **A response count rising while the mapped fields on records stay stale** means the update
  template stopped applying. Check the record, never the submission confirmation.

## Related blueprints

- [Blueprint 011 — How do you keep hundreds of CRM automations
  maintainable?](https://blueprints.coevera.com/blueprints/keeping-hundreds-of-automations-maintainable/)
  — why one form needs several processes, and how to name them.
- [Blueprint 003 — How do you model something your CRM has no object
  for?](https://blueprints.coevera.com/blueprints/where-should-this-data-live/) — the framework
  behind rejecting a custom entity for responses.
- [Blueprint 001 — How do you run five different kinds of customer request through one help
  desk?](https://blueprints.coevera.com/blueprints/one-entity-five-request-types/) — the approval
  subsystem's custom-entity limit, which forms do not share.
- [Blueprint 007 — How do you price one product differently per region, segment or
  contract?](https://blueprints.coevera.com/blueprints/pricing-one-product-many-prices/) — what
  the products-and-services question is priced against.

---

Published by Coevera. Abstracted to the reusable pattern — no customer names, no client
data, no personal data.
