Importing contacts
Import many contacts at once from a CSV file; Reach maps its columns to contact fields and creates or updates a contact per row, recording any failures in an import job you can review.
Importing brings a list of contacts into Reach from a CSV file in one pass instead of adding them one at a time. You upload the file, map each column to a contact field, and Reach processes every row, creating new contacts and updating existing ones. The import runs from the contacts list, and every run is recorded as a job you can open afterward to see what succeeded and what failed.
Starting an import
Open Contacts and click the upload-arrow button in the toolbar (labelled Import contacts for screen readers). A panel opens on the right and walks through three steps: Import contacts (upload), Map columns, and Import complete.
Preparing your CSV file
On the first step, pick a file through the CSV file field. The picker accepts files with a .csv extension. The on-screen guidance states the expected format: comma-separated, UTF-8, with a header row, and quoted fields (so a value can contain a comma). The file is read and parsed in your browser the moment you select it, and a preview appears on the next step.
The parser handles only comma delimiters and standard double-quote escaping. It doesn't read tab-, semicolon-, or pipe-separated files, and it expects valid UTF-8 text. If the file can't be read, the upload step shows an error such as "The CSV file appears to be empty.", "The CSV file has a header row but no data rows.", or a "Could not parse CSV" message with the parse failure, and the import doesn't advance.
Mapping columns to fields
The Map columns step lists each header from your file with a dropdown beside it. Set each dropdown to the contact field that column should fill, or leave it on its default skip option to ignore the column. A preview of the first five data rows appears below the mapping so you can confirm the columns line up. Any header whose name matches a field name or label (ignoring case) is mapped for you automatically.
These are the fields a column can map to:
- Email, First name, Last name, and Full name: the identifying fields.
- Phone, Company, Job title, Industry, and Pronouns.
- City, Province / State, Country, and LinkedIn URL.
- Email opt-in and SMS opt-in: consent flags. A cell reads as opted in when its value is
true,yes, or1(case-insensitive); any other value reads as not opted in.
At least one identifying column must be mapped: either Email, or one of First name / Last name / Full name. If none is mapped, the import refuses to run and shows "Map at least Email, or First name / Last name, so contacts can be identified." When the mapping is valid, click Import N contacts to run it.
How rows become contacts
Reach matches each row to your existing contacts by email. When a row's email already belongs to a contact in your workspace, that contact is updated with the row's values rather than a second record being created; email matching is case-insensitive. A row whose email is new creates a new contact. A row with no email is always added as a new contact, because email is the only key Reach matches on. Every imported contact is stamped with the source reach_csv_import, which shows in the Source column so you can tell imported contacts apart from manual or event-sourced ones.
A row needs at least one usable identifying value, email, first name, last name, or phone, after the mapping is applied. A row that maps to none of these is skipped and recorded as a failure with the message "Row has no identifiable field (email, firstName, lastName, or phone)." Empty cells are treated as no value, so a blank column doesn't overwrite data already on a matched contact.
Plan limits
Contacts and companies share one stored-record allowance, and an import is checked against it as a whole batch, before any row is written, rather than row by row. On the Starter plan, if the file would push your workspace past its cap, the entire import is refused with "This import would push you past your plan's stored-record limit. Upgrade, or import a smaller file." Pro and Growth plans don't hit this wall; they accrue overage instead of being blocked.
The check counts every parsed row in the file, not only the rows that would create a new contact rather than update one. So a file that would mostly dedupe down against existing contacts can still be refused on a Starter plan if its row count alone crosses the line. Unlike the import checks for custom objects elsewhere in Reach, there's no separate row-count or file-size cap here beyond this plan gate.
Reading the result
When the run finishes, the Import complete step summarizes the outcome: how many of your rows were imported and how many failed. Rows process independently, so one bad row doesn't stop the rest; the run can finish fully imported, partially imported, or fully failed. When some rows fail, a Row errors section lists each failure with its row number (counted as it appears in your file, header included) and the reason. The first 50 errors show inline; the rest are available in the job history.
Click View import history to open the job's detail page. That page shows the job status, the totals (total rows, imported, failed, and the completed date), the exact column mapping that was used, and the full list of row errors. Click Done to close the import panel; your contacts list refreshes with the new and updated records.
Updated