Your contact form says “Referral”. The CRM it feeds only accepts “Refferal”, typo and all. Your visitors should never see that, and your form must still send it back letter for letter.
Table of Contents
A familiar example: your phone’s contact list
You tap “Mom” and your phone dials +1 555 0142 8890. You never read the number, and the phone never “tidies” it before dialing: one wrong digit and the call goes nowhere. The name is for you; the number is what the network matches on.
Connecting two systems works the same way. Say your website has a “How did you hear about us?” dropdown, and every answer goes into a CRM field with its own fixed list of options. Over the years, that list picked up some mess:
| What your visitors should see | What the CRM actually stores |
|---|---|
| Referral | Refferal |
| Billing | [EU] Billing - use this |
| Marketing | Mktg |
Show the left column on your form. Send the right column to the CRM. Never the other way round, and never “corrected”.
Labels and keys look the same, and that’s the trap
Two kinds of text are hiding in that table. A label is for a person to read; you can reword it freely. A key is what a system matches on; changing it by a single character breaks the match.
They usually look identical. Refferal reads like a label with a typo, so the natural instinct is to send “Referral” instead. But the CRM only knows Refferal. Send the corrected spelling and, depending on the system, the write fails, creates a brand-new option nobody asked for, or quietly leaves the field blank. None of those announce themselves.
A label can be improved. A key can only be matched. Improving a key is how you break it.
Copy the stored values exactly, flaws included
Look up the target system’s real values and record them exactly as stored: the extra space, the missing letter, the leftover note, the capitalization. Don’t normalize them, don’t correct the typo, don’t trim what looks like stray punctuation. Those imperfections are the key. The usual suspects:
- Typos in the other system:
Refferal. Your form shows “Referral”; you sendRefferal. - Old context stuck in the name:
[EU] Billing - use this, a note someone added years ago. Your form shows “Billing”; you send the whole string. - Abbreviations and inconsistent styles:
Mktgsitting next toSales Team. Your form shows “Marketing”; you sendMktg.
Keep the list in a small data file or a sheet, not buried in code, so anyone can check it and a change is a one-line edit.
Translate in one place: the moment you send
The swap happens at exactly one point: just before the data leaves for the other system. Everywhere else (your form, your own records, your logs, your reports) uses the clean name. That keeps the mess contained to a single line, and nobody reading your data ever needs to know the CRM misspells things.
Two rules for values that aren’t in the list:
- A value that’s already an exact stored value passes straight through, so a correct value never breaks just because it wasn’t listed.
- A clean name with no stored value yet (say you added “Podcast” to your form but nobody created it in the CRM) is something to hold and flag for a person, not something to guess. A guessed key produces a failure somewhere far from where the guess was made.
Translate once, at the edge. Everything before that line speaks human; only the last step speaks the other system’s dialect.
Check by matching, not by reading
A list like this looks right far more often than it is. A trailing space or a wrong letter survives review for months, because people read past them. The only real check is to compare every value you might send against the other system’s own list of allowed values, automatically if it offers one: each must be present, exactly. A mismatch is a silent failure waiting for the one visitor who picks that option.
It’s the same habit as confirming a write against the system itself rather than a success message: the other system is the authority, not your copy of what it should say.
What the list can’t do
A translation list hides messy labels; it doesn’t clean them up at the source, and it’s one more thing to keep current. When someone finally fixes Refferal in the CRM, your list is suddenly wrong the other way, and every “Referral” fails until you update it. That’s another reason to run the matching check regularly. It also can’t rescue a genuine clash: if two different stored values would both reasonably display as “Billing”, you have to keep them distinct on your side too (“Billing (EU)”, “Billing (US)”). The list is an adapter between two systems, not a data-quality program.
The short version
When you send data into a system whose own labels are messy (a typo like Refferal, an old note like [EU] Billing - use this, an abbreviation like Mktg), show people clean names and keep a two-column list from each clean name to the exact stored value. Swap only at the moment you send, character for character and never corrected; let exact stored values pass through; hold and flag a clean name that has no stored value yet. Check by matching every value you might send against the other system’s list, not by reading the pairs. The label is for people; the stored value is a key.
Frequently Asked Questions
Why not just fix the messy values in the other system?
Often you can’t, or not quickly: it belongs to another team, other reports and automations depend on the old values, or changing it means coordinating a cleanup you don’t control. A translation list lets you give your visitors a clean experience today. When the source is cleaned up, you update the list.
Should the list live in code or in a data file?
In a data file or sheet. It’s vocabulary, not logic, and it changes when the other system changes, not when your code does. As data, anyone can audit the whole set at a glance, corrections are one-line edits, and every part of your setup that sends data can share the same list instead of keeping copies that drift apart.
What should happen when a value isn’t in the list?
Let a value that’s already an exact stored value pass through unchanged. But a clean name with no stored counterpart should be held and flagged for a person, never mapped to a guessed value, because a wrong guess fails somewhere far from where you made it.
Isn’t this just translation, like making a site multilingual?
It looks similar but works the opposite way. Translating between languages is people-to-people, so you can reword freely for clarity. A display-to-stored list turns a person’s label into a machine’s key, and the right-hand side must be sent exactly as stored, because the other system matches on it.
Do I need the list in both directions?
Usually not. The direction that matters is display to stored, when you send. If you also read values back from the other system to show them, map them for display only, and never write a “cleaned-up” version back, or you’ll overwrite the key you depend on.
How do I stop the list from breaking silently?
Re-run a check that compares every value you might send against the other system’s current list of allowed values. When the other system renames or fixes something, the check fails right away instead of one unlucky visitor’s submission failing weeks later.