# CSV import

Bring existing feedback into Usero from a CSV file or a pasted spreadsheet range. The rows land in your inbox as feedback items,
run through the same AI clustering as everything else, and any of them can become a GitHub pull request. This is the fastest way
to migrate off another tool (Canny, Productboard, Featurebase) or to pull a support backlog out of a spreadsheet.

## What it does

- **Bulk-load feedback from a CSV.** Upload a `.csv` file or paste a range copied straight from a spreadsheet. Usero parses it in
  the browser, reads the headers, and walks you through mapping, preview, and commit on one screen.
- **Auto-detects common exports.** Canny, Productboard, and Featurebase exports are recognized and their columns are mapped for
  you, so you usually just confirm the mapping. Any other tool that exports CSV works on the generic path.
- **Tags the source.** Imported rows are marked as a CSV import and carry an importer id, so you can tell them apart from widget,
  email, and GitHub feedback and undo a bad import as a unit.
- **One-hour undo.** Every completed import can be undone for one hour after it finishes.

## Prerequisites

- A Usero account and a project. You need to be a member of the project you are importing into.
- Your feedback as a CSV file, or open in a spreadsheet so you can copy a range. If your old tool only exports JSON or XML,
  convert it to CSV first (most spreadsheet apps do this in two clicks).

## Prepare your CSV

You do not need to rename columns before importing; you map them in the wizard. But a clean file imports more cleanly:

- **One header row.** The first row is treated as column names.
- **One feedback item per row.** Each row becomes one feedback item.
- **A title column.** Every row needs a non-empty title. Rows with a blank title are flagged in the preview so you can fix or skip
  them before they import.
- **Optional columns** Usero can map: a content/description column, author email, author name, votes, status, and a created-at
  date. Anything else is ignored.
- **Dates** in any format `Date.parse` understands (ISO `2026-01-15`, `Jan 15 2026`, and similar) are read as the item's created
  date. Unparseable dates are left blank rather than failing the row.
- **Emails** that do not look like an email address are dropped rather than imported as junk.

Canny exports the post body as HTML; Usero strips the tags so you get clean text. You do not need to clean it yourself.

## Upload and map columns

1. Open your project, go to **Integrations**, and find the **CSV import** card. Click **Start a CSV import**. (Direct URL:
   `usero.io/YOUR_CLIENT_ID/import/csv`.)
2. **Bring it in.** Drop your `.csv` file onto the drop zone, or paste a copied spreadsheet range. Usero reads the headers
   immediately.
3. **Match your columns.** If Usero recognizes a Canny, Productboard, or Featurebase export, the mapping is pre-filled and a banner
   says so; confirm it or override to the generic mapping. Otherwise, map each Usero field to one of your column headers. **Title
   is required.** Content, author email, author name, votes, status, and created-at are optional.
4. **Map status values (if you mapped a status column).** Usero builds a default translation from your raw status values (for
   example `under review`) onto Usero statuses. Adjust any that are wrong. Source values you do not map fall back to **open**.
5. **Preview.** You see the row count, unique authors, unique statuses, the date range, and a count of problem rows. Fix a missing
   title inline or skip the row. Then choose how duplicates are handled:
   - **Skip** (default) leaves any row that already exists untouched.
   - **Merge** updates the existing item.
   - **Replace** overwrites the existing item.
6. Click **Import**. The file finishes uploading if it has not already, and the import starts.

## What happens after commit

- The rows ingest in the background while a progress bar fills. You can reload or share the URL mid-import; it carries the job id
  and resumes on the progress step.
- Each row becomes a feedback item with `source = csv_import`, tagged with the import job so the batch can be undone together.
- **Dedup runs in two passes.** Exact repeats inside the same file (matching title, author email, and created-at) are collapsed to
  one. With the **skip** strategy, rows whose key already exists in this project are dropped so re-running the same import does not
  double up.
- Imported items run through the same AI clustering as the rest of your feedback, so near-duplicates that exact matching missed get
  grouped semantically once they are in.
- When the import finishes you are taken to the dashboard, and the inbox offers an **undo** control for **one hour**. After the
  hour the items are normal feedback you can edit or delete individually.

## Troubleshooting

**"Upload not found; please retry the upload."** The file did not finish uploading before commit. Go back and re-drop the file,
then import again.

**Rows skipped for "missing title."** Those rows had a blank title column. Map a different column to title, or fix the titles in
the preview (or in your source file) and re-import.

**Author emails missing on imported items.** Values that do not match a basic email pattern are dropped on purpose, so a name or
a handle in the email column will not import as an email. Map the correct column, or leave author email unmapped.

**Duplicates still appeared.** Exact dedup keys off title, author email, and created-at. Two rows that describe the same request
in different words are treated as distinct on import; the AI clustering groups them afterward in the inbox.

**I imported the wrong file.** If it has been under an hour, use the **undo** control in the inbox to reverse the whole batch.
After an hour, the items are normal feedback you delete individually.

**My export is not CSV.** Usero imports CSV only. Convert a JSON or XML export to CSV in your spreadsheet app first, then import.

## Next

- [Integrations overview](/docs/integrations)
- [Find your clientId](/docs/find-your-client-id)
- [GitHub (AI pull requests)](/docs/integrations/github)
