# How to Configure Merchant Feed Adapter?

This document provides a comprehensive guide for configuring and managing **Merchant Feed Adapters** within the **Omnitron**, an essential tool for exporting structured product data to external platforms.

Merchant feeds are used to display products on comparison shopping engines, search engines, or affiliate platforms—allowing users to view product details, prices, and availability without visiting the brand’s actual e-commerce site. To support this, Omnitron enables merchants to generate and customize **XML feed files** based on their own schema requirements, language preferences, pricing lists, and filtering logic.

Whether you are creating a feed for a single market or managing a complex multi-language, multi-region catalog, this tutorial walks you through:

* Setting up new feed adapters through the Omnitron
* Structuring feed content using `schema_data`
* Mapping product attributes with flexible rule-based logic
* Filtering the feed by SKU or base code using uploaded files
* Managing multiple feeds by language and pricing combinations
* Manually or automatically triggering feed generation
* Accessing the final XML output via a generated file URL

By the end of this guide, you will be able to confidently configure and launch feeds that are optimized for your sales channels, meet third-party specifications, and scale across multiple locales with ease.

## <mark style="color:red;">Add Merchant Feed Adapter in Omnitron</mark>

To begin creating a Google Merchant Feed Adapter, follow the steps below.

### <mark style="color:red;">Navigate to the Feed Adapter Section</mark>

{% stepper %}
{% step %}
Go to **Sales Channels > Content Management > Google Merchant Feed Adapter.**
{% endstep %}

{% step %}
From this page, you can **view existing adapters**, **edit them**, or **add new ones**.
{% endstep %}

{% step %}
Click on **“+ New Goggle Merchant Feed Adapter”** to open the adapter creation form.

<figure><img src="/files/SmuCMkh2uSsDus3WFli9" alt=""><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

### <mark style="color:red;">Fill in Basic Adapter Settings</mark>

{% stepper %}
{% step %}
At the top of the page, you’ll see a set of core fields to define the adapter:

<table><thead><tr><th width="133.0625">Field</th><th>Description</th></tr></thead><tbody><tr><td><strong>Name</strong></td><td>A unique name for the feed adapter. This is used to distinguish between different feeds, especially in multi-language or multi-region setups.<br><em>Example:</em> <code>insider</code>, <code>google_feed_en</code>, <code>feed_ar_uae</code></td></tr><tr><td><strong>Adapter Type</strong></td><td>Defines which adapter class will handle feed generation. Select <code>base</code> unless your project includes a custom implementation.</td></tr><tr><td><strong>Status</strong></td><td>Set this to <code>Active</code> to allow the adapter to be used during scheduled or manual feed generation. If set to <code>Passive</code>, it will be ignored by automatic processes.</td></tr><tr><td><strong>One time</strong></td><td>Check this box if you want the feed to only be triggered manually. This disables scheduled executions.</td></tr><tr><td><strong>File URL</strong></td><td>This field is automatically filled after feed generation. It provides a direct link for the generated XML file.</td></tr><tr><td><strong>Choose File</strong></td><td>(Optional) Upload a filter file in <code>.csv</code> or <code>.xls</code> format. The system will convert it to base64. The file should contain <code>sku</code> or <code>base_code</code> headers to restrict which products are included in the feed.</td></tr></tbody></table>

<figure><img src="/files/pYjk7ZQByV1y29XavkZe" alt="" width="438"><figcaption></figcaption></figure>
{% endstep %}

{% step %}
If you're generating feeds for multiple markets, it's a best practice to name the adapter accordingly (e.g., `google_feed_ar_ksa`) and define separate adapters per language/price list.
{% endstep %}
{% endstepper %}

### <mark style="color:red;">Configure Feed Schema (</mark><mark style="color:red;">`config`</mark> <mark style="color:red;">field)</mark>

Once the basic adapter is settings is filled, the next critical step is configuring how the feed will be generated. This is done through the **`config` field**, which is a JSON object that defines the structure, behavior, and formatting rules for the XML file that will be generated.

This configuration directly determines:

* Which product attributes are included
* What the output file is named
* How images, categories, and language-specific values are handled
* Whether out-of-stock products are shown
* How visual content (like cropped images or additional images) is formatted

#### Example Configuration:

