Supplier Feed Import & Dropshipping for PrestaShop 8 & 9
Install, configure and automate multi-supplier import (CSV, XML, JSON), margins, combinations and stock synchronization.
Overview
The Supplier Feed Import & Dropshipping module (technical name dfsupplierfeed) automatically imports and syncs your suppliers’ catalogs into PrestaShop 8 and 9. It handles multiple suppliers and feeds in CSV, XML and JSON, applies your margin rules, builds combinations, links products together, syncs stock via cron, and arbitrates duplicate EAN13 codes through a per-supplier priority.
The module does not replace PrestaShop’s native CSV import (built for a single manual load): it industrializes recurring imports from several sources, with automatic margins, combinations and synchronization.
Installation
- In the back office, go to Modules > Module Manager, then Upload a module.
- Select the
dfsupplierfeed.zipfile and confirm. - Once installed, click Configure.
On install, the module creates five tables (dfsf_supplier, dfsf_feed, dfsf_rule, dfsf_product, dfsf_log) and generates a unique cron token.
Interface overview
- Dashboard — counters and a warning about feeds whose import is in progress.
- Suppliers — suppliers and priorities.
- Feeds — feeds, analysis, field mapping and options.
- Margin rules — retail price computation rules.
- Logs — detailed import history.
- Settings & Cron — general settings, large catalogs, cron URLs.
Step 1 — Create your suppliers
In the Suppliers tab, add a supplier with:
- Name of the supplier.
- Priority — an integer,
1being the highest. It settles EAN13 duplicates. - Active — an inactive supplier is skipped by the cron.
- Create the native PrestaShop supplier — recommended: it also fills the purchase cost in
product_supplier.
Assign the best priorities (lowest numbers) to your most reliable or cheapest suppliers: they are the ones that will “own” shared products.
Step 2 — Create the feed and let the module analyse it
In the Feeds tab, create the feed with its supplier, its source type (remote URL or local file inside the shop directory) and its format. Save, then click the magnifier button on the feed row.
The module downloads a sample and shows the items_path detected for XML and JSON feeds, the list of every field actually present with sample values, and a complete pre-filled mapping, editable before it is applied.
Numbered photo columns (image_1, image_2…) are grouped automatically, packed size columns, colour columns and related-reference columns are recognised, and column names are identified in English, French, Spanish, German and Italian with a sanity check on the values.
Always check the proposal before applying it. Many suppliers ship a recommended retail price where the module expects a purchase cost: your margin would then be applied on top of an already marged price.
Step 3 — The field mapping
The mapping is a JSON object linking the feed’s columns or nodes to normalized fields. The 21 canonical fields are:
name reference ean13 mpn cost quantity description description_short category manufacturer weight tax_rate image images group_reference attributes variants_stock variants_ean variants_reference variant_attribute related
Only reference or ean13 is mandatory: those are the two matching keys. A row with neither is rejected.
Several sources for one field
A field value may be a list. A supplier spreading its photos over several columns maps like this:
{
"fields": {
"reference": "id",
"name": "name",
"cost": "wholesale_price",
"images": ["image_1", "image_2", "image_3", "image_4"]
}
}
For the images field every filled column is imported. For any other field the first non-empty value is kept, which lets you write a fallback chain: "cost": ["sale_price", "net_price"].
CSV
Link each field to a column header, or to a column index starting at 0 when the headers are unusable. The delimiter is detected automatically, multiline quoted fields are handled, and both 1 234,56 and 1,234.75 are accepted.
{
"fields": {
"name": "product_name",
"reference": "sku",
"ean13": "ean",
"cost": "price",
"quantity": "stock",
"category": "category",
"image": "image_url"
}
}
A row whose column count does not match the header is rejected and counted as an error. That is the only safe way to handle an unescaped delimiter inside a text field: without the check, every following value would be shifted and imported silently.
XML
items_path points at the repeated node, at any depth. Field paths are relative to that node, and @name reads an attribute.
{
"items_path": "products/product",
"fields": {
"reference": "@sku",
"name": "title",
"ean13": "ean",
"cost": "pricing/wholesale",
"quantity": "stock/quantity",
"image": "images/image"
}
}
Since paths are relative to the item, a value living only on an ancestor node cannot be read: there is no .. navigation.
JSON
items_path uses dot notation down to the items array. A numeric segment reads an array entry, so images.0 is the first image. Leave items_path empty if the file starts directly with [.
{
"items_path": "data.products",
"fields": {
"reference": "sku",
"name": "name",
"ean13": "barcode",
"cost": "prices.cost",
"quantity": "inventory.available",
"image": "images.0"
}
}
The Feeds tab holds sixteen commented examples covering the most common structures.
Step 4 — Define your margins
In the Margin rules tab, each rule computes the tax-excluded retail price from the tax-excluded purchase cost:
- Percent —
cost × (1 + value/100). - Coefficient —
cost × value. - Fixed addition —
cost + value.
An optional psychological rounding is then applied: x.99, x.95, x.90 or round up to integer.
Scope and resolution
A rule can target a supplier, a category, both, or be global. The most specific one wins, in this order: supplier + category, then supplier only, then category only, then the global rule. Category rules also apply to child categories. With no rule at all, the default margin from the settings is used.
EAN priority between sources
When the same ean13 appears in several feeds:
- the supplier with the best priority owns the product;
- other sources are skipped for that reference;
- if a better-priority supplier later brings that EAN, it automatically takes over.
Combinations
Two feed shapes are supported.
One line per variant
Enable Build combinations and map group_reference (identical for every variant of one product) and attributes (the options, for example Size:M|Colour:Red). Separators |, , and ; are accepted between pairs, : and = between name and value.
One line per product, sizes packed in a column
This is the most common shape among textile and lingerie wholesalers:
sizes_stock : EU 70C | FR 85C:4,EU 70D | FR 85D:2,EU 75A | FR 90A:1
ean_codes : EU 70C | FR 85C:5901741925360,EU 70D | FR 85D:5901741925377
Enable Split packed variants and map variants_stock, plus variants_ean and variants_reference when the feed provides them. The module splits the line into one combination per size and matches stock, EAN and reference by label. Three settings sit next to the checkbox: the attribute group name (Taille by default), the separator between entries (,) and the separator between label and value (:).
The label/value split happens on the last occurrence of the separator, so a label such as EU 70C | FR 85C stays readable. Pairs built this way never go through string parsing, which rules out collisions with separators present inside the labels.
Tick the box before the first import. If you import without it first, the products are created with no group_reference: enabling the split afterwards means the module cannot find those parents and creates new ones, doubling your catalog. If it happens, delete the created products and clear the cursors from the Maintenance panel.
A second axis from a feed column
Many suppliers ship the colour in a separate column while the sizes are packed. Map variant_attribute to that column:
{
"fields": {
"reference": "id",
"name": "name",
"cost": "wholesale_price",
"variant_attribute": "color",
"variants_stock": "sizes_stock",
"variants_ean": "ean_codes"
}
}
Every combination of the product then gains a second axis, under the attribute group for the extra column set on the feed (Couleur by default). You get Size and Colour combinations, usable by faceted filters.
Since each feed line is a product in a single colour, the Colour group holds one value per product. Colourways are not merged into a single page with a colour selector: to navigate between them, use the related products below.
Related products
When the feed lists the other colourways or the associated models in a column of references, tick Import related products and map related:
{
"fields": {
"reference": "id",
"related": "other_colors"
}
}
The column holds a comma separated list of supplier references. The links are created as PrestaShop accessories, so they show up in your theme’s related products block.
Resolution happens once the feed has been read from end to end, because a reference very often points at a product appearing later in the file. Three behaviours to know:
- a reference pointing at the product itself is skipped, which is common since many suppliers list the whole group on every member;
- a reference pointing at a product absent from the feed is skipped without counting as an error: on a category-filtered export this routinely accounts for a fifth of the references;
- existing accessories are never deleted, so links you added by hand survive the import. In exchange, a grouping changed by the supplier leaves old links in place.
The number of links created appears in the end-of-import message and in a dedicated log column.
What the feed may overwrite
Five checkboxes per feed decide which fields are synchronized: prices, stock, name, descriptions, images. By default only prices and stock are checked.
If you rewrite the product pages for SEO, uncheck name and descriptions after the first import, otherwise the next cron pass will overwrite your work.
Products removed from the supplier catalog
Each feed picks its behaviour: leave untouched, set stock to zero, disable, or both. The action runs at the end of a completed full import, and only on the products that feed had created or linked.
In dropshipping, setting the stock to zero is the safest choice: the product can no longer be sold but keeps its URL and its ranking.
Categories and currencies
The category field accepts a plain name or a full path, for example Home > Office > Chairs. The separator is configurable per feed, and the Create missing categories option creates the absent levels. A path starting with the separator, such as /WOMEN/Lingerie, is read correctly.
If the supplier invoices in another currency, select it on the feed: costs are converted to the shop default currency before margins are applied.
Large catalogs
Feeds are read in streaming: the memory used does not depend on the file size. Processing is sliced into resumable batches. Two settings, in the Settings & Cron tab:
- Checkpoint every N items (2000 by default).
- Time budget per pass (120 s by default) — the next cron call resumes at the exact same item.
A very large catalog simply needs several cron passes and completes on its own. The downloaded file is cached while the import is unfinished.
Splitting multiplies the volume: a feed of 7,300 products with variants produces over 33,000 combinations, so roughly 41,000 objects created on the first full import. Plan for several passes and test on a staging shop before production.
Running an import manually
- Full import (play icon) — updates linked products and creates the missing ones if the feed allows it.
- Stock sync (refresh icon) — updates only prices and quantities of already-linked products.
From the back office a pass is capped at 45 seconds so the web server does not time out.
Automating with cron
# Hourly stock sync
0 * * * * curl -sL "https://yourshop.tld/index.php?fc=module&module=dfsupplierfeed&controller=cron&token=YOUR_TOKEN&mode=stock" > /dev/null
# Nightly full import
30 3 * * * curl -sL "https://yourshop.tld/index.php?fc=module&module=dfsupplierfeed&controller=cron&token=YOUR_TOKEN&mode=full" > /dev/null
Optional parameters: &id_feed=N to process a single feed, &budget=600 to allow a longer run.
If you regenerate the token in the settings, update your cron jobs: the old URL will return a 403 error.
General settings
- New products active immediately — disabled by default.
- Deactivate products out of stock at the supplier, reactivated when stock returns.
- Default margin when no rule matches.
- Log retention and automatic purge.
- On uninstall — delete the data or keep everything.
- Clear feed cache and cursors in the Maintenance panel.
Monitoring and logs
The Logs tab lists every run: feed, mode, items processed, created, updated, skipped, errors, missing, related links created, a completion flag with the resume point, execution time and the details of the first errors.
Troubleshooting
“Malformed CSV row: 23 columns instead of 22”
The row contains an unescaped delimiter or quote inside a text field. It is rejected to avoid importing shifted values.
“Feed file not found or outside shop directory”
For a file source, the path must point to a readable file inside the shop directory.
The analysis finds no items
Set items_path manually in the mapping, then run the analysis again.
Products are created but invisible on the front office
This is the default behaviour: created products are disabled.
Combinations are not created
Check that the matching box is ticked, that the required fields are mapped (group_reference and attributes, or variants_stock), and that the separators match the file.
My catalog doubled after enabling the split
The import ran before the box was ticked. Delete the products created by that feed, clear the cursors, then run again.
Few or no related links created
Links are only resolved at the end of a completed full import: on a large feed processed in several passes, they appear on the last one. Also check that the references in the column match the field mapped to reference.
Prices look too high or too low
Check whether the feed provides tax-inclusive costs, whether the currency is correct, which margin rule applies, and that the field mapped to cost really is a purchase cost.
The import never finishes
That is normal on a very large feed: it progresses in passes. The Status column gives the resume item.
Compatibility
- PrestaShop 8.0 to 9.x, PHP 7.4 to 8.3.
- No PrestaShop core override.
- Multistore: created products are associated with the shops of the current context.
- Interface translated into English and French.