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

# Importing Contacts

> Bulk import contacts via CSV upload

Import contacts in bulk using CSV files. The import process validates numbers, normalizes formats, and handles duplicates automatically.

## CSV Format

### Required Column

| Column                                | Description          | Example                    |
| ------------------------------------- | -------------------- | -------------------------- |
| `phone_number` or `phone` or `msisdn` | Contact phone number | +14155551234 or 4155551234 |

### Optional Columns

| Column              | Description                                                                                                                                                                                                                                     | Example                                     |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
| `email`             | Email address (stored but not used for SMS)                                                                                                                                                                                                     | [user@example.com](mailto:user@example.com) |
| `first_name`        | Contact first name                                                                                                                                                                                                                              | John                                        |
| `last_name`         | Contact last name                                                                                                                                                                                                                               | Doe                                         |
| `carrier`           | Mobile carrier name                                                                                                                                                                                                                             | T-Mobile                                    |
| `line_type`         | Phone line type (CELL PHONE, VOIP, LANDLINE, UNKNOWN)                                                                                                                                                                                           | CELL PHONE                                  |
| `consent_date`      | Date the contact gave consent to be messaged. Accepts `YYYY-MM-DD`, `MM/DD/YYYY`, `MM-DD-YYYY`, or full ISO 8601 datetime. Future dates are rejected. Also accepted as column headers: `consentdate`, `consent`, `opted_in_date`, `optin_date`. | 2025-01-15                                  |
| `ad_network_source` | Ad network source for attribution                                                                                                                                                                                                               | facebook                                    |
| `ad_network_id`     | Ad network campaign/account ID                                                                                                                                                                                                                  | camp\_123                                   |

<Note>
  Custom fields are set via the API's `custom_fields` object when creating or updating contacts, not via CSV columns. See the [API reference](/api-reference/contacts/create-contact) for details.
</Note>

<Note>
  Providing `consent_date` preserves the original opt-in date for contacts you collected outside of Trackly (e.g. migrated from another platform or a legacy form). This is part of the TCPA consent evidence trail — see [Opt-In Tool Data & Retention](/concepts/optin-tool-data-retention) for how Trackly records consent for opt-ins captured through the platform.
</Note>

### Example CSV

```csv theme={null}
phone_number,first_name,last_name,email,consent_date
+14155551234,John,Doe,john@example.com,2025-01-15
+14155551235,Jane,Smith,jane@example.com,2025-03-22
4155551236,Bob,Jones,bob@example.com,
```

## Import Process

Contacts can be imported via CSV through the dashboard or the [bulk API endpoint](/api-reference/v2/contacts/bulk-create).

<Tip>
  The import supports a **dry-run mode** (`dryRun: true`, enabled by default) that validates all rows without persisting, so you can preview results before committing.
</Tip>

## Phone Number Normalization

The import process automatically handles various phone number formats:

| Input             | Normalized     |
| ----------------- | -------------- |
| `4155551234`      | `+14155551234` |
| `(415) 555-1234`  | `+14155551234` |
| `415-555-1234`    | `+14155551234` |
| `+1 415 555 1234` | `+14155551234` |
| `14155551234`     | `+14155551234` |

Numbers are assumed to be US (+1) unless they include a country code.

## Duplicate Handling

When importing contacts that already exist:

| Scenario                             | Behavior                                        |
| ------------------------------------ | ----------------------------------------------- |
| **Contact exists on this list**      | Custom fields are merged (new values override)  |
| **Contact exists on different list** | Added to this list with specified custom fields |
| **Contact previously opted-out**     | Skipped (opt-out is permanent)                  |
| **New contact**                      | Created and subscribed                          |

## Import Limits

The import endpoint accepts up to **5,000** contacts per request.

## Import Validation

Each contact is validated during import:

### Validation Rules

| Rule               | Invalid Example    | Result                                        |
| ------------------ | ------------------ | --------------------------------------------- |
| Valid phone format | `abc123`           | Skipped                                       |
| Number length      | `415555`           | Skipped                                       |
| Landline numbers   | Landline detected  | Stored (VOIP rejection is opt-in per account) |
| Not on blocklist   | Previously blocked | Skipped                                       |

### Import Report

After import, you receive a report showing:

```
Import Complete
---------------
Total rows:            10,000
Created (new):          9,280
Updated (existing):       243
Duplicate (already on list, or repeated in file):  45
Skipped (opted-out):      198
Error (invalid row):      234
```

`skipped` counts only active opt-out refusals. `duplicate` covers both
in-file repeats and the race-condition case where a concurrent importer
already added the contact to this list between your upload and ours.

## Triggering Welcome Journeys

When creating contacts via the API, set `use_journeys: true` on individual contacts to enroll them in active welcome journeys for the list.

## Best Practices

<AccordionGroup>
  <Accordion title="Validate before importing">
    Clean your CSV before importing. Remove obviously invalid numbers and test a small batch first.
  </Accordion>

  <Accordion title="Use consistent custom field naming">
    Establish custom field naming conventions (e.g., `source`, `campaign`, `cohort`) and use them consistently across imports.
  </Accordion>

  <Accordion title="Include source custom fields">
    Always include a `source` custom field indicating where contacts came from. This helps with attribution and analysis.
  </Accordion>

  <Accordion title="Don't re-import opted-out contacts">
    Opted-out contacts cannot be resubscribed via import. This is by design for compliance.
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Import stuck at 0%">
    Large imports can take time to start. Wait a few minutes. If still stuck, check file encoding (use UTF-8).
  </Accordion>

  <Accordion title="High skip rate">
    Check the skip reasons in the report. Common issues: invalid format, numbers already opted-out, landlines.
  </Accordion>

  <Accordion title="Custom fields not appearing">
    Ensure custom fields are passed in the `custom_fields` object when using the API. See the [API reference](/api-reference/contacts/create-contact) for the correct format.
  </Accordion>

  <Accordion title="Wrong country code">
    If numbers are non-US, include the full E.164 format with country code in the CSV.
  </Accordion>
</AccordionGroup>

## Common Pitfalls

<Accordion title="Why are rows failing during import?">
  Common causes for import row failures:

  * **Phone number format**: Numbers must be in E.164 format (e.g., `+14155551234`). Numbers without the `+` prefix or country code are rejected.
  * **Duplicate phone numbers**: If the same phone number appears multiple times in your CSV, only the first occurrence is imported. Subsequent duplicates are skipped.
  * **File encoding**: CSV files must be UTF-8 encoded. Files saved with Windows-1252 or other encodings may produce garbled characters or parsing errors.
  * **Column mapping**: Ensure your CSV headers match the expected field names. Unrecognized columns are silently ignored.
  * **Row limit**: Each CSV import supports up to 5,000 rows. Split larger files into batches.
</Accordion>

## Next Steps

<CardGroup cols={2}>
  <Card title="Custom Fields" icon="tags" href="/guides/contacts/custom-fields">
    Organize imported contacts
  </Card>

  <Card title="Audiences" icon="users" href="/guides/audiences/overview">
    Segment your contacts
  </Card>

  <Card title="Journeys" icon="route" href="/guides/journeys/overview">
    Automate onboarding
  </Card>
</CardGroup>
