The Tag Nobody Reads


The job was to audit a client’s CRM tags and clear out the debris. 429 tags in the system. We wanted to get that down.

The script counted contacts per tag, scanned every workflow body for tag references, and produced a report. Tags with zero contacts and no workflow references: delete. Tags with contacts but no references: archive candidates. Tags wired into active workflows: leave alone.

The scan came back. 173 tags qualified for deletion. Nearly 40% of the system was dead weight.

103 of them had come from a single test import in March — someone had run a CSV with a column that wasn’t stripped, and every row had become its own unique tag. test_import_row_47. Sixty-two variations of it, sitting there doing nothing, never cleaned up.

Easy enough to remove.

The eleven tags

The problem was eleven tags that were on zero contacts, appeared in zero workflow bodies, and were still live triggers.

In GHL, a workflow trigger is the condition that fires it. One trigger type is “tag applied”: specify a tag string, and when any contact receives that tag, the workflow starts. Our script was scanning workflow bodies — the steps, branches, and actions inside each workflow. Triggers aren’t in the body. The API endpoint that returns a workflow definition doesn’t include its triggers; that’s a separate call to a separate endpoint.

Our scan looked at the right system for the wrong question. The triggers were invisible to it.

Eleven tags. Zero contacts each. Workflow body scan: zero references. Trigger scan: live. One of them was the entry point for a quote follow-up — customer requests a quote, tag gets applied, automation fires within minutes. The tag appeared to do nothing. It was doing everything.

The clean-looking scan

The failure has a name: the clean-looking scan.

It’s a query that returns nothing because it’s asking the right system for a different question. The absence of results looks like confidence — you looked, you found nothing, there’s nothing to find. But the zero is a zero in the searched field, not in the thing you actually care about.

A query that returns unexpected results at least tells you something is there. The clean-looking scan returns nothing, and you move on.

Why renaming is worse than deleting

Once we understood the trigger problem, the question became: what would have happened if we’d tidied up without running the full trigger scan?

Deleting a tag that still drives a workflow tends to fail loudly — the workflow breaks visibly, contacts stop being processed, someone notices. It’s a hard failure and usually recoverable.

Renaming a tag is silent. The trigger is still watching for the original string. Rename quote_requested to quote-requested and the trigger watches for a tag that no longer exists. Contacts get tagged with the new name. The workflow never fires. No error, no alert, no visible break.

You’d see a workflow with no recent activity. That might be normal for a seasonal flow. Or it might be that the string it’s watching for changed six weeks ago. The workflow doesn’t know it’s broken. It’s just very patient.

Deleting is a hard failure. Renaming is a quiet one.

The fix

We requested trigger data from the separate endpoint. Cross-referenced with the body scan. Got the full picture. The eleven tags were kept. The 162 others went.

The report now runs both scans by default and flags tags that appear as triggers but have zero contacts — not as delete candidates, but as things to understand before touching.

The fix for the clean-looking scan is to ask: if the data I want were somewhere adjacent, would a zero result look any different to a zero result with full coverage? If not, one more check is needed before treating clean as clear.