> For the complete documentation index, see [llms.txt](https://native-app-co.gitbook.io/omnibus-owl/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://native-app-co.gitbook.io/omnibus-owl/core-features/bulk-import-export.md).

# Bulk import & export

Export your entire price history as a CSV, edit it in a spreadsheet, and import it back — across all products, variants, and markets at once.

The **Import & export** tab on the **Omnibus Lowest Price** page lets you work with price history in bulk. Instead of editing [one variant at a time in the admin](/omnibus-owl/core-features/price-history-in-admin.md), you export everything to a CSV, make your changes in a spreadsheet, and import the file back.

Typical uses:

* **Seed correct 30-day history right after installing** — for example when migrating from another tool or from your own records.
* **Fix wrong entries across many variants** after a mispriced sale or a sync problem.
* **Set market-specific historical prices in bulk** — each row can target one country, so multi-market catalogs stay manageable.

## Export

Click **Export price history** and Omnibus Owl generates a CSV in the background — you can leave the page and come back. The file contains every variant that has price history: one row per variant, entry date, and country.

* The finished file shows its size, row count, and variant count, with a **Download** button.
* Each export is available for **7 days**, then deleted automatically. Export again any time.
* **Download empty template** gives you the header row plus example rows if you'd rather start from scratch.

## The CSV format

| Column          | On import    | Meaning                                                                                                                                                                 |
| --------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `variant_id`    | **Required** | The variant's ID, e.g. `gid://shopify/ProductVariant/45123456789` (a bare numeric ID is accepted too). This is the **only** column used to match rows to variants.      |
| `product_title` | Ignored      | Context so you can tell rows apart while editing.                                                                                                                       |
| `variant_title` | Ignored      | Context.                                                                                                                                                                |
| `sku`           | Ignored      | Context. SKU is deliberately **not** a matching key — many stores have missing or duplicate SKUs.                                                                       |
| `date`          | **Required** | `YYYY-MM-DD` (optionally with `HH:MM` or `HH:MM:SS` — exports write full seconds), in your shop's timezone. The date the price became valid. Future dates are rejected. |
| `country`       | Optional     | Two-letter country code (`PL`, `DE`, …) for market-specific prices. **Leave empty to apply the price to all your active market countries.**                             |
| `price`         | **Required** | Decimal with a dot, e.g. `199.00`.                                                                                                                                      |
| `currency`      | **Required** | Three-letter code, e.g. `PLN`.                                                                                                                                          |

Rows with the same `variant_id` and `date` are combined into one history entry with per-country prices. All rows for a variant become that variant's **complete** history.

{% hint style="info" %}
Keep the `variant_id` in the `gid://…` form the export uses. Spreadsheet apps corrupt long bare numbers by rewriting them in scientific notation (`4.51235E+10`) when saving, but leave the `gid://…` text intact. Corrupted IDs are caught during validation with a clear error — they are never silently mis-matched.
{% endhint %}

## Import

Importing is a guided flow — nothing is written until you explicitly confirm:

1. **Upload** a CSV (up to 50 MB).
2. **Validation preview** — Omnibus Owl parses the file and shows what would happen: how many variants and entries, and a table of problem rows with line numbers and reasons. **Errors** (unknown variant, bad date, future date, bad price) cause that entire variant to be skipped — a variant is never partially imported. **Warnings** (currency doesn't match the market, country not in your markets, duplicate rows, a date missing prices for markets the variant covers elsewhere in the file) import anyway and are flagged. You can download the problem rows as a CSV, fix them, and re-upload.
3. **Confirm** — you acknowledge two things before the import runs:

{% hint style="danger" %}
**Importing replaces price history — it does not add to it.** For every variant in your file, the imported entries become that variant's entire price history. Existing entries for those variants are deleted. Variants not in the file are untouched.
{% endhint %}

{% hint style="warning" %}
**You are responsible for the accuracy of imported data.** Imported prices become the basis for the "lowest price in the last 30 days" shown to your customers under the EU Omnibus Directive. Import only prices you actually charged.
{% endhint %}

4. **Processing** — before anything is written, Omnibus Owl automatically saves a **backup** of the affected variants' current history, downloadable for 7 days. Then the import runs in the background; you can leave the page.
5. **Report** — how many variants were replaced, how many entries written, what was skipped and why, plus download links for the backup and the problem rows. The last report stays on the tab until your next import.

## Good to know

* One export and one import can run at a time.
* Imported entries are marked internally as imported, so they stay distinguishable from automatically tracked prices.
* Entries older than your display window import normally and are stored — they don't affect the widget until the window reaches them (you can track up to 365 days via the **Days to track** setting).
* All uploaded and generated files are deleted automatically after 7 days.

## Anchored prices (Croatia)

The same tab also handles the [anchored price](/omnibus-owl/core-features/anchored-price.md) (*sidrena cijena*) in a second **Anchored prices (Croatia)** section. It works even while the feature is off — values are stored, and shown on the storefront once you enable it on the Settings tab.

* **Export anchored prices** lists **every** variant, one row per variant and market. Variants that have no anchored price yet come out with empty price cells, so the file doubles as the list of what still needs a value.
* **Import anchored prices** sets the anchored price of every variant in the file. Rows with an empty `anchored_price` are **ignored**, so re-importing an untouched export changes nothing. Like the price-history import, it validates first, backs up the affected variants' current values, and replaces (all markets of) each variant in the file.

| Column                                  | On import    | Meaning                                                                                                     |
| --------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------- |
| `variant_id`                            | **Required** | The variant's ID, as in the price-history file. The only matching key.                                      |
| `product_title`, `variant_title`, `sku` | Ignored      | Context for editing.                                                                                        |
| `country`                               | Optional     | Two-letter country code. **Leave empty to apply the price to all your active market countries.**            |
| `anchored_price`                        | **Required** | Decimal with a dot, e.g. `45.00`. **Empty = row ignored.**                                                  |
| `currency`                              | **Required** | Three-letter code, e.g. `EUR`.                                                                              |
| `anchored_date`                         | Optional     | `YYYY-MM-DD`. The date the price refers to. Empty = the reference date from Settings. One date per variant. |
| `source`                                | Ignored      | Written by the export: `h` derived from history, `m` set by hand, `i` imported.                             |
