The short answer: mapping a CSV column to a Salesforce field means three
things, and only three. The column has to land on the field's API name
(AnnualRevenue, not "ACV"); its value has to survive conversion to the field's
type (a date field wants yyyy-MM-dd, not 07/01/2026); and if
the field is a restricted picklist, the value has to already be one the field accepts. You can
do all three in Excel with a helper column per field, and for a clean 200-row file you probably
should. The rest of this page is what the work looks like when the file is not clean.
Get the target field names first
In Salesforce: Setup → Object Manager → your object
→ Fields & Relationships. The Field Name column is the API
name — what a bulk load matches on, not the label on the page layout. Custom fields end in
__c. Note each field's type, and whether a picklist has "Restrict picklist to the
values defined in the value set" ticked.
Two type rules cause most of the damage. Bulk API 2.0 accepts yyyy-MM-dd for
Date fields and yyyy-MM-ddTHH:mm:ss.SSSZ (or the same with a
+/-HH:mm offset; the milliseconds are optional) for DateTime. Number
fields want a plain numeral: no currency symbol, no thousands separator, a period as the decimal
mark.
Field mapping: four ways a field gets its value
One column to one field covers maybe two-thirds of a real load. The rest needs one of these:
- Source column — the ordinary case.
- Fixed constant — every row gets the same value.
LeadSource=Trade Showfor the whole file, without adding a column to the spreadsheet. - Combined fields — two or more columns joined in a chosen order, with a
separator you specify between each part:
first+ space +lastintoName. - Unmapped — the field is deliberately left empty. That is a decision, and it should be visible as one.
Columns whose names already line up are matched for you: an exact, case-insensitive header match
first, then a normalized match that ignores case and punctuation and drops the trailing
__c — so a header Wealth Management lands on
Wealth_Management__c.
Conditional values
Some fields are not a column at all — they are a rule about the row. Any mapped field can carry ordered rules that override the mapped value. Conditions inside one rule combine with AND, rules are read top to bottom, first match wins. A rule returns a constant (a blank one counts), and the field's transformations then run on the result.
IF country = "US" AND state has a value → BillingCountry = "United States"
IF country = "UK" → BillingCountry = "United Kingdom"
(otherwise) → the mapped column value
The 13 transformations
Transformations chain per column in an order you set, each taking the previous one's output. They run after row selection and before type conversion.
| Transformation | What it does | In → out |
|---|---|---|
| Trim whitespace | Removes leading and trailing whitespace. | " ACME corp " → "ACME corp" |
| Remove HTML tags | Strips tags, decodes entities, tidies the leftover spacing. | Bluewave <b>Ltd</b> → Bluewave Ltd |
| Collapse whitespace | Any run of whitespace becomes one space; ends trimmed. | "Acme Corp" → "Acme Corp" |
| UPPERCASE | Upper-cases the value. | gb → GB |
| lowercase | Lower-cases the value. | ACTIVE → active |
| Title Case | Lower-cases, then capitalizes each word. | ACME CORP → Acme Corp |
| Find & replace | Plain substring, or a regular expression. | $120,000 → 120000 (regex [$,] → empty) |
| Map values | Whole-value lookup against a table you define. Trimmed and case-insensitive; values not in the table pass through unchanged. | US → United States |
| Add prefix | Puts a fixed string in front. | 0451 → ACC-0451 |
| Add suffix | Appends a fixed string. | acme → acme.com |
| Default if empty | Substitutes a value when the cell is blank or whitespace only. | "" → Prospecting |
| Substring | A slice from a 0-based start, with an optional length. | INV-2026-0031 (start 4) → 2026-0031 |
| Parse date (exact format) | Reads the value with the exact format you name and emits ISO 8601. A value that does not match is a cell error, not a silent guess. | 07/01/2026 as MM/dd/yyyy → 2026-07-01T00:00:00 |
The exact-format rule is the point of that last one. A parser that works out for itself whether
07/01/2026 is January or July is the parser that
silently shifts half your dates. Naming
the format makes an ambiguous file fail loudly instead.
Value mapping: the distinct-values screen
Map values earns its own section because it kills the loop that eats afternoons. Rather than find-and-replacing one value at a time, it lists the distinct values your source column actually contains, each against a dropdown of the values the field accepts — captured from the org's describe when the target came from a Salesforce object. You fix the whole set in one screen, and you can see which ones you have not decided yet. Optionally, one click asks the AI to propose the obvious translations; every suggestion is shown for you to accept or correct, and nothing is applied until you do. See bad value for restricted picklist field for what happens when this step is skipped.
Row selection: which rows become records
Source files rarely hold one row per Salesforce record. Exports carry every member of a household, every line of an order. Row selection decides which rows survive, and it runs across the whole file before any transformation.
- Keep all rows — the default.
- Only matching rows — keep rows where all your conditions hold. A filter.
- First per group — one row per group key, in file order. Plain de-duplication.
- One per group, preferring a match — the first matching row; if none matches, the group's first row. No group is lost.
- One per group, requiring a match — the first matching row; groups with no match are dropped.
Conditions use fourteen operators: equals, does not equal, contains, does not contain, starts with,
ends with, has a value, is empty, is greater than, is at least, is less than, is at most, is any
of, is none of. Text comparisons ignore case and surrounding whitespace. The four ordered
comparisons parse numbers or dates rather than comparing text, so 100 is correctly
greater than 20.
Reading a sibling row
Grouping buys one more thing: a mapped field can take its value from a different row in the same group — either the nth row in file order, or the first row where a chosen column equals a chosen value. That is how you flatten a household: the primary contact becomes the record, the spouse's email comes from the sibling row, and a group with no such sibling leaves the cell blank rather than failing.
Multi-file joins
One primary file plus up to four lookups, joined on key columns compared trimmed and
case-insensitively. Before you commit, you see the match rate, how many keys are empty, and a
sample of keys that found no match — which is where you discover the two exports you were handed do
not actually share an ID. Joined columns keep an alias (Contacts.Email), so two files
can each have an "Email"; rows with no match contribute blanks rather than dropping out.
Validation and preview
Every mapped value is converted to the field's declared type — Text, Number, Date, DateTime, or Boolean — and anything that will not convert becomes a per-cell error, shown next to the row it came from. Restricted picklists are checked against the accepted values captured from the org, so a rejectable value is flagged before anything is written. Unrestricted picklists are not flagged: they legitimately accept new values through the API. A preview shows the first rows; a full review scan covers every selected row before a workbook is generated.
Delivery
| Typed workbook | Direct Salesforce load | |
|---|---|---|
| Salesforce connection | Not required at all | Required (OAuth) |
| Output | An .xlsx written onto your own uploaded load template — header block and formatting preserved | A Bulk API 2.0 insert, or an upsert matched on an External ID field |
| Cell errors | Reported; you may still export if you confirm | Upload refused outright while any cell error remains |
| Never does | Delete records. Update by record Id. Repeat an identical upload unless you explicitly allow it. | |
Every option on this page is in INQUA's import tool, free during early access. It reads .csv, .txt, .xlsx, and .xlsm directly — no CSV conversion step — and saves the whole recipe, so next month's file is a re-upload rather than another afternoon of spreadsheet surgery. It does not export records from Salesforce and does not schedule jobs; if that is what you need, see the honest Data Loader comparison.
What none of this can catch
Mapping and validation happen on your file. They cannot simulate what your org does once the records arrive. No preview — ours or anyone's — predicts:
- Required-field failures — a blank cell on a field the org's schema requires: a required standard field, a custom field marked required, or a master-detail relationship. (A field marked required on a page layout is a red herring: layouts govern the UI, and an API load ignores them entirely.)
- Validation rules, which are formulas that can reference anything on the record and reject it once it arrives.
- Apex triggers and record-triggered Flows, which can reject or rewrite a record after insert.
- Duplicate rules and unique-field collisions against records already in the org.
The honest claim is narrower and still worth a lot: type conversion and restricted-picklist violations are caught on your file, before the job runs — two of the reasons a bulk load comes back with thousands of failed rows. For everything else, load a ten-row test batch first; that advice is as old as the Data Import Wizard and still correct. What Salesforce sends back, and what each message means, is in the import error reference.