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

# Import Contacts from CSV

> Bulk-add contacts by uploading a small CSV spreadsheet.

CSV import is the fastest way to add many contacts at once. Xobito reads your file in batches, validates each row, and imports the valid rows while listing any errors in an import log.

## Key limits

<Warning>
  Xobito's CSV import has a **50 MB file-size limit**, not a row-count limit. If your file is larger than 50 MB, split it into smaller files and import each one in turn.
</Warning>

| Limit             | Value                                            |
| ----------------- | ------------------------------------------------ |
| Maximum file size | **50 MB**                                        |
| Batch size        | 100 rows at a time (processed in the background) |
| Invalid rows      | Skipped per-row; valid rows still import         |

<Tip>
  Even within the 50 MB ceiling, smaller files import faster and are easier to recover from if something goes wrong. If in doubt, split very large lists into batches.
</Tip>

## What you need before you start

* A CSV file in UTF-8 encoding.
* A header row naming each column. Header names are **case-insensitive** but must match Xobito's field names exactly — there is no column-mapping UI.
* All phone numbers in E.164 format.
* Any **statuses**, **sources**, and **custom fields** already created in Xobito (the CSV refers to them by their ID).

## Download a sample CSV

The import screen offers a **sample CSV** you can download. It has the correct header row and one example data row. Use it as a template.

## Required columns

These columns **must** be present in your CSV. Rows missing any required value are skipped.

| Column      | Description           | Validation                                                      |
| ----------- | --------------------- | --------------------------------------------------------------- |
| `firstname` | First / given name    | Max 191 characters                                              |
| `lastname`  | Last / family name    | Max 191 characters                                              |
| `type`      | Contact type          | Must be `lead` or `customer`                                    |
| `phone`     | Phone in E.164 format | Must match `/^\+[1-9]\d{5,14}$/`. Unique within your workspace. |
| `status_id` | Status identifier     | Must be the ID of an existing status                            |
| `source_id` | Source identifier     | Must be the ID of an existing source                            |

<Note>
  `status_id` and `source_id` are the numeric IDs assigned to the status/source records you created in **Contacts → Status** and **Contacts → Source**. Check those screens to find the IDs before building your CSV.
</Note>

## Optional columns

| Column                            | Description                                                   |
| --------------------------------- | ------------------------------------------------------------- |
| `company`                         | Company name                                                  |
| `description`                     | Free-text notes                                               |
| `email`                           | Email address — if provided, must be unique in your workspace |
| `country_id`                      | Country identifier                                            |
| `city`, `state`, `zip`, `address` | Address details                                               |
| `assigned_id`                     | Staff user ID assigned to the contact                         |
| `group_id`                        | Group identifier(s) — See [Groups](/contacts/groups)          |
| Custom-field slugs                | Any custom field's `field_name` can be used as a column       |

## Sample CSV

```csv theme={null}
firstname,lastname,type,phone,email,status_id,source_id,city,country_id
Alex,Morgan,customer,+14155551234,alex@example.com,2,1,San Francisco,1
Priya,Shah,lead,+919876543210,priya@example.com,1,3,Mumbai,91
Tom,Becker,customer,+447911123456,,2,2,London,44
```

<Note>
  Leave a cell empty for optional fields you don't have — don't write `null` or `-`.
</Note>

## Phone number format

Phone numbers are the number-one cause of failed imports. The rules:

* Must start with `+` followed by the country code.
* No spaces, no dashes, no parentheses.
* No leading zero after the country code (UK `07911…` becomes `+447911…`).
* Total length between 7 and 15 digits after the `+`.

| Example          | Accepted                  |
| ---------------- | ------------------------- |
| `+14155551234`   | Yes                       |
| `+447911123456`  | Yes                       |
| `+919876543210`  | Yes                       |
| `415-555-1234`   | No                        |
| `(415) 555 1234` | No                        |
| `07911123456`    | No — missing country code |
| `14155551234`    | No — missing `+`          |

## Step-by-step import

