# Untag Contact

Remove one or more tags from the person behind this conversation — clears the old state when someone moves forward, so a segment or broadcast stops targeting them for it.

## Getting here

**Automate → Workflows**, open a workflow, click **+** on the canvas, then pick **Untag Contact** 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).
- Nothing outside Inchat has to be connected. The step only writes to the contact behind this conversation.

## Set up

1. Open the workflow and click **+** where the removal belongs.
2. Pick **Untag Contact**.
3. Leave **Action** on **Remove Tag** and **On** on **Contact** — switching either turns this into Untag Conversation, Tag Conversation or Tag Contact instead, since all four share one editor.
4. Pick one or more tags from the chips.
5. Save the step, then publish the workflow. A saved but unpublished workflow removes nothing.

## Fields

| Field | What it means | Default | Limits |
| --- | --- | --- | --- |
| Action | Add Tag or Remove Tag. | Remove Tag | Choosing **Add Tag** saves this as the Tag Contact step instead. |
| On | Whether the tag comes off the contact or off this one conversation. | Contact | Choosing **Conversation** saves this as the Untag Conversation step instead. |
| Tags | Chips for every tag already used somewhere in the workspace. Several may be picked on one step. | — | A free-text box to type a name only appears when the workspace has no tags at all yet — with any tag already in the workspace, Remove offers chips only, so you cannot type a name that is not on the list. |

## How it works

- The step resolves the contact behind this conversation and rewrites `contacts.tags` with the named tag taken out — the same column **Tag Contact** writes and Contacts, segments and broadcasts read.
- Removing a tag the contact does not carry — including one that only differs in letter case from what the contact actually has — is a no-op success: nothing is written and the step still counts as ok, so a branch can clear a whole set of mutually exclusive tags without first checking which one is set. This is the pairing the product expects: a flow that marks a contact `no_show` should remove it in the same branch that later marks them `attended`, or the tag can only ever grow.
- Naming several tags on one step tries every one of them, even if an earlier one in the list failed to write, and the step is recorded failed if any of them did.
- Removal matching is exact and case-sensitive against whatever is currently stored — the workspace's tag list holds one canonical spelling per name (folded there when the tag was added), so naming this step's tag in a different case than that stored spelling is the no-op above, not a match. A name saved in another case — typed while the step was on Add Tag, or written by the AI builder — is that no-op.
- A tag actually removed (not a no-op) is logged to the contact's Activity tab, marked as removed by a workflow (or by the AI agent, when the step runs inside an AI turn).

## When it fails

- This conversation has no linked contact: the step fails with **this conversation has no contact to tag**, and nothing is written.
- A database error reading or writing the contact — rare and transient — also fails the step, with no specific reason set: the run's **Activity** tab shows the fixed line **failed without a reported reason**.
- A failed removal does not stop the run: the step is recorded failed and the flow moves straight to the next one, so a message or close placed after it still happens with the tag still on the contact.

## Limits

- It never touches this conversation's own tags — clearing a tag Tag Conversation added needs **Untag Conversation** instead.
- The removal applies to the contact everywhere, not to this conversation's channel alone — the tag lived on the contact, not on any one thread.
- It does not fire this workspace's **Contact Tag Updated** trigger for other workflows — only a change made in (Contacts, the inbox sidebar, the app, or the public API) does. Unlike **Tag Contact**, removing a tag also never moves or opens a deal — a pipeline stage's auto-tag rule only ever reacts to a tag being ADDED, never to one being removed.

## Use cases

- Remove `no_show` once the same contact has **attended** a rescheduled session, so a broadcast that targets no-shows for a nudge stops reaching them.
- Remove `webinar-attendee` if a registration is later canceled, so a segment built on past attendance does not keep counting them.

## Related

- [Tag Contact](https://inchat.inseller.my/help/workflows/tag-contact)
- [Tag Conversation](https://inchat.inseller.my/help/workflows/tag-conversation)
- [Untag Conversation](https://inchat.inseller.my/help/workflows/untag-conversation)
- [Conditions and variables](https://inchat.inseller.my/help/workflows/conditions-and-variables)
- [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/form-payload.ts`, `src/lib/workflows/workflow-input-schema.ts`, `src/lib/activity/record.ts`, `src/lib/workflows/contact-triggers.ts`, `supabase/migrations/20260911210000_tags_catalog.sql`, `supabase/migrations/20260917190000_pipeline_stage_auto_tags.sql`