```json
{
  "chunk_size": 100,
  "schema_data": [
    {
      "tag": "description",
      "attr_type": null
    },
    {
      "tag": "g:gender",
      "attr_type": null,
      "default_value": "Default"
    },
    {
      "tag": "title",
      "attr_type": null,
      "default_value": "title"
    }
  ],
  "EXTRA_IMAGES": true,
  "feed_filename": "insider/insider-feed_en.xml",
  "IS_ALL_SMALL_IMAGE": true,
  "url_attribute_data": null,
  "THUMBNAIL_CROP_TYPE": "Center",
  "extra_image_configs": [
    {
      "tag_name": "g:image_link",
      "tag_option": {
        "crop": "Center",
        "width": 1080,
        "height": 1080
      }
    }
  ],
  "IS_REQUIRED_SMALL_IMAGE": true,
  "category_attribute_data": [
    "category_name_en-us"
  ],
  "include_stock_out_products": true,
  "price_list_id": 1,
  "stock_list_id": 3,
  "category_name_translate_key": "category_name_en-us",
  "MERCHANT_FEED_VISILABS_IMAGE_TAG": "g:additional_image_link",
  "MERCHANT_FEED_VISILABS_IMAGE_SIZE": {
    "crop": "Center",
    "width": 1080,
    "height": 1080
  },
  "CUSTOM_CATEGORY_MAPPING_ENABLED": true,
	"category_ids_dict": {
		"00010001": "custom category id"
	},
	"category_dict": {
		"00010001": "custom category name"
	},
}
```

#### Explanation of Key Fields:

<table><thead><tr><th width="270.16015625">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>chunk_size</code></td><td>Number of products processed per task run. Useful for optimizing large feeds. Must be greater than 0 and less than 1000.<br><em>Setting a value outside this range may result in validation errors or failed feed generation.</em></td></tr><tr><td><code>schema_data</code></td><td>List of tags to be included in the feed. Each item defines one XML tag. Optionally include a <code>default_value</code> if the mapped attribute is missing.</td></tr><tr><td><code>EXTRA_IMAGES</code></td><td>Enables inclusion of first product image in the feed.</td></tr><tr><td><code>feed_filename</code></td><td>Path + filename for the output feed. This should be unique per language/market.</td></tr><tr><td><code>IS_ALL_SMALL_IMAGE</code></td><td>Ensures small image versions are used where applicable.</td></tr><tr><td><code>url_attribute_data</code></td><td>Usually null unless custom logic is used for URL mapping.</td></tr><tr><td><code>THUMBNAIL_CROP_TYPE</code></td><td>Cropping strategy for image thumbnails. Options may include <code>Center</code>, <code>Top</code>, <code>Bottom</code>, etc.</td></tr><tr><td><code>extra_image_configs</code></td><td>Defines how extra images (e.g., <code>g:image_link</code>) should be rendered, including size and crop strategy.</td></tr><tr><td><code>IS_REQUIRED_SMALL_IMAGE</code></td><td>Forces the presence of small-sized images in the feed.</td></tr><tr><td><code>category_attribute_data</code></td><td>List of category-related product attributes. These are used when building the product's category tree or name.</td></tr><tr><td><code>include_stock_out_products</code></td><td>If <code>true</code>, includes products that are out of stock.</td></tr><tr><td><code>price_list_id</code> / <code>stock_list_id</code></td><td>Used to pull price and stock info from specific price/stock lists configured in Omnitron. Useful for multi-market feeds.</td></tr><tr><td><code>category_name_translate_key</code></td><td>Attribute key used to get the translated category name (e.g., for localized feeds).</td></tr><tr><td><code>MERCHANT_FEED_VISILABS_IMAGE_TAG</code></td><td>Specifies the tag under which additional images for Visilabs integration are exported.</td></tr><tr><td><code>MERCHANT_FEED_VISILABS_IMAGE_SIZE</code></td><td>Image dimensions and crop settings used for Visilabs-specific image feeds.</td></tr><tr><td><code>CUSTOM_CATEGORY_MAPPING_ENABLED</code></td><td>Enables manual category mapping by path. If set to <code>true</code>, feed category values can be overridden using <code>category_ids_dict</code> and <code>category_dict</code>.</td></tr><tr><td><code>category_ids_dict</code></td><td>Dictionary to override <code>&#x3C;category_code></code> based on category <code>path</code> value.<br>Format: <code>"{path}": "custom_code_value"</code><br>See: <a href="https://apidocs.akinon.com/commerce-openapis/data-warehouse/catalogs">Getting category path information</a></td></tr><tr><td><code>category_dict</code></td><td>Dictionary to override <code>&#x3C;category_name></code> based on category <code>path</code> value.<br>Format: <code>"{path}": "custom_name_value"</code></td></tr></tbody></table>