<Steps>
  <Step title="Create your statuses, sources, and custom fields first">
    CSV references them by ID — they must exist before you import.
  </Step>

  <Step title="Prepare your CSV">
    Build the spreadsheet using the required columns above. Save as **CSV UTF-8**. Confirm the file is under 50 MB.
  </Step>

  <Step title="Open the import screen">
    In the sidebar, go to **Contacts** and open the import option.
  </Step>

  <Step title="Download the sample CSV (first time only)">
    Use it as the reference header layout.
  </Step>

  <Step title="Upload your file">
    Drag and drop or click to browse. Xobito checks the file size — if over 50 MB you'll see an error before any rows are processed.
  </Step>

  <Step title="Start the import">
    Xobito processes rows in batches of 100. Very small imports finish almost instantly; larger ones run in the background.
  </Step>

  <Step title="Review the import log">
    Once processing completes, the import log lists: total rows, successful rows, and each skipped row with the reason (row number + field errors).
  </Step>
</Steps>

## What happens to each row

| Case                                            | Result                                         |
| ----------------------------------------------- | ---------------------------------------------- |
| All required fields present and valid           | Contact is created.                            |
| Phone number already exists for another contact | Row is skipped with "phone already exists".    |
| Phone number is invalid (bad format)            | Row is skipped with a format error.            |
| `type` is not `lead` or `customer`              | Row is skipped with a validation error.        |
| `status_id` or `source_id` doesn't exist        | Row is skipped with a reference error.         |
| Custom field value fails validation             | Row is skipped with the field name and reason. |
| Email already exists for another contact        | Row is skipped with "email already exists".    |

<Warning>
  Xobito never aborts the whole import when a bad row is found. Invalid rows are skipped per-row. All valid rows still import. Check the import log after it finishes.
</Warning>

## Import Log

Every import writes a log entry. Visit **Contacts → Import Log** to see status, download the original CSV, or retry failed batches.

### How processing works

* Imports run **asynchronously** in batches of **100 rows per job**.
* Each import has a row in the Import Log with a status of `processing`, `completed`, or `failed`.

### Per-import counters

Each log row tracks the following counters as the job runs:

| Counter             | Meaning                                           |
| ------------------- | ------------------------------------------------- |
| `total_records`     | Total rows in the uploaded file.                  |
| `processed_records` | Rows the worker has finished evaluating.          |
| `valid_records`     | Rows that passed validation and became contacts.  |
| `invalid_records`   | Rows rejected by validation.                      |
| `skipped_records`   | Rows skipped for other reasons (e.g. duplicates). |

### Error capture

The `error_messages` JSON column captures per-row validation errors so you can pinpoint exactly which rows failed and why.

Use the log to fix bad rows in your original spreadsheet and re-import just the corrected rows.

## Best practices

<AccordionGroup>
  <Accordion title="Keep files manageable">
    The hard limit is 50 MB. Even within that ceiling, splitting large exports into several smaller files is faster and easier to recover from if something goes wrong.
  </Accordion>

  <Accordion title="Create IDs first">
    Get the `status_id`, `source_id`, and any `country_id` values you need **before** building the CSV. Without them every row will fail.
  </Accordion>

  <Accordion title="Test with 5 rows first">
    Before uploading your main file, upload a trimmed 5-row version. Check the log, open one of the created contacts, then run the full import.
  </Accordion>

  <Accordion title="Use UTF-8">
    Non-Latin names (Hindi, Arabic, Chinese) need UTF-8 encoding. Export from Excel as **CSV UTF-8**, not plain CSV.
  </Accordion>

  <Accordion title="Never import opted-out numbers">
    Only import contacts who have agreed to receive WhatsApp messages from you. Unsolicited messages hurt your quality rating.
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="'File too large' error">
    Your CSV exceeds the 50 MB limit. Split it into smaller files.
  </Accordion>

  <Accordion title="All my rows were skipped">
    Open the import log — it lists the exact reason per row. The most common causes are phone numbers without a country code, and missing `status_id` or `source_id`.
  </Accordion>

  <Accordion title="Non-English names show as question marks">
    Your CSV is in the wrong encoding. Re-export as **CSV UTF-8** from your spreadsheet tool.
  </Accordion>

  <Accordion title="Column header doesn't seem to be recognised">
    Column names must match Xobito's field names exactly (case-insensitive). There is no mapping UI. Check spelling and avoid extra spaces.
  </Accordion>

  <Accordion title="Dates in custom fields aren't accepted">
    Xobito expects dates in a standard format — see [Custom Fields](/contacts/custom-fields) for details.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Organise into groups" icon="users" href="/contacts/groups">
    Segment your imported contacts for targeted campaigns.
  </Card>

  <Card title="Run a campaign" icon="bullhorn" href="/campaigns/create-campaign">
    Broadcast to your freshly imported list.
  </Card>
</CardGroup>
