> ## Documentation Index
> Fetch the complete documentation index at: https://www.twicecommerce.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# How to import customers from a CSV

> Bring an existing customer list into TWICE — the columns the importer accepts, why every row creates a new profile rather than updating one, and what it will not carry across.

<Frame caption="Customers">
  <img src="https://mintcdn.com/twicecommerce/Ab7tx7ih94KQsi0k/images/customers-overview.webp?fit=max&auto=format&n=Ab7tx7ih94KQsi0k&q=85&s=44e286b208dc583e0f533f75ca512a33" alt="The customers table, where the import action lives" width="1920" height="1080" data-path="images/customers-overview.webp" />
</Frame>

<Card title="Open in TWICE Admin" icon="external-link" href="https://admin.twicecommerce.com/customers" horizontal>
  customers
</Card>

Moving to TWICE usually means bringing a customer list with you. The importer takes a CSV and makes profiles from it, which is most of the job — but it is narrower than the profile itself, and it only ever creates.

Knowing both limits before you start saves the two expensive mistakes: assuming a re-import will update what is already there, and assuming everything on your old records comes across.

## Prerequisites

<Warning>
  **Required permissions:** `customers:customer` in create. All four system roles hold it. See [Users & Roles](/docs/settings/users-roles).
</Warning>

<Info>
  **Have ready before you start:**

  * **A CSV with a header row.** The importer matches your column names against the ones it expects, and recognises common variants (`first name`, `firstname`, `first_name`).
  * **A first name and a unique email on every row.** These are the two required columns, and a row missing either cannot be imported.
  * **A deduplicated file.** Two rows sharing an email fail each other — see the pitfalls.
</Info>

## The Walkthrough

<Steps>
  <Step title="Prepare the columns the importer accepts">
    Six columns, and that is the whole list:

    | Column                | Required | Notes                                                            |
    | --------------------- | -------- | ---------------------------------------------------------------- |
    | **First name**        | Yes      | *First name is required* if blank                                |
    | **Last name**         | No       |                                                                  |
    | **Email**             | Yes      | Must be unique in the file *and* against your existing customers |
    | **Phone number**      | No       |                                                                  |
    | **Marketing consent** | No       | Defaults to `false` when blank — see the note below              |
    | **Language**          | No       | Defaults to `en` when blank                                      |

    Anything else in your file is ignored. In particular the importer does **not** carry **Customer type**, **Company name**, **Tax / VAT ID**, addresses, tags, or custom attributes — so a B2B list arrives as a set of individuals with no company details, and everything imported has an empty **Billing address**.

    <Warning>
      **Marketing consent defaults to `false`, and that is the safe default — leave it alone unless your old system recorded real consent.** Setting the column to `true` wholesale because it is convenient asserts a consent you may not have. The flag is what your email exports filter on, so it should be true only where it is true.
    </Warning>
  </Step>

  <Step title="Run Import customers">
    Open **Import customers** from the customers table and follow the steps: upload the file, map your columns onto the expected ones, and review what the importer flags before committing.

    Column mapping is where a differently-named header gets pointed at the right field. The importer pre-matches obvious variants, so usually you are confirming rather than mapping.
  </Step>

  <Step title="Read the validation before you commit">
    Validation runs per row, and the email check runs twice — once inside your file and once against your existing customers. Three messages you will actually see:

    | Message                                     | Meaning                                             |
    | ------------------------------------------- | --------------------------------------------------- |
    | *First name is required*                    | The row has no first name                           |
    | *Email must be unique*                      | Two or more rows in **this file** share the address |
    | *Email already exists for another customer* | The address is already on a profile in TWICE        |

    Fix the file and re-upload rather than committing a partial set. A row that fails validation is not imported, and there is no report afterwards telling you which ones did not make it.
  </Step>

  <Step title="Understand that import only ever creates">
    **The importer creates profiles. It never matches or updates an existing one.**

    That is why an existing email is an error rather than a merge: a row for a customer TWICE already knows is rejected, not applied on top. So:

    * **You cannot use import to bulk-update customers.** Re-importing a corrected file does not fix the records already in TWICE; it fails on every row that matched.
    * **You cannot import in passes** — one file with names, another adding phone numbers. The second pass fails entirely.
    * **Get the file right before the first run.** It is the only run that lands.

    To change many existing customers, edit them in the table instead.
  </Step>

  <Step title="Fill in what the import could not carry">
    After the import, the profiles exist but are thin. Depending on your operation, some of this matters:

    * **Business customers** need **Customer type**, **Company name** and **Tax / VAT ID** set — see [Set up business customers](/docs/guides/customers/business-customers).
    * **Addresses** are empty and have to be added where you invoice or deliver.
    * **Tags and attributes** are unset, so any segmentation you had is gone. Rebuild it — see [Segment customers](/docs/guides/customers/segment-customers).

    Prioritise by what you will actually use. A list you only email needs email and consent to be right and nothing else.
  </Step>
</Steps>

## How do I know it worked?

* **The customers table row count** matches your file, less any rows you knowingly dropped.
* **A sample of records reads correctly** — spot-check a few, especially any with accented characters or unusual phone formats.
* **Marketing consent is true only where it should be**, which is worth filtering the table to check before you send anything.
* **Language is right**, since it decides which language each customer's emails render in.

## Troubleshooting / Common Pitfalls

<AccordionGroup>
  <Accordion title="&#x22;Email already exists for another customer&#x22;">
    **Cause:** that address is already on a profile. The importer creates only, so it treats a known email as a collision rather than an update.

    **What to do:** remove those rows from the file. If the existing record needs the file's data instead, edit it directly — import will not do it.
  </Accordion>

  <Accordion title="&#x22;Email must be unique&#x22; on rows that look fine">
    **Cause:** the duplicate is *within your file*. Two rows share the address, so both fail.

    **What to do:** deduplicate before uploading. Exports from older systems frequently contain the same person twice under different names.
  </Accordion>

  <Accordion title="I re-imported a corrected file and nothing changed">
    **Expected — import cannot update.** Every row matching an existing email was rejected, and any that succeeded created a *second* profile.

    **What to do:** check for duplicates you may just have created, then correct the originals in the table instead.
  </Accordion>

  <Accordion title="My customers have no company details after importing">
    **Expected.** **Customer type**, **Company name** and **Tax / VAT ID** are not importable columns, so a B2B list arrives as individuals.

    **What to do:** set them per profile, or accept individuals if you do not invoice companies. There is no bulk route for this.
  </Accordion>

  <Accordion title="A row has no email and I want to import it anyway">
    **Not possible** — email is required and must be unique, because it is the identity the record is found and contacted by.

    **What to do:** for a customer you genuinely have no email for, create the profile by hand rather than trying to force the file through.
  </Accordion>

  <Accordion title="The file is very large">
    **The importer batches it** — rows are sent in chunks rather than one request, so size alone is not a problem. Give it time and do not close the dialog mid-run.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Segment customers" icon="filter" href="/docs/guides/customers/segment-customers">
    Rebuilding groups and attributes the import did not carry.
  </Card>

  <Card title="Set up business customers" icon="building" href="/docs/guides/customers/business-customers">
    Adding the company details after an import.
  </Card>

  <Card title="Export customers" icon="file-export" href="/docs/guides/customers/export-customers">
    Getting the list back out again.
  </Card>

  <Card title="Customers overview" icon="users" href="/docs/customers/overview">
    The table, its columns and its filters.
  </Card>
</CardGroup>
