# Save to Contact Field

Write a value onto one of this workspace's custom contact fields, so an answer collected in the conversation lives on the record instead of only in the transcript.

## Getting here

**Automate → Workflows**, open a workflow, click **+** on the canvas, then pick **Save to Contact Field** under **Add Steps**.

## Before you start

- An **owner**, **admin** or **agent** can add this step and save the workflow. Publishing that workflow — the thing that makes it run on live conversations — is an **owner** or **admin** action.
- Building and running workflows depends on your plan; see [pricing](/pricing).
- The custom field must already exist under **Settings → Custom fields**. This step cannot create one.

## Set up

1. Open the workflow and click **+** where the write belongs.
2. Pick **Save to Contact Field**.
3. Choose the field under **Contact field** — only fields already defined for this workspace are listed.
4. Set **Value**, usually a placeholder like `{{answer.text}}` right after an **Ask a Question** step, or plain text.
5. Save the step, then publish the workflow. A saved but unpublished workflow writes nothing.

## Fields

| Field | What it means | Limits |
| --- | --- | --- |
| Contact field | Which of this workspace's declared custom fields to write. | Lists only fields already created under Settings → Custom fields; this step cannot create one. |
| Value | The text to store, usually a placeholder that resolves from the run. | A value that resolves to nothing fails the step rather than clearing the field — see When it fails. |

## How it works

- The step resolves the contact behind this conversation and writes the value into that field on `contacts.attributes`, replacing whatever was there before — it never merges or appends.
- The field key is checked against this workspace's declared custom fields before anything is written; a key that is not one of them is refused rather than saved into a place nothing else reads.
- The value is rendered through the run's placeholders and trimmed before it is written, so `{{answer.text}}` becomes the customer's actual answer.
- The previous value is remembered for the run. If this same run also tries to send the customer something and every one of those sends fails, the field write is rolled back to what it held before — unless something else has changed the value again since. A run that never tries to send anything to the customer is not affected by this.
- The same writer backs **Ask a Question**'s own "save response as a contact field" option, so a value saved either way behaves identically once it lands on the record.

## When it fails

- No field chosen: the step fails outright — this can only happen on a step an AI builder saved with no key, since the drawer requires picking one.
- The field named is not one this workspace has declared: the step fails with **“<field>” is not a contact field in this workspace — create it under Contacts → custom fields**, and nothing is written. (That message names the wrong menu path — the real one is **Settings → Custom fields** — a copy bug in the product, not in this article.)
- This conversation has no linked contact: the step fails with **this conversation has no contact to write to**.
- The value resolves to an empty string — a missing placeholder with no fallback text, for example: the step fails with **nothing to store in “<field>” — the value resolved to empty**, rather than writing a blank that a later condition on “exists” would then wrongly pass.
- A failed write does not stop the run: the step is recorded failed and the flow moves straight to the next one, with the field left exactly as it was.

## Limits

- It cannot create a custom field — only write to one that already exists.
- It cannot clear a field to empty. Writing an empty value fails the step instead of blanking the record; there is no “remove this field's value” action.
- It always replaces the field's value; it cannot append to, or merge with, whatever is already stored.
- It only writes to the contact behind this one conversation — not to any other contact, and not to the conversation itself.
- It does not fire this workspace's **Contact Field Updated** trigger for other workflows — only a change made in (Contacts, the inbox sidebar, the app, or the public API) does; use **Trigger Another Workflow** to hand off on purpose instead. This is narrower than "cannot start a chain": writing a **date**-typed field is still visible to **Contact Date Reached**, which checks, every 10 minutes, the date field each published Contact Date Reached workflow names, regardless of who wrote the value, so a date saved by this step can still start that trigger's workflows.

## Best practices

- Place it directly after the **Ask a Question** step whose answer it stores, so the placeholder it reads is still fresh in the run.

## Use cases

- After asking "What's your monthly budget?", save `{{answer.text}}` into a `budget` contact field so it shows on the contact sidebar for the next conversation, not just this one.
- Save `{{payload.plan}}` from an inbound webhook onto a `signup_plan` field, so a later broadcast can segment by it.

## Related

- [Ask a Question](https://inchat.inseller.my/help/workflows/ask-a-question)
- [Update Lifecycle](https://inchat.inseller.my/help/workflows/update-lifecycle)
- [Tag Contact](https://inchat.inseller.my/help/workflows/tag-contact)
- [Workflows: how a flow runs](https://inchat.inseller.my/help/workflows/workflows-overview)

---

Source files: `src/lib/workflows/ai-builder/spec.ts`, `src/lib/workflows/canvas-model.ts`, `src/components/workflows/WorkflowStepConfigDrawer.tsx`, `src/lib/workflows/engine-record-actions.ts`, `src/lib/workflows/engine.ts`, `src/lib/workflows/engine-contracts.ts`, `src/lib/workflows/workflow-input-schema.ts`, `src/lib/workflows/contact-triggers.ts`, `src/lib/workflows/date-triggers.ts`, `src/components/layout/nav-items.ts`
