Custom Import/Export Module Development for 1C-Bitrix

Custom Import/Export Module Development for 1C-Bitrix Standard exchange via CommerceML covers typical tasks with 1C: catalog, orders, balances. But when data comes in a non-standard format – XML from a supplier, JSON from a CRM, XLSX reports – performance drops and mapping becomes a quest. A cust

Our competencies:

Frequently Asked Questions

Custom Import/Export Module Development for 1C-Bitrix

Standard exchange via CommerceML covers typical tasks with 1C: catalog, orders, balances. But when data comes in a non-standard format – XML from a supplier, JSON from a CRM, XLSX reports – performance drops and mapping becomes a quest. A custom import/export module solves this: it works directly with any source, uses stream processing for large volumes, and supports bidirectional sync with collision control. We develop such modules turnkey: from schema analysis to deployment and admin training. Our team has been doing custom development for 10+ years and has successfully implemented 40+ integrations for retail, logistics, and manufacturing. We'll evaluate your project within one day – contact us for a consultation.

A typical scenario: you have an external warehouse or ERP system that outputs data in CommerceML format. But CommerceML is a heavy XML that takes hours to process volumes over 10,000 items per load. A custom module parses data with its own parser, using XMLReader for streaming, and can process up to 1,000 elements per second. The difference is 3–5 times faster than standard exchange. Additionally, we implement batch processing with Bitrix agents, eliminating web request timeouts.

When CommerceML Falls Short

CommerceML is a universal protocol, but it's not always flexible. If your data source is a JSON API of a third-party service, a binary XLSX with thousands of rows, or requires complex field transformations (merging, deduplication, linking to reference tables), standard exchange is inefficient. A custom module can handle arbitrary formats: XML (any schema), CSV, XLSX, JSON, and also fetch files via FTP/SFTP. For volumes over 100,000 records, chunked loading is mandatory – we embed it into the module core.

How Bidirectional Synchronization Works

The hardest part is avoiding collisions when changes occur simultaneously in both systems. We use timestamp-based sync with a sync_hash field. On export, we record the hash of the record state. On the next import: if the hash changed in the source – we update Bitrix; if it changed in Bitrix (user edited) – we send changes back to the source. If both changed – conflict, logged for manual resolution.

SQL for adding sync_hash field
ALTER TABLE b_iblock_element ADD COLUMN sync_hash VARCHAR(32); ALTER TABLE b_iblock_element ADD COLUMN synced_at DATETIME; 

Custom Module Architecture

A Bitrix module is a directory in /local/modules/{vendor}.{modulename}/ registered via RegisterModule. Standard structure:

local/modules/company.import/ ├── install/ │ ├── index.php # InstallDB(), UnInstallDB(), DoInstall() │ └── db/mysql/install.sql ├── lib/ │ ├── Importer.php # main logic │ ├── Parser/ │ │ ├── XmlParser.php │ │ └── CsvParser.php │ └── Queue/ │ └── ImportQueue.php ├── admin/ │ └── import_settings.php # administrative interface ├── include.php └── .settings.php 

Import from Custom XML Source

Example parser implementation for a custom schema:

