Import and update products from supplier CSV, XML and JSON feeds in OpenCart 4.x or 3.0.x on a schedule: URL, FTP, SFTP or upload; field mapping with real sample values; markup by price band and category with .99 rounding; stock-only syncs; sizes and colours from feed rows; products the supplier dropped set to stock 0 with a safety limit; a dry-run preview with old and new values, run history with a row log and undo of any run. No core changes, no OCMOD.
On saleVersion 1.0.0Compatible with OpenCart 4.0.2.0 – 4.1.0.4, 3.0.3.8 – 3.0.5.1 No core file edits
Built forOpenCart
CSV, XML, JSON and uploaded supplier feeds in; prices with your margin, current stock and complete products out1 of 9
Import and update products from supplier CSV, XML and JSON feeds in OpenCart 4.x or 3.0.x on a schedule: URL, FTP, SFTP or upload; field mapping with real sample values; markup by price band and category with .99 rounding; stock-only syncs; sizes and colours from feed rows; products the supplier dropped set to stock 0 with a safety limit; a dry-run preview with old and new values, run history with a row log and undo of any run. No core changes, no OCMOD.
OpenCart 4.0.2.0 - 4.1.0.4, 3.0.3.8 - 3.0.5.1
Overview
Keep your catalogue in sync with your suppliers. Point the extension at a supplier feed (CSV, XML or JSON from a URL, FTP, SFTP, a file on your server or an upload), map the feed fields to your product fields once, add your price and stock rules, and let it create and update products on a schedule. A dry-run preview shows the old and new values before anything is saved, every run is logged with a row log, and any run can be undone.
OpenCart itself has no product import. This extension runs on its own, from one cron job, for as many suppliers as you have.
Feed list with schedules, last results and products per feed
Key features
Sources: HTTP and HTTPS URLs (with optional basic authentication), FTP and FTPS, SFTP, a file on your server and manual upload. gzip-compressed feeds are unpacked automatically.
Formats: CSV with delimiter and encoding detection, XML with a product element and XPath field paths (price, @id, images/image, param[@name="Color"]), JSON with dot paths (data.products, price.amount).
Field mapping with real samples: load the fields from the feed and see a sample value next to each one; Suggest mapping fills in the obvious ones; fixed values for fields the feed does not have; presets to reuse a setup.
Product fields: model or SKU as the match key, name, price, special price, quantity, status, category, manufacturer, description, meta title and description, tags, model, SKU, EAN, MPN, main and additional images, weight, out-of-stock status and any number of attributes.
Options from feed rows: feeds with one row per size or colour become one product with a select option, stock per value and the price difference to the cheapest row.
Categories: paths like Outdoor > Backpacks are found or created (with SEO keywords), or sent to a store category through a mapping table; a default category catches the rest.
Price and stock rules: markup by price band and category, in percent or a fixed amount, a special price from the feed price, rounding to cents, whole numbers, .99, .95 or .90, a stock threshold and cap, and value replacements such as "in stock" → 10.
Update modes: create and update, or update only; choose which fields change on existing products (for example only price and stock); unchanged rows are skipped.
Dropped products: products that left the feed get stock 0 or are disabled, only after a complete run and with a safety limit against broken files. A product that comes back is enabled again.
Dry run: the preview shows what each row would do, with old → new values. Nothing is saved.
Run history and undo: counters, a row log with the reason for each warning, and Undo restores the previous prices, stock, texts, options and images and disables the products a run created.
Scheduling: an interval per feed (15 minutes to once a day) and one cron URL for all feeds; on OpenCart 4 a cron job is added for you. Large feeds run in short steps that continue on the next call, and a lock prevents overlapping runs.
Images: downloaded in their own phase after the rows, again only when their URLs change; your own product photos stay.
Safe by design: feed and image URLs that point to your own server or a private network are refused, downloads have size and time limits, XML files with a DOCTYPE are refused (no XXE), passwords are stored encrypted, and a product is never created with a missing price.
Clean install: admin only, no storefront changes, no core file changes and no OCMOD.
OpenCart 4.0.2.0 – 4.1.x (kv_scheduled_feed_import.ocmod.zip) and 3.0.3.8 – 3.0.5.x (kv_scheduled_feed_import-oc3.ocmod.zip), one license for both. Tested on 4.1.0.4 and 3.0.5.1.
PHP 7.4 or newer (OpenCart 4.1 and 3.0.5 need PHP 8.1+) with cURL; XMLReader and DOM for XML feeds (present on almost every host).
Works with any theme: the extension changes nothing on the storefront; imported products are normal OpenCart products.
Installation
Requirements
OpenCart 4.0.2.0 – 4.1.x or 3.0.3.8 – 3.0.5.x
PHP 7.4 or newer (OpenCart 4.1 and 3.0.5 need PHP 8.1+) with cURL; XMLReader and DOM for XML feeds
For SFTP sources: PHP cURL built with SSH support or the ssh2 extension (ask your host; FTPS and HTTPS work everywhere)
A writable OpenCart storage folder (work files) and image/catalog/ (downloaded product images)
OpenCart 4
Extensions > Installer: upload kv_scheduled_feed_import.ocmod.zip and click Install.
Extensions > Extensions, type Modules: find Scheduled Supplier Feed Import, click Install (green +), then Edit.
Copy the cron URL from the settings page into your hosting control panel (every 5 minutes, see below).
Open Catalog > Feed import and add your first feed.
The extension adds its tables, two admin events (the menu entry and the daily license check) and a cron job in System > Maintenance > Cron Jobs that also runs due feeds once an hour. Nothing else is changed.
Copy the exact URL from the settings page; it contains your secret key. wget -q -O /dev/null "<URL>" works the same. Each call keeps importing for the Time per cron call set in the settings and continues where the last call stopped, so feeds with tens of thousands of rows work on normal hosting.
Without a cron job you can still run every feed with Run now in the admin panel. On OpenCart 4 the store's own cron (System > Maintenance > Cron Jobs) also runs due feeds once an hour.
Updating
Upload the new package through Extensions > Installer as above. Your feeds, mappings, presets and run history stay. On OpenCart 3 click Refresh in Extensions > Modifications afterwards.
Uninstalling
Extensions > Extensions > Modules > Scheduled Supplier Feed Import > Uninstall removes the feeds, presets, run history, events, cron job and work files. Products, categories, manufacturers, options and images that feeds created stay in your store.
Configuration
Open Extensions > Extensions > Modules > Scheduled Supplier Feed Import > Edit. These settings apply to all feeds; each feed has its own options on its feed page (see Usage).
Cron job card on the settings page
General
Setting
Default
Description
Status
Enabled
Off: the cron skips all feeds and Run now is unavailable. Feeds, history and undo stay available.
Maximum feed size (MB)
50
Larger downloads and uploads are stopped. Compressed (.gz) feeds count with their unpacked size.
Download timeout (seconds)
60
Time limit for downloading one feed file. Images use at most 30 seconds and 10 MB each.
Rows per step
100
Imports run in short steps (also in the admin panel). Lower it on slow hosting.
Time per cron call (seconds)
50
How long one cron call keeps importing. Keep it below the PHP time limit of your cron.
Runs kept per feed
30
Older runs, their row logs and their undo data are deleted.
Allow feeds from private network addresses
No
Feed and image URLs that point to this server, localhost or a private network (10.x, 172.16–31.x, 192.168.x, link-local and similar IPv4 and IPv6 ranges) are refused. Turn it on only if your supplier feed is on your own network.
Cron job
The card shows the cron URL and a ready-made cron command. The key in the URL protects it; if it was shared by mistake click New key, save and update your cron job. See Installation.
Permissions
The feed pages need the extension's own permission (System > Users > User Groups, access and modify for extension/kv_scheduled_feed_import/module/kv_scheduled_feed_import on OpenCart 4 or extension/module/kv_scheduled_feed_import on OpenCart 3) and the core Catalog > Products permission. Users with access only can view feeds, history and row logs; saving, previews, runs and undo need modify.
License
Enter your Kavio Labs license key (KAVIO-XXXX-XXXX-XXXX-XXXX, from My licenses on opencart.kaviolabs.com) in the License card and save. Check now verifies it at once.
The license is bound to your store's base domain and covers its subdomains. Development hosts (localhost, private IP addresses, *.test, *.local) always work.
Without a key the extension works fully for 14 days.
The check runs in the admin panel or from the cron job, once a day, never on storefront pages. It sends the key, the extension ID and version and your store's host names; no customer, order or product data.
Without a valid license new imports stop (scheduled runs and Run now). Feeds, mappings, presets, the preview, the run history and undo stay available, and your products are not touched. A banner on the feed pages tells you why.
Usage
Go to Catalog > Feed import. The list shows every feed with its source, schedule, the result of the last run, the next run and the number of products it manages. Add feed opens a new feed; each row has Run now, Edit, Enable/Disable, Copy and Delete. The feed editor has six steps.
1. Source
Source of a feed
Name, Run this feed on its schedule (disabled feeds are never run by the cron; Run now still works) and Run automatically: manually only, every 15 or 30 minutes, every 1, 3, 6 or 12 hours, or once a day.
Where the feed comes from:
URL: an HTTP or HTTPS address, with an optional login and password for basic authentication.
FTP / FTPS: ftp://host/path/file.csv or ftps://..., with the FTP login.
SFTP: sftp://host/path/file.xml, with the SFTP login (needs PHP cURL with SSH or the ssh2 extension).
File on this server: a path relative to the store folder, for example feeds/supplier.csv (allowed: .csv, .txt, .tsv, .xml, .json, .gz).
Uploaded file: drop a file on the upload box; upload a new one whenever you want to import it again.
Format:
CSV: the first row holds the column names. The delimiter (comma, semicolon, tab, pipe) and the encoding (UTF-8, Windows-1252, ISO-8859-1) are detected, or choose them.
XML: the Product element selects the element that holds one product, for example //product, //offer or /catalog/items/item.
JSON: the dot path to the product list, for example data.products (empty when the file is the list itself or an object with one list).
Passwords are stored encrypted and never shown again; leave the field empty to keep the saved one.
Click Save and load fields from the feed: the feed is downloaded once and its fields are listed with a sample value on the mapping step.
2. Field mapping
Field mapping with sample values
For each product field pick the feed field (or Type a field name or path for anything not in the list) and optionally a fixed value, used when the feed field is empty or not mapped. Suggest mapping picks the usual names (sku, title, price, stock, brand, image ...); check them before running.
Product code (match key) is required. Match products by Model or SKU decides which product field it is compared with. A row updates the product with the same code; otherwise a new product is created (its model is the code).
Category: a path like Outdoor > Backpacks is found by name or created; a numeric value is taken as a category ID. The Category mapping table sends exact feed category texts to a store category instead.
Manufacturer: found by name, created when allowed.
Special price: the open-ended special price of the default customer group. Specials with dates that you add yourself are never touched.
Main image URL and Additional image URLs: several URLs can come from one field (separated by | by default) or from repeated XML elements. If the product already has its own main image, the feed images are added after your images.
Out-of-stock status: the name of a stock status, for example 2-3 Days.
Attributes: add rows to fill attributes from Catalog > Attributes.
XML paths are XPath expressions relative to the product element: price, @id, price/@currency, images/image, param[@name="Color"]. JSON paths use dots: price.amount, images.0.
Options from feed rows
For feeds with one row per size or colour, map Parent code (rows with the same value become one product), Option name (usually a fixed value such as Size) and Option value. The product gets a required select option: each value has its own stock and the price difference to the cheapest row, and the product stock is the sum. Values that leave the feed keep their option with stock 0. Options and values are created when missing (can be switched off).
Options from feed rows
Presets
Save as preset stores the format, mapping, rules and import options. Choose a preset and click Apply to copy it into another feed.
3. Price and stock rules
Markup rules
Price markup: rules with Apply to (price or special price), a feed price range, an optional Category contains text and a percentage or fixed amount. The first matching rule per field is applied. A special price rule starts from the feed price when the feed has no special price. The example box shows the result for the first feed price.
Round prices: to cents, whole numbers, or up to .99, .95 or .90.
Treat stock below this as 0 and Show at most (a cap).
Replace values: change feed values before they are used, matching the whole value or a part of it, for example in stock → 10, yes → 1.
Number formats such as 1,234.56, 1.234,56, 12,5 and $19.90 are understood. Status values can be 1/0 or words like yes, no, enabled, disabled, active, hidden.
4. Import options
Import options for existing products
Create products that are not in the store (off = update only), Status of new products (for example Disabled until you check them), Category for new products, Stores, Feed language, Tax class, and whether missing categories, manufacturers and options are created.
Fields to update on existing products, for example only Price and Quantity. The shortcuts Price and stock, Stock only and All fields set them in one click. New products always get every mapped field.
Skip unchanged rows: rows whose values did not change since the last run are not written again (fast stock syncs).
When a product is no longer in the feed: do nothing, disable it, or set its stock to 0. Only products this feed created or updated before are affected, and only after a complete run. The Safety limit skips the action when more than the given share of the feed's products is missing (a broken or truncated file).
Category path and image URL separators, and the number of preview rows.
5. Preview
Run preview downloads the feed and shows what would happen to the first rows: create, update with the old and new value of each changed field, unchanged, skip or error, with the messages. Nothing is saved.
6. Run history
Run history
Run now (top right) imports the whole feed with a progress bar: rows first, then images, then the products that left the feed. You can leave the page; the cron finishes the run. Cancel stops it (rows imported so far stay imported).
The history lists each run with the start time, Run now or Scheduled, the status and the counters. Row log shows each warning or error with the row number, the product code and the reason, for example Price: "call us" is not a valid number or A new product needs a name. A new product is never created without a valid price.
Undo is offered on the newest run that changed something: it restores the values products had before that run (price, special price, stock, status, texts, codes, category, manufacturer, attributes, options and images) and disables the products the run created. Undo works backwards one run at a time; after undoing, the next run compares every row again.
FAQ
Does it change my storefront or core files?
No. It works only in the admin panel and from the cron URL, with no OCMOD and no core file changes. Imported products are normal OpenCart products.
How many suppliers can I connect?
As many as you like: one feed per supplier, each with its own schedule, mapping and rules.
My supplier sends prices without my margin. How do I add it?
Add markup rules on Price and stock rules: for example +45 % up to 50, +32 % from 50 to 200, +60 for tents over 200, and round to .99. The first matching rule is used.
I only want to update stock every 15 minutes, not my texts. Set Run automatically to every 15 minutes, click Stock only under Fields to update and keep Skip unchanged rows on. Rows that did not change are not written again.
What happens to products the supplier removed?
With When a product is no longer in the feed set to Set its stock to 0 or Disable it, they are changed after a complete run. The Safety limit (for example 20 %) stops this when a file is broken or truncated. Products that come back are enabled again.
Can I see what a run will do before it runs?
Yes: Preview shows the first rows with old → new values and saves nothing.
I ran a feed with a wrong rule. Can I go back?
Yes: Run history > Undo restores the previous values and disables the products that run created.
Does it work with XML feeds like Google Merchant or YML?
Yes. Set the product element (for example //item, //offer) and use XPath paths for the fields (namespaced fields such as g:price and g:id work with the prefix used in the file, attributes like @id, parameters like param[@name="Color"]).
My feed has one row per size. Do I get one product per size?
No: map Parent code, Option name and Option value and the rows become one product with a Size option, stock and price per size.
Are images downloaded every time?
No. Images are downloaded in their own step after the rows and only again when their URLs change. Your own product photos stay.
My feed is on my own network or on localhost. Turn on Allow feeds from private network addresses in the settings. It is off by default so a feed URL cannot be used to reach internal services.
Where is the cron command?
On the settings page, with the URL and your key. See Installation.
Is it multi-store?
New products and categories are added to the stores you tick on Import options; products are matched by model or SKU across the catalogue.
Server-side tracking for OpenCart 4.x and 3.0.x: purchases, refunds, add to cart, checkout, product views and leads go from your server to the free official GA4 Measurement Protocol, Meta Conversions API and TikTok Events API, deduplicated with the browser pixels through shared event ids. Consent-aware, SHA-256 hashed customer data, order status mapping, queue with retries, test mode and an event log. No paid relay, events only, no OCMOD.
The department store theme for OpenCart 4.x and 3.0.x: colour-coded departments, a department list beside the hero slider with two side promos, a big search with a department selector, tabbed product blocks, a 2 + 1 + 2 offer grid, deals of the day with real countdowns, a department showcase, a promotions band and a three-column product page with a sticky buy box. Four styles (Meridian, Harbor, Citrus, Night) and your own colours on top. Events only, no core changes.
Stop AI crawlers, scrapers, vulnerability scanners and unwanted countries before OpenCart 4.x or 3.0.x builds a page. Googlebot and Bingbot are verified by DNS and always allowed; 50+ bots get one switch each; country rules use free GeoIP databases and can close only the checkout; IP and network lists, rate limits, honeypots and the cart flood fix; a one-second challenge instead of a captcha; learning mode, dashboard, log, IP tester and Cloudflare export. No core changes, no OCMOD.