Most vendors do not ship one tidy file. They ship an item master with part numbers and cost, and then — on a different day, in a different format — a second file that is nothing but product copy and specs for the same items. An enrichment feed is how you take in that second file: a Product Catalog feed whose job is not to create products, but to pour content onto products this vendor already supplies.
Why a second feed for the same vendor
A vendor can have as many Product Catalog feeds as they have files, plus as many Inventory feeds as they have stock files. Each feed gets its own directory, its own filename pattern, its own column mapping, its own label and its own schedule — because the files share none of those.
Real examples this is built for:
- Ace ships the Article file (the item master: part numbers, UPCs, cost, MSRP) and a separate Romance file whose only payload is long-form copy, keyed by the same item number.
- VSG ships a product sheet and an independent MAP price sheet, dated weeks apart.
- A cost-only update sheet that arrives weekly against a catalog that only changes quarterly.
Trying to force these into one feed means one schedule, one column map and one file pattern for sources that agree on none of it. Instead, add a second feed pointed at the same vendor. Both use the same importer, the same matching, and the same review queue — they just read different files.
ℹ️ Note: An enrichment feed is still a Product Catalog feed. There is no separate “enrichment” feed type. What makes it an enrichment feed is the way you configure it: content columns mapped, product creation off.
💡 Tip: Give each feed a Label (“Article — item master”, “Romance — copy”). The label is what the feed row shows, and on a vendor carrying three feeds it is the only thing that tells them apart at a glance.
📷 Screenshot: The vendor page’s Products panel showing two Product Catalog feed rows for the same vendor — an item-master feed and a content feed, each with its own label, directory and schedule (placeholder — replace with
/docs-images/vendors/enrichment-feeds-two-catalog-feeds.png)
How the feed finds the right products
An enrichment feed links a row to a product exactly the way the item-master feed does: by the vendor part number. Once a product has been matched to this vendor’s part number — through the Review Queue and Apply — that vendor product is permanent, and every later run of any of this vendor’s feeds resolves straight to it. Matching is case-insensitive and ignores surrounding spaces.
That has two consequences worth knowing before you build the feed:
- The item-master feed has to go first. Enrichment only reaches products that are already linked to this vendor. Run the item master, work the review queue, apply it, and then point the content feed at the same catalog.
- Both feeds must read the same part number. Map the enrichment feed’s Vendor Part-Number Column to whatever column carries the identical value the item master used. The two files can call it different things — one may head the column
Articleand the otherEJD_Item#— but the values have to be the same part number, or nothing matches.
Rows the feed cannot resolve to an existing vendor product fall through the normal path — matched by your chosen strategy, staged for review, or counted as “not carried”. They are not lost, they simply have nothing to enrich yet.
ℹ️ Note: A row whose vendor part-number cell is empty is not enriched and not staged — it is counted as a failed row, alongside rows whose column count does not match the feed’s Expected Columns.
What an enrichment feed actually writes
Only mapped columns are read, and a blank value is never written over anything. On a feed run, these are the fields that reach an already-linked product:
| Map the vendor column to | Where it lands on the product | Governed by |
|---|---|---|
| Manufacturer’s description | Source Content → Manufacturer Description | Descriptions |
| Vendor’s description | Source Content → Vendor Description | Descriptions |
| Manufacturer Part # | Identifiers → Manufacturer Part # (MPN) | Part numbers, barcodes, weight |
| UPC / Barcode | Identifiers → GTIN / UPC / EAN | Part numbers, barcodes, weight |
| Attribute blob (Key: value) | The product’s Attributes tab | Nothing — see the warning below |
That is the whole list. A few things ride a different path and are worth stating plainly, because assuming otherwise is how a feed disappoints you:
- Weight is governed by the Part numbers, barcodes, weight group, but a recurring run never carries a weight value — the run’s content pass sends descriptions, MPN, GTIN and the attribute blob and nothing else. A mapped Weight column reaches a product through the review queue: it rides the proposal, and lands when you approve it and hit Apply, under that same field group’s policy.
- Retail price, images and categories are likewise apply-time. On Apply, the vendor’s MSRP can become your retail price under the Retail price policy (default Never change it), the vendor’s image joins the gallery under Images, and the vendor’s category path files the product wherever you mapped it in Vendor Categories.
- Vendor cost, drop-ship cost, MSRP and MAP — when mapped — refresh the vendor product for that item (the record holding this vendor’s part number and cost, and the cost a drop-ship purchase order is priced from) on every run, whenever the value actually changed. They are not gated by the update policy, and they never touch your retail price. A column you did not map never blanks a value you already have.
- Product titles are not rewritten, by a run or by Apply. Neither path carries a title for a product you already have, so the Product title policy is a guard rather than a lever. Titles for products this vendor created come from the feed’s Title for new products template, and the Re-title products action in the feed’s ⋯ menu is what re-applies it.
⚠️ Warning: The Manufacturer Description and Vendor Description fields are internal source content. They are not rendered on your storefront — the storefront reads Short Description and Full Description, which no vendor feed touches. Their job is to be raw and detailed so AI description generation has real specs to work from instead of guessing.
The update policy, field group by field group
Every Product Catalog feed carries a policy for what the vendor may change on a product you already have. It lives in the feed editor under Updating products you already have, and it is set per field group:
| Option | What it does |
|---|---|
| Never change it | The feed ignores these fields entirely. |
| Only fill it in if mine is blank | Writes only where your product has nothing there. |
| The vendor’s version wins | The vendor is the source of truth — an existing value is replaced. |
The groups and their defaults:
| Field group | Covers | Default | Reaches the product |
|---|---|---|---|
| Descriptions | Manufacturer description, vendor description | Only fill it in if mine is blank | Every run |
| Part numbers, barcodes, weight | MPN, GTIN, weight | Only fill it in if mine is blank | MPN and GTIN every run; weight on Apply |
| Images | The image this vendor supplied | Only fill it in if mine is blank | On Apply |
| Product title | The product’s title | Never change it | Nothing supplies one |
| Retail price | Your selling price and MAP — not cost | Never change it | On Apply, from the vendor’s MSRP / MAP |
Title and price default to Never change it on purpose. Your naming is your merchandising, and retail price belongs to you and the repricer; vendor cost is a different number that lives on the vendor product and updates regardless of every setting here.
“Blank” means empty or missing. For weight, price and MAP a 0 counts as blank — a physical product does not weigh nothing — so Only fill it in if mine is blank will fill a zero weight.
💡 Tip: For a pure content feed, The vendor’s version wins on Descriptions is usually the right call — that is the whole reason you took the second file. Leave Product title and Retail price on Never change it.
✅ Nothing is rewritten when it already matches. A value identical to what is stored is skipped, so an unchanged file re-read costs nothing, does not bump the product’s timestamp, and does not churn your channel listings.
📷 Screenshot: The “Updating products you already have” section of the feed editor, showing all five field groups with their three-option dropdowns (placeholder — replace with
/docs-images/vendors/enrichment-feeds-update-policy.png)
Field locks: one product’s veto
The feed policy is the general rule. A single product can overrule it. On any product, under Protect from vendor updates, tick the aspects you have curated by hand:
- Title
- Price & MAP
- Description
- MPN / GTIN / Weight
- Images
- Categories
A locked aspect turns The vendor’s version wins into Only fill it in if mine is blank for that product. It is deliberately not a total blackout: filling a genuinely empty field takes nothing away from you, so a locked product still gets the gaps filled — it just never gets your work overwritten. A locked Categories aspect is the exception: category filing is purely additive, so a locked product is skipped entirely rather than filled.
The locks are honoured on both paths — the run’s content pass and Apply — so a lock you set today protects the product against every feed this vendor has, and every vendor.
This is what makes The vendor’s version wins safe to use across a large catalog. You can let a distributor keep 20,000 stub products current while the 50 products you photographed and rewrote stay exactly as you left them.
📷 Screenshot: The “Protect from vendor updates” checkbox grid on a product, with Description and Images ticked (placeholder — replace with
/docs-images/vendors/enrichment-feeds-product-locks.png)
The attribute blob
Distributors often refuse to ship specs as columns. Instead they cram every spec for an item into one field, as labelled pairs separated by asterisks:
Product Type: Peg Hook*Brand Name: Rust Oleum*Color: Black*Material: Steel*Fertilizer Analysis (N-P-K): 6-8-0*Disposable:
Map that column to Attribute blob (Key: value) in the feed’s Column Mapping and it stops being a wall of text. Each pair is parsed out and written as a real product attribute:
| Attribute | Value |
|---|---|
| Product Type | Peg Hook |
| Brand Name | Rust Oleum |
| Color | Black |
| Material | Steel |
| Fertilizer Analysis (N-P-K) | 6-8-0 |
The parsing rules, exactly:
- Pairs are separated by
*. That separator is fixed — a vendor using a different one will not parse. - The key and value split at the first colon, so a value containing a colon (or a key containing a hyphenated code in brackets) survives intact.
- Whitespace inside a key is collapsed, so
Interior or Exteriordoes not become a second, near-identical attribute. - A segment with no colon is skipped. A pair with an empty value (
Disposable:above) is skipped. - If the vendor lists the same key twice in one blob, the last value wins.
How attributes get created
Keys are matched against your existing attributes case-insensitively, so a vendor shipping Number in Piece and Number in piece gets one attribute, and a key that matches something you already defined reuses your definition rather than duplicating it.
A key you have never seen creates a new attribute automatically, as type Text, Visible, and not Filterable. That last part is intentional: a vendor should not be able to reshape your storefront’s filter rails. Go to Catalog → Attributes afterwards to promote the handful worth filtering on.
Values are added when missing and corrected when the vendor changes them. They are never deleted — if a vendor drops a spec from a later file, the value already on your product stays until you remove it. Unchanged values are left alone entirely, so a re-read of the same blob writes nothing.
⚠️ Warning: Attributes are not covered by the update policy and not covered by field locks. If you map the attribute blob, the blob is written — even on a feed where every field group is set to Never change it, and even on a product with every lock ticked. If you do not want a vendor authoring your attributes, unmap that column.
📷 Screenshot: The feed editor’s Column Mapping section with a vendor column mapped to “Attribute blob (Key: value)” (placeholder — replace with
/docs-images/vendors/enrichment-feeds-map-attribute-blob.png)
📷 Screenshot: A product’s Attributes tab showing the Assigned Attributes list populated from a vendor blob (placeholder — replace with
/docs-images/vendors/enrichment-feeds-product-attributes.png)
Setting up an enrichment feed
- Add the feed — go to Purchasing → Vendors, open the vendor, switch to the Integration tab, and in the Products panel click + Add Feed. Choose SFTP / FTP server if the vendor drops the file on an endpoint, or Spreadsheet upload if someone emails it to you.
- Name it — set a Label that says which file this is. Two unlabelled Product Catalog feeds on one vendor are indistinguishable on the page.
- Point it at the right file — under Files, set the Directory, and set a Filename Pattern that matches only this file (for example
*_Romance_*.csv). This matters more than usual: see the warning below. - Set the identity — under Identity, pick the Vendor Part-Number Column. Set the Matching Strategy to the same one the item-master feed uses; it only comes into play for rows that are not linked yet.
- Map the content columns — on an SFTP feed, click Read columns from the vendor to pull the real headers off the file so every picker becomes a dropdown of real column names. Then map the vendor’s description columns, part number, UPC, and the attribute blob. Only mapped columns are read.
- Set the update policy — under Updating products you already have, decide per field group what this vendor may change.
- Turn creation off — leave Create products for vendor items that don’t match anything unchecked. A content file is usually a partial slice of the catalog, and letting it mint products means creating stubs with copy and no cost.
- Set the schedule — under Schedule, set Check For New Files Every to 15 minutes, Hour, 6 hours, 12 hours, or Day. Match the vendor’s real drop cadence.
- Save it — the button reads Create Feed (stays off until enabled). Creating a feed never starts it.
ℹ️ Note: A spreadsheet-upload feed has no directory, delimiter or schedule — it runs when you send it a file with Upload files, and the setup wizard only asks for a handful of columns. Everything else, including the description columns and the attribute blob, is mapped afterwards through Edit feed, in the same editor an SFTP feed uses. Its column pickers come from the sheet you uploaded at setup, so upload a new file to pick up columns the vendor added.
⚠️ Warning: Two SFTP feeds reading the same directory with no filename pattern — or the same pattern — will each ingest both files. Each feed tracks what it has already taken in independently, so the item-master file will be imported a second time by the content feed, under the content feed’s settings. Give every feed a pattern that matches only its own file.
Running it, and what a run reports
On the feed row, Run feed (or Run again) reads the vendor’s current file. For a catalog feed this both stages unknown items for review and writes the vendor’s content onto products it already matched — the enrichment is not queued for approval, it lands directly under your policy and each product’s locks.
A few behaviours worth knowing:
- A feed cannot be enabled for its recurring schedule until it has been run once. The toggle reads Analyze first until then.
- A file whose contents are identical to one already ingested is skipped, so a vendor re-dropping the same file costs nothing.
- If you change the mapping or the update policy and want it applied to what is already there, use Run again. When nothing new is waiting at the vendor, an explicit run re-reads the last ingested file — which is how a configuration change reaches products that were imported under the old settings.
- Fresh re-analyze, in the ⋯ menu, clears everything currently waiting for review (To approve / Needs a decision / Flagged) and rebuilds the queue from the vendor’s current file. Products you have already created and matched are left alone. Use it when the queue was built under a mapping you have since fixed.
- Re-title products, also in the ⋯ menu, is vendor-wide, not feed-wide: it recomputes titles for the products this vendor created, from the vendor’s catalog-feed title template, and only where the title actually changes. It runs as a background job — watch it in the jobs tray.
The stat grid under the feed row reports the run: rows read, matched (linked to products you already have), created, need review, flagged, not carried, filtered out, vendor categories, and failed. Those are this run’s numbers, not the vendor-wide totals. For an enrichment feed the number that matters is matched — that is how many rows found a product to enrich. Expect created to be zero.
The enrichment itself is not broken out in that grid. To confirm it, open one of the vendor’s products and look at Source Content and the Attributes tab.
Troubleshooting
| What you see | What it usually means |
|---|---|
| Every row lands in “not carried” or “need review” | The part numbers do not line up with the vendor products the item master created, or the item master has not been applied yet. |
| A high matched count but no visible change | The policy is on Only fill it in if mine is blank and the fields already had values, or the product has that aspect locked. |
| Descriptions imported but the storefront looks the same | Vendor descriptions fill internal Source Content. The storefront reads Short Description and Full Description. |
| Weight mapped but never lands | Weight does not ride a run. It reaches the product through the review queue on Apply, under the Part numbers, barcodes, weight policy. |
| The blob imported as one giant attribute | The vendor is using a separator other than *, or the whole field was mapped to a description field instead of Attribute blob. |
| Attributes changed on a product you locked | Attributes ignore both the policy and locks. Unmap the blob column on that feed. |
| The content feed imported the item-master file | Both feeds match the same files. Tighten the filename patterns. |
| The run reports failed rows | Rows the importer could not read — usually a column-count mismatch or an empty vendor part number. The run’s error report is attached to its background job; find the job in the jobs tray. |
More symptoms, across every feed type, are in Vendor Troubleshooting.
Next
Go to Product Feeds for the item-master feed this one enriches, and to the Review Queue to apply the rows an enrichment run staged. Then open Catalog → Attributes to review what the vendor’s blob created and decide which of those should be filterable on your storefront, and Products to set per-product locks on anything you have curated by hand.