namespace Company\Import; use Bitrix\Main\Loader; use Bitrix\Catalog\ProductTable; class Importer { private \SimpleXMLElement $xml; public function __construct(string $filePath) { Loader::includeModule('iblock'); Loader::includeModule('catalog'); $this->xml = simplexml_load_file($filePath); } public function run(): array { $stats = ['created' => 0, 'updated' => 0, 'errors' => 0]; foreach ($this->xml->products->product as $product) { try { $this->processProduct($product, $stats); } catch (\Throwable $e) { \Bitrix\Main\Diag\Debug::writeToFile($e->getMessage(), 'IMPORT ERROR', '/bitrix/modules/company.import/error.log'); $stats['errors']++; } } return $stats; } private function processProduct(\SimpleXMLElement $p, array &$stats): void { $externalId = (string)$p->id; $existing = $this->findByExternalId($externalId); $fields = [ 'IBLOCK_ID' => IMPORT_IBLOCK_ID, 'NAME' => (string)$p->name, 'CODE' => \CUtil::translit((string)$p->name, 'ru'), 'ACTIVE' => (string)$p->is_active === '1' ? 'Y' : 'N', 'PROPERTY_VALUES' => [ 'EXTERNAL_ID' => $externalId, 'VENDOR_CODE' => (string)$p->sku, 'DESCRIPTION' => (string)$p->description, ], ]; if ($existing) { \CIBlockElement::Update($existing, $fields); $stats['updated']++; } else { $el = new \CIBlockElement(); $newId = $el->Add($fields); if (!$newId) throw new \RuntimeException($el->LAST_ERROR); $stats['created']++; } // Update price and stock \CPrice::SetBasePrice($newId ?? $existing, (float)$p->price, 'RUB'); \CCatalogProduct::Update($newId ?? $existing, ['QUANTITY' => (int)$p->stock]); } } 

Batch Processing and Agents

For 100,000+ records, a direct web request is impossible – timeout. We use a Bitrix agent that saves progress in the database. The agent runs every minute and processes the next chunk:

class ImportQueue { public static function processChunk(int $jobId, int $offset, int $limit = 500): array { $job = ImportJobTable::getById($jobId)->fetch(); // ... read $limit rows starting from $offset // ... process // ... update progress in DB return ['processed' => $count, 'total' => $job['total_rows']]; } } function ImportAgent(): string { $activeJob = getActiveImportJob(); if (!$activeJob) return ''; $result = ImportQueue::processChunk($activeJob['id'], $activeJob['offset']); if ($activeJob['offset'] + $result['processed'] >= $result['total']) { markJobComplete($activeJob['id']); return ''; } return 'ImportAgent();'; } 

Data Export

Export to custom format for an external system:

class Exporter { public function exportOrders(\DateTime $from, \DateTime $to): string { $orders = \Bitrix\Sale\OrderTable::getList([ 'filter' => [ '>=DATE_INSERT' => $from->format('d.m.Y H:i:s'), '<=DATE_INSERT' => $to->format('d.m.Y H:i:s'), 'CANCELED' => 'N', ], 'select' => ['ID', 'ACCOUNT_NUMBER', 'PRICE', 'CURRENCY', 'DATE_INSERT', 'USER_ID'], ])->fetchAll(); $xml = new \XMLWriter(); $xml->openMemory(); $xml->startDocument('1.0', 'UTF-8'); $xml->startElement('orders'); foreach ($orders as $order) { $xml->startElement('order'); $xml->writeElement('id', $order['ID']); $xml->writeElement('number', $order['ACCOUNT_NUMBER']); $xml->writeElement('amount', $order['PRICE']); $xml->writeElement('date', $order['DATE_INSERT']->format(\DateTime::ATOM)); // ... order items $xml->endElement(); } $xml->endElement(); return $xml->outputMemory(); } } 

Formats and Sources

Format/Source Tools Notes
XML (custom) SimpleXML, XMLReader XMLReader for files > 100 MB
CSV/XLSX PhpSpreadsheet, fgetcsv XLSX – binary, requires library
JSON REST API curl, Guzzle Pagination, rate limiting
FTP/SFTP phpseclib Automatic file download
1C CommerceML Built-in Bitrix exchange Customization via events
Google Sheets Google Sheets API v4 For small volumes

How to Speed Up Large Catalog Import?

For volumes over 50,000 items, standard exchange hits PHP execution time and memory limits. A custom module uses asynchronous agents, chunked loading, and query profiling. We add indexes on external IDs and sync date, accelerating duplicate search by 10x. Clients achieve import of 100,000 elements in 2–3 minutes instead of an hour.

Timeline and Cost

Development cost is calculated individually based on mapping complexity, number of formats, and need for bidirectional sync. We'll give an accurate estimate after analyzing your data.

Stage Duration
Format analysis and field mapping 1–2 days
Parser/exporter development 3–5 days
Batch processing, Bitrix agent 2–3 days
Administrative interface 2–3 days
Bidirectional sync (if needed) 3–5 days
Testing with real data 2–3 days

Total: 2–3 weeks for one-way import; 3–4 weeks for bidirectional sync.

What’s Included

  • Module source code with comments.
  • Module API documentation and setup guide.
  • Access to Git repository with change history.
  • Admin training (up to 2 hours online).
  • 3-month warranty on uninterrupted operation.

Get an engineer consultation – request a preliminary audit of your exchange.CommerceML — exchange protocol