New to Attio?Get 10% off when you sign up through Craftt.Try Attio free →
All articles

The replace() and replaceAll() functions in Attio: clean domains, phones, and names without a workflow

Written by

Published 6 min read

Tested in live Attio workspaces.

Data doesn't arrive clean. Enrichment writes www.acme.com, the inbound form writes acme.com, a rep types +1 415 555 0100 where the dialer wants +14155550100, and each mismatch turns into a duplicate, a missed match, or a bounced sync. replace() and replaceAll() fix the text inside a formula — so the clean version lives on the record as a computed attribute, stays in sync with the messy source, and never needs a cleanup workflow.

This is part of our function-by-function series on Attio formula attributes — previously: if(), timeSpentIn(), dateDiff(), the ?? operator, count(), hasBeenIn(), valueSetAt(), contains(), sum(), previousValue(), dateAdd(), formatDate(), min()/max(), and valueAt(). This one covers the two text-rewriting functions together, because the only difference between them is *how many* times they act.

Table of contents

What replace() and replaceAll() do

Same three arguments for both: the text to edit, the text to find, and what to put in its place.

replace(subject, search, replacement)
replaceAll(subject, search, replacement)

replace("Hello World", "World", "There") returns "Hello There". replaceAll("Hello World", "l", "r") returns "Herro Worrd" — every l swapped, not just the first. Force the output type to Text; the input is text and so is the result.

First occurrence vs. every occurrence

The choice between them comes down to one question: *can the search text appear more than once, and do you want all of them?*

replace() stops after the first match. That's the right tool when the thing you're removing is a known token in a known position — a www. prefix, a Inc. suffix, a single label you want to rename. It's also the safer choice when the search text might legitimately appear elsewhere in the string and you don't want to touch it.

replaceAll() keeps going. That's the tool for formatting noise — spaces, dashes, dots, parentheses — that can show up anywhere and any number of times. replace({Phone}, " ", "") on +1 415 555 0100 gives you +1415 555 0100, which is worse than useless; replaceAll() gives you +14155550100.

The empty-string trick

Most real-world use isn't substitution — it's deletion. Pass "" as the replacement and the match is removed:

replace({Domains}, "www.", "")

www.acme.com becomes acme.com; a domain without the prefix passes through untouched. This one formula is the single biggest dedupe win in the text library: put it on Companies, use it as the matching key, and enrichment's www.acme.com and the form's acme.com resolve to the same value.

Nesting for multi-step cleanup

Each call fixes one kind of noise; stack them for several. Phone numbers usually need spaces *and* dashes gone:

replaceAll(replaceAll({Phone}, " ", ""), "-", "")

Inner call strips spaces, outer call strips dashes. Add a third layer for parentheses if your data has them. This is nesting within one formula, which is fine — the three-deep limit from the pillar applies to formula attributes referencing *other* formula attributes, not to functions inside a single formula.

Composing with contains(), length(), and if()

The text family works as a set. contains() decides *whether* to clean; 13px] bg-[color:var(--color-bg-muted)] border border-[color:var(--color-border)] px-1.5 py-0.5 rounded">replace() does the cleaning; [if() routes on the result:

if(contains({Domains}, "www."), replace({Domains}, "www.", ""), {Domains})

Strictly you don't need the guard — replace() on a string without a match returns it unchanged — but the pattern matters when the cleaned and uncleaned cases should produce *different* downstream values. And length() on the cleaned string is the honest data-quality check: length(replaceAll({Phone}, " ", "")) tells you how many digits you actually have, spacing ignored.

CRM use cases that earn their keep

  • Domain normalizationreplace({Domains}, "www.", "") — important because dedupe, matching, and enrichment all key on domain, and one prefix splits one company into two.
  • Dialer-ready phonesreplaceAll({Phone}, " ", "") — important because dialers and SMS tools reject formatted numbers, and a rep shouldn't retype them.
  • Legal-suffix strippingreplace({Name}, " Inc.", "") — important because "Acme Inc." and "Acme" are the same account, and the display name in emails and reports shouldn't carry the suffix.
  • Label migrationreplace({Segment}, "SMB", "Small business") — important because renaming a category across thousands of records is a formula, not a bulk edit, and the source stays untouched.
  • Slug and ID generationreplaceAll({Name}, " ", "-") — important because a URL-safe or key-safe version of the name feeds integrations that can't handle spaces.
  • Notes hygienereplaceAll({Description}, "\n", " ") — important because multi-line enrichment text breaks single-line syncs and exports.

Copy-paste formulas

Swap in your attribute names and these work as-is:

Domain without www. (Text output):

replace({Domains}, "www.", "")

Phone with spaces and dashes removed (Text output):

replaceAll(replaceAll({Phone}, " ", ""), "-", "")

Company name without legal suffix (Text output):

replace({Name}, " Inc.", "")

URL-safe slug from the name (Text output):

replaceAll({Name}, " ", "-")

Phone digit count, spacing ignored (Number output):

length(replaceAll({Phone}, " ", ""))

Gotchas

  • Search is literal text. replace() and replaceAll() match the exact characters you pass — there's no pattern matching. Clean one kind of noise per call and nest for more.
  • Case matters. "Inc." doesn't match "inc.". If your data mixes cases, add a second call for the variant.
  • replace() stops at one. If a phone formula looks half-cleaned, that's the tell — switch to replaceAll().
  • color:var(--color-text-heading)]">Blank in, blank out. A record with no phone or domain returns blank, not an error. Guard downstream comparisons with [?? if blank would break them.
  • Multi-value attributes. Domains can hold several values; test the formula on a record with more than one to confirm it does what you expect before keying dedupe on it.
  • Clean, don't overwrite. The formula sits next to the raw attribute — it never edits it. That's the point: the source stays as it arrived and the cleaned version regenerates whenever it changes.

Final thoughts

replace() and replaceAll() are the quiet data-quality layer of the formula library. Ship replace({Domains}, "www.", "") first — it pays for itself the first time a duplicate doesn't get created — then replaceAll() on phones. Neither needs a workflow, a bulk edit, or a cleanup sprint; the clean value just exists, next to the messy one, and stays current.

For the rest of the library — every history, logic, math, date, and text function with CRM use cases — see the complete guide to Attio formula attributes.

And if you'd rather have your dedupe keys, data-quality flags, and integration-ready fields designed and shipped for you, that's literally what we do. Get a free workspace audit or see the AI-native Attio sprint.

Official sources

Attio documentation used to verify this guide:

Need help with your Attio setup?

We migrate teams, build data models, wire automations, and train Claude agents inside your workspace. Discovery call is free.

Book a free discovery call