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

# Import history

> Start with a trained model by importing behaviour you already have.

A backfill imports interaction history you already hold into NeuronSearchLab, so a model can train on it immediately.

The [embed](https://docs.neuronsearchlab.com/embed.md) collects behaviour from the moment it renders, but only going forward. Where you already have a year of orders in Shopify or pageviews in GA4, importing that history means your first model trains on real customers rather than waiting a month for new behaviour to accumulate.

Whichever source you import from, the mapping is the same three questions: which item, which event, and when. The sections below cover each supported source.

***

## CSV

The simplest path, and the one that works regardless of which tools you use.

```csv theme={null}
user_id,item_id,event,timestamp
u-1042,SKU-9,view,2026-03-04T10:30:00Z
u-1042,SKU-9,purchase,2026-03-04T10:32:11Z
```

Upload it in **Data → Events → Configure signals → Import history**, or send it to the Platform API.

**Columns are matched by name, not position**, so you do not need to reorder your export. These are all recognised:

| Field | Accepted column names |
| - | - |
| User | `user_id`, `user`, `customer_id`, `visitor_id` |
| Item | `item_id`, `product_id`, `sku`, `url`, `item_url` |
| Event | `event`, `event_type`, `event_name`, `action` |
| Time | `timestamp`, `time`, `occurred_at`, `created_at`, `date` |

Timestamps can be ISO 8601, epoch seconds, or epoch milliseconds.

**You choose what each event name means.** Every export names its events differently, so nothing is guessed. After you pick the file, the console lists each distinct event name in it with its row count, and you choose which of your event IDs it becomes - or leave it out. `Order Completed` is not assumed to be a purchase, and `add_to_cart` is never folded into a click.

Your answers are saved, so the next export that uses the same names imports without asking again. Through the API, send the mapping as an `event_mapping` form field: a JSON object from each event name to an event ID, or `null` to leave it out. A request without a complete mapping starts nothing and answers with the names it found.

***

## Shopify

The [NeuronSearchLab Shopify app](https://docs.neuronsearchlab.com/embed/shopify.md) reads your order history with its order access when you install it. Stores that connected earlier with an Admin API token (scope `read_orders`) in **Developers → Integrations → Shopify** can still import from there.

Order line items become verified purchases, on the event bound to the `purchase` signal: your workspace's **Purchase** event unless you have rebound it. Shopify does not expose product views, so this gives you conversions, which is the signal the embed cannot collect.

***

## Google Analytics

GA4 comes in two shapes, and the difference decides what you actually get.

### BigQuery export - real training data

If you have linked GA4 to BigQuery, we can read per-user rows: every `view_item`, `select_item`, `add_to_cart` and `purchase` with the pseudonymous user id attached. **This trains a model.**

GA4's event names are a fixed schema, so they are translated once rather than asked about: `view_item` is the `view` signal, `select_item` is `click`, and `add_to_cart` and `purchase` are themselves. Each lands on the event ID bound to that signal, and starting the import creates any that are missing.

### Data API - a popularity prior only

Without the BigQuery export, GA4's reporting API returns aggregated item metrics with no user dimension at all. We import those as a popularity signal, which genuinely helps cold start - but there is no *who* in it, so it cannot train personalisation.

> [!NOTE]
>
> The console tells you which of these it is running. If you want GA4 to be more than a popularity prior, [link GA4 to BigQuery](https://support.google.com/analytics/answer/9823238) first and re-import.

***

## What happens to your rows

Item references resolve against both the identifier a feed supplied and the canonical URL a crawl recorded, so an import works whether your catalogue was built by crawling or by ingesting a feed.

Rejections are reported by cause, because the two mean different things:

| Reported as | What it means |
| - | - |
| Unknown item | Your catalogue and your export disagree on identifiers. Usually the export uses SKUs and the catalogue was crawled by URL, or the reverse. |
| Unknown event | An event name you left out, or one that was not mapped when the import started. |
| Malformed | A missing field or an unreadable timestamp. |

> [!WARNING]
>
> An import that silently discarded 40% of its rows would be worse than one that never ran. Check the rejection counts before treating an import as finished - a high unknown-item count means almost nothing landed.

Imports are safe to re-run. Every row carries a deterministic identifier derived from its own content, so importing the same export twice will not double-count anything.

***

## After importing

Imported events are marked with their origin, so they can be weighted or excluded during training independently of live traffic.

Once you have history in place, train a model from **Models → Catalog**, or let [scheduled retraining](https://docs.neuronsearchlab.com/console/models.md#scheduled-retraining) pick it up.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.