### <mark style="color:red;">Upload Filter Files (Optional)</mark>

To include only specific products in the feed, you can upload a filter file—**CSV** or **XLS**—containing product identifiers. Filter files help reduce feed size or tailor feeds to campaign-specific product lists. For example, if you want to export only a selection of SKUs for a seasonal collection, use a filter.

{% stepper %}
{% step %}
Go to the **Choose File** field in the adapter form.
{% endstep %}

{% step %}
Upload a `.csv` or `.xls` file.
{% endstep %}

{% step %}
File must contain a `sku` or `base_code` column.

{% hint style="warning" %}
If the file format or header is incorrect, the system will return an error:\
`No valid header found in file headers.`
{% endhint %}
{% endstep %}

{% step %}
You can also combine the uploaded filter file with additional config-based filters via the `filter_arguments` key in the config:

```json
"filter_arguments": {
  "is_listable": true
}
```

This way, only listable products **that also match the uploaded SKUs** are included in the feed.
{% endstep %}
{% endstepper %}

### <mark style="color:red;">Save and Generate the Feed</mark>

Once you’ve completed the **Basic Adapter Settings**, added your **config JSON**, and optionally uploaded a **filter file**, it’s time to save the adapter:

* Click **“Save”.**
* If your `config` field is valid and includes a `schema_data` section, the page will reload and reveal a new section called **Mapper Settings**.
* This section allows you to define the transformation logic for each XML tag listed in your `schema_data`.

{% hint style="warning" %}
If you skip the config or forget to include `schema_data`, the Mapper Settings section will **not** be displayed.
{% endhint %}

## <mark style="color:red;">Attribute Mapping with Rules and Actions</mark>

After configuring your feed schema using the `config` field, the next crucial step is to **define how each XML field (tag) retrieves its data** from the product catalog. This is done using the **Mapper Settings** section in the adapter interface.

Each XML tag listed under `schema_data` must have a corresponding **mapper**, which includes:

* A **rule** that determines when the mapping should be applied
* An **action** that defines how to fetch or transform the data

Together, these enable complex conditional logic, localization, and formatting for your feeds—ensuring data consistency and compatibility with platforms like Google Merchant Center.

<figure><img src="/files/ez1fBua3WcfZswjCkCFR" alt="" width="375"><figcaption></figcaption></figure>

Each mapper is a JSON object with two main parts:

#### 1. `rule`: *When should this mapping be applied?*

Defines the condition that must be true for the action to run.

#### 2. `action`: *How should the value be retrieved or constructed?*

Specifies how to fetch, format, or combine values.

### <mark style="color:red;">Rule Types (When)</mark>

<table><thead><tr><th width="217.21875">Rule Type</th><th>Description</th></tr></thead><tbody><tr><td><code>always</code></td><td>Always applies the action, regardless of product data</td></tr><tr><td><code>attributeexists</code></td><td>Applies only if a specific attribute exists on the product</td></tr><tr><td><code>multiattributeexists</code></td><td>Checks if multiple attributes exist (can be all or any)</td></tr><tr><td><code>query</code></td><td>Applies if a certain query condition is met (advanced)</td></tr><tr><td><code>in_dict</code></td><td>Checks if a field exists in a predefined dictionary</td></tr></tbody></table>

### <mark style="color:red;">Action Types (How)</mark>

<table><thead><tr><th width="221.8515625">Action Type</th><th>Description</th></tr></thead><tbody><tr><td><code>attrgetter</code></td><td>Retrieves a single attribute value</td></tr><tr><td><code>attrformatter</code></td><td>Formats an attribute using a custom template</td></tr><tr><td><code>multiattrformatter</code></td><td>Combines multiple attributes into a single string</td></tr><tr><td><code>outputdict</code></td><td>Uses a dictionary to map internal values to output values</td></tr><tr><td><code>stdout</code></td><td>Outputs a static value (useful for fixed tags)</td></tr></tbody></table>

#### Basic Example: Simple Attribute Getter

This mapper fetches the `description` field from the product data and maps it directly to the `<description>` XML tag.

