Skip to main content

Bulk import overview

An overview of Bulk Import — using a CSV to record historical purchases in batch. Covers when it's the right tool, how product matching works, how price, premium, and spot interact, and the all-or-nothing validation step before transactions are created.

Bulk Import is a Premium feature that lets you record historical purchases in batch by uploading a CSV file. Each row in your CSV becomes one BUY transaction in your ledger, with one inventory item created per unit in the Qty column.

It's the right tool when you're catching up on years of past purchases at once; for one or two coins at a time, the manual Record Purchase form is faster.

This article is the high-level tour of how the feature is wired together. The deeper drill-downs — the column reference, the preview screen, edge cases — live in their own articles, linked at the bottom.

When bulk import makes sense

The honest answer to "should I use bulk import?" depends entirely on how much catching up you have to do.

  • Use bulk import if you're onboarding a stack with more than a handful of historical purchases — a decade of dollar-cost-averaging buys you'd like in the app in one sitting, for example.

  • Stick with the manual Record Purchase form if you only have a few transactions to record, or you're recording purchases as they happen. Typing one transaction into the form is faster than opening a spreadsheet, and the form auto-fills more of the work for you (live spot, dealer dropdown, premium math).

  • Sales are not part of bulk import. Only BUY transactions are supported in the CSV. If you have historical sales to record, use the Record Sale form — see How to record a sale.

To open the Bulk Import page, head to Transactions → Add Purchase and click the Bulk Import button in the top-right corner of the form. The button is visible only on the Premium plan — Starter and Pro accounts don't see it.

The Download template CSV button at the top of the Bulk Import page gives you a pre-headed file with a few sample rows; that template is the easiest starting point.

How each row turns into a transaction

The model is straightforward: one row in your CSV becomes one BUY transaction in your ledger, and the Qty column on that row decides how many individual inventory items the transaction creates.

A row that says "10 American Gold Eagles bought on 2024-08-12" produces one transaction record dated 2024-08-12 with ten gold-eagle inventory items behind it — exactly what you'd see if you'd used the Record Purchase form and set Quantity to 10.

Product matching

Bulk Import needs a way to know what each row is. There are two paths, and you choose between them per row.

Use a key (recommended)

Every product in Gold Silver Ledger — both the standard catalog and your own custom items — has a short text key that uniquely identifies it.

  • For standard catalog products, the key is the slug shown on the Standard Bullion tab of the Catalog page. Examples: american-gold-eagle-1oz, silver-maple-leaf-1oz, pre-1965-dime.

  • For your own custom items, the key is the CSV Key shown on the My Custom Items tab of the Catalog page. It's auto-generated when you create the custom product, and you can copy it from that screen.

Put that key in the catalog_id column of your CSV and the import treats every unit on the row as that exact product. No name-matching guesswork, no chance of accidentally creating a second copy of a product you've already set up.

Leave the key blank (creates or reuses a custom item)

If you leave catalog_id blank, the row needs five fields instead: product_name, metal, form, weight_oz, and purity. The import then does one of two things:

  • If a custom item with that exact name already exists in your account, the row is matched to that existing custom item — no duplicate is created.

  • If no match is found, the import creates a new custom item from the fields on the row and uses it for the transaction. The new product shows up on the My Custom Items tab of the Catalog afterward.

This path is useful when you're importing a mix of products that aren't in the standard catalog and you'd rather have the import create them on the fly than pre-build each one.

For the row-by-row column reference, see Preparing your CSV.

How price, premium, and spot work together

Three of the columns interact in a way worth understanding before you fill in the spreadsheet. The short version: enter what you know, and the import calculates whatever is missing.

Price per unit (required)

The amount you paid per coin or bar, in your account's display currency. This is the only price field that has to be filled in on every row — without it, the import has nothing to anchor the cost basis to.

Spot at Time (optional, takes precedence)

The spot price per troy ounce at the moment of the purchase, in USD. If you fill it in, it is the spot of record for the row, and the premium on that row is derived from Price per unit and the weight at that spot. Anything in the Premium per unit column on the same row is overwritten.

If you leave Spot at Time blank, the behavior depends on whether Premium per unit is filled in — see below.

Premium per unit (optional)

Premium per unit comes into play only when Spot at Time is left blank on the same row. In that case, the import uses Price per unit and Premium per unit to back-calculate the spot that applied at the time of purchase.

If Spot at Time is filled in on the same row, Spot at Time wins and any value you typed in Premium per unit is ignored — the premium is derived from price minus melt instead.

When both are blank

If Spot at Time and Premium per unit are both empty on a row, the import falls back to the current live spot for that metal and derives the premium from there.

This is fine for a purchase you made today, but not great for a purchase from years ago — the cost basis will be right, but the recorded spot and premium won't reflect what was true on the actual purchase date.

For historical rows, fill in Spot at Time from your invoice or a public chart for that date.

In every case, exactly one of "spot" and "premium" lands as the value of record on the row, and the other is derived from it.

Shipping cost (optional)

If your dealer charged shipping, insurance, or handling, you can put the total for the order in the shipping_cost column.

The import stores it on the transaction separately from the per-unit price, and the rest of the app allocates it across the line's individual items in proportion to each one's pre-shipping cost — the same way the Record Purchase form handles shipping.

shipping_cost is independent of the price, premium, and spot fields — it doesn't enter the spot/premium derivation at all. Leave it blank (or set it to 0) for rows where shipping was already rolled into the per-unit price.

Validation and the all-or-nothing rule

When you drop a CSV onto the page, the import doesn't immediately create transactions. It parses the file and shows you a preview table — one row per line in your CSV — with a Status column on the right.

Every row that's good to go shows an OK status. The Import N transactions button at the bottom-right tells you exactly how many records will be created when you commit.

Bulk Import is all or nothing. If any row in your CSV has a problem that the import flags the entire upload; none of the rows are committed, including the good ones.

To proceed, fix the offending rows in your CSV, save it, and use the Replace button at the top of the preview to upload the corrected file. The preview re-validates from scratch each time.

For the long version of what triggers a flag and how to clear the most common ones, see Fixing common CSV errors.

After import

Once you click Import N transactions and the upload commits, the rest of the app responds the same way it does to a manual purchase entry — only in bulk.

  • The Transactions History page lists every imported row as its own BUY transaction, dated to the purchase date you supplied in the CSV rather than the day of the import.

  • The Holdings page picks up every individual coin and bar as its own item record, with the right metal, weight, dealer, and any custom item the import created on the fly.

  • The Dashboard updates Total Portfolio Value, the metal allocation, and the Top Holdings cards.

  • The Analytics page picks up the new cost basis in its performance and allocation charts.

If you spot a mistake on a specific row after the fact, you can edit or delete that single transaction from the History page.

There's no separate "undo this whole import" button, but because every row is its own transaction, you can clean up individual entries without affecting the rest.

Where to go next

Did this answer your question?