```json
{
  "rule": {
    "rule_type": "always"
  },
  "action": {
    "action_type": "attrgetter",
    "action_kwargs": {
      "input_key": "description"
    }
  }
```

#### Example: Formatting Gender Using Output Dictionary

If your internal values for gender are stored as `M`, `F`, and `U`, but Google requires `male`, `female`, and `unisex`, use this:

```json
{
  "rule": {
    "rule_type": "always"
  },
  "action": {
    "action_type": "outputdict",
    "action_kwargs": {
      "input_key": "gender",
      "mapping_dict": {
        "M": "male",
        "F": "female",
        "U": "unisex"
      }
    }
  }
}
```

#### Combine Multiple Attributes

Use this action when you need to generate a value from multiple fields (e.g., combining brand + title + size).

```json
{
  "rule": {
    "rule_type": "always"
  },
  "action": {
    "action_type": "multiattrformatter",
    "action_kwargs": {
      "input_keys": ["brand", "title", "size"],
      "format_str": "{0} - {1} ({2})",
      "delimiter": " "
    }
  }
}
```

**Output Example:** `Nike - Air Max (42)`

### <mark style="color:red;">Handling Localized Fields</mark>

When generating feeds in **multiple languages**, you need to retrieve the correct **language-specific values** from product data. The format of your `input_key` inside the **mapper's `action_kwargs`** will vary depending on:

* Whether the feed is for the **default language**
* Whether the field is a **text** or **dropdown** attribute

#### <mark style="color:red;">For Default Language Feeds</mark>

If you're generating a feed in your **default language**, product attribute values can be accessed using this structure:

```json
"input_key": "attributes__{{attr_code}}"
```

This directly pulls the attribute from the product's default data.

#### <mark style="color:red;">For Localized Feeds (Non-Default Languages)</mark>

For other languages (e.g., Arabic, Turkish, English (US)), you need to reference **localized fields**. The structure depends on the **type of attribute**.

#### For text fields:

Use `localized_attributes` for retrieving translated text fields such as `title`, `description`, or `long_name`.

***Pattern:***

```
localized_attributes__{{language_code}}__{{attribute_code}}
```

***Example:***

```json
[
  {
    "rule": {
      "rule_type": "always",
      "rule_kwargs": {}
    },
    "action": {
      "action_type": "attrgetter",
      "action_kwargs": {
        "input_key": "localized_attributes__en-us__l_name"
      }
    },
    "shared_kwargs": {}
  }
]
```

#### For dropdown fields:

For dropdown attributes that have translated options (e.g., brand, material, gender), use the `attributes_kwargs` structure to access the translated label.

***Pattern:***

```
attributes_kwargs__{{attribute_code}}___translations__{{language_code}}__label
```

***Example:***

```json
[
  {
    "rule": {
      "rule_type": "always",
      "rule_kwargs": {}
    },
    "action": {
      "action_type": "attrgetter",
      "action_kwargs": {
        "input_key": "attributes_kwargs__brand___translations__ar__label"
      }
    },
    "shared_kwargs": {}
  }
]
```

{% hint style="warning" %}
Use the appropriate `language_code` (e.g., `en`, `ar`, `tr`) depending on the feed’s target market.
{% endhint %}

## <mark style="color:red;">Triggering and Monitoring Feed Generation</mark>

Once your Merchant Feed Adapter is configured and saved, it's time to **generate the actual XML feed file**. Omnitron provides both **automated** and **manual** triggering methods for this purpose. You can also **track the status** of the generation process and retrieve the final file URL programmatically.

**Automatic vs. Manual Triggering:**

<table><thead><tr><th width="216.5">Trigger Type</th><th>Description</th></tr></thead><tbody><tr><td><strong>Automatic (Scheduled)</strong></td><td>If the adapter's <code>One Time</code> checkbox is <strong>unchecked</strong>, Omnitron will automatically run the feed generation task every 3 hours.</td></tr><tr><td><strong>Manual (One-Time)</strong></td><td>If <code>One Time</code> is checked, the feed must be triggered manually via the API or Omnitron UI. This is useful for test feeds, campaign-based feeds, or ad-hoc exports.</td></tr></tbody></table>

### <mark style="color:red;">Trigger Feed Generation Manually (API)</mark>

To manually trigger feed generation for a specific adapter:

#### **Endpoint:**

```bash
POST /api/v1/remote/1/google_merchant_feed_adapter/{adapter_pk}/trigger_task/
```

Replace `{adapter_pk}` with the ID of the adapter you want to trigger.

#### Example Request:

```bash
curl --location --request POST 'https://your-commerce-url/api/v1/remote/1/google_merchant_feed_adapter/268/trigger_task/' \
--header 'Authorization: Token your_token_here'
```

#### Example Response

```json
{
  "cache_key": "6c27bc5a8f06442f96044302e6168d7a"
}
```

### <mark style="color:red;">Monitor Progress of Feed Generation</mark>

You can track the progress of the feed task using the returned `cache_key`.

#### Endpoint:

```bash
GET /api/v1/remote/1/google_merchant_feed_adapter/{adapter_pk}/trigger_status/?cache_key={cache_key}
```

#### Example Request:

```bash
curl --location 'https://your-commerce-url/api/v1/remote/1/google_merchant_feed_adapter/268/trigger_status/?cache_key=6c27bc5a8f06442f96044302e6168d7a' \
--header 'Authorization: Token your_token_here'
```

#### Example Response:

```json
{
  "completed_tasks": 1,
  "data": [
    {
      "progress": [1, 1],
      "completed": true,
      "chunk_count": 1
    }
  ],
  "progress_count": 1
}
```

{% hint style="warning" %}
**`progress: [x, y]`** represents **x completed chunks out of y total**. You can calculate progress percentage as:\
`(x / y) * 100`
{% endhint %}

### <mark style="color:red;">Get Feed File URL</mark>

Once the task is completed, the file will be available at the adapter’s detail endpoint.

#### Endpoint:

```bash
GET /api/v1/remote/1/google_merchant_feed_adapter/{adapter_pk}/
```

#### Example Request:

```bash
curl --location 'https://your-commerce-url/api/v1/remote/1/google_merchant_feed_adapter/268/' \
--header 'Authorization: Token your_token_here'
```

#### Example Response:

```json
{
  ...
  "file_url": "https://cdn.akinoncloud.com/google/insider-feed_en.xml"
}
```

You can now use this file URL in your Google Merchant Center, comparison shopping platforms, or campaign tracking tools.

### <mark style="color:red;">Error Handling</mark>

If a feed task is already in progress and a new one is triggered:

#### Example Response:

```json
{
  "non_field_errors": "Google Merchant Feed task is already running. Please wait until the current task is completed before starting a new one.",
  "error_code": "google_merchant_feed_adapter_100_2"
}
```

{% hint style="warning" %}
Always check if a task is running before triggering a new one to avoid queue conflicts.
{% endhint %}

### <mark style="color:red;">Triggering Feed Manually via Omnitron</mark>

In addition to using API calls, you can also **manually trigger feed generation directly from the Omnitron interface**—with just a few clicks.

{% stepper %}
{% step %}
**Select the Feed Adapter(s):**

Use the checkbox on the left to select the adapter(s) you want to run. You can select one or multiple rows.
{% endstep %}

{% step %}
**Open the "Select Action" Dropdown:**

At the top of the list, open the **Select Action** dropdown.
{% endstep %}

{% step %}
**Click “Trigger Task with Selected Items”:**

This option will immediately initiate the feed generation task for the selected adapters.

<figure><img src="/files/tWVRNC2uhEv9qsPyEj3t" alt=""><figcaption></figcaption></figure>
{% endstep %}

{% step %}
**Click “Apply”:**

The task will be queued and executed via Celery. You can monitor the task’s status using the API or check the file URL once generation is complete.

<figure><img src="/files/bFWFSz33hmOCgoQCaOUw" alt=""><figcaption></figcaption></figure>
{% endstep %}
{% endstepper %}

## <mark style="color:red;">Feed URL Usage</mark>

Once the feed generation is complete, the XML file becomes accessible via the provided `file_url`.\
For example, you can access the generated feed directly at:

{% embed url="<https://2c1676.s3.amazonaws.com/insider/insider-feed_en.xml>" %}

<figure><img src="/files/Zb6gOaXHubpTxzE4a2cT" alt=""><figcaption></figcaption></figure>

You can now use this URL to upload the feed to Google Merchant Center or share it with external platforms that support scheduled product feed imports.

{% hint style="warning" %}
This URL remains valid as long as the feed is not deleted or regenerated under a different filename.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.akinon.com/tutorials/omnitron/sales-channels/content-management/how-to-configure-merchant-feed-adapter.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
