> For the complete documentation index, see [llms.txt](https://docs.hotwax.co/documents/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hotwax.co/documents/learn-shopify/shopify-reference/products/download-products.md).

# Product Sync from Shopify

Learn how HotWax Commerce downloads product data from Shopify using bulk operations and change detection.

HotWax Commerce treats Shopify as the primary source of truth for all product information. To keep large product catalogs synchronized without hitting API limits, HotWax uses the Shopify GraphQL Admin API and bulk operations.

The synchronization process runs in seven stages:

1. **Queue the request:** The scheduled `Sync Shopify Product Updates` job plans the sync. It identifies exactly what data is needed from Shopify based on the last successful sync time and adds a small time buffer to make sure no updates are missed.
2. **Send to Shopify:** HotWax sends the bulk query to Shopify's GraphQL Admin API and records the bulk operation that Shopify creates in response.
3. **Confirm completion:** Shopify processes the bulk query in the background. HotWax confirms when the operation finishes in two ways: it polls Shopify on a schedule, and it listens for a real-time `Bulk Operations Finish` webhook from Shopify. Once completion is confirmed, HotWax downloads the result file, a JSONL file containing the products and variants returned by the query. If Shopify completes the operation without a result file, there is no product file to import.
4. **Prepare data:** HotWax reads the downloaded file, transforms it into a nested JSON format, and queues it for the database sync.
5. **Identify changes:** Instead of overwriting the database, HotWax identifies exactly what has changed using a baseline comparison strategy. It groups related product data (such as core details, tags, features, identifiers, and variant associations) and computes a unique SHA-256 hash for each group. If a new hash matches the one stored in the `ProductUpdateHistory` table, that group has not changed and is skipped.
6. **Update the database:** Only the identified changes (deltas) are applied. This selective update handles core product details, features, tags, pricing, and identifiers like SKU and UPC. It also detects the correct product type (such as `FINISHED_GOOD` vs. `DIGITAL_GOOD`) based on Shopify flags.
7. **Save history:** Finally, HotWax updates the `ProductUpdateHistory` record with the new hashes and a snapshot of the current data. On subsequent runs, matching hashes let HotWax skip unchanged data groups rather than reapply those updates.

```mermaid
sequenceDiagram
    accTitle: Shopify export and HotWax product import stages
    accDescr: HotWax queues a Shopify bulk query and confirms completion by polling or webhook. When there is a result file, HotWax downloads and transforms it, queues the product import, compares data-group hashes, applies changes, and saves update history. Export completion does not prove import success.
    participant Connector as HotWax connector
    participant Shopify
    participant Import as HotWax product import
    Connector->>Connector: Queue product update request
    Connector->>Shopify: Start bulk query
    Note over Shopify: Prepare requested product data
    Shopify-->>Connector: Completion via poll or webhook
    opt Export has a result file
        Connector->>Connector: Download and transform file
        Connector->>Import: Queue product import
        Import->>Import: Compare hashes and apply changes
        Import->>Import: Save update history
    end
```

Shopify export completion does not prove that the HotWax import succeeded. To inspect the current pipeline:

1. Open the Company App and select `Shopify`.
2. Open the affected Shopify connection, then select `Product sync`.
3. Review `Track sync progress` for the system message, Shopify bulk operation, and HotWax bulk import separately.
4. Check whether the import completed, failed, or was skipped because Shopify returned no product data. Review failed records before recovery.

<figure><img src="https://1292394199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fq42f0puI9OYah51t08oQ%2Fuploads%2Fgit-blob-efca5c4836c366cf72a70abcc8a3beece41e3f8e%2Fcompany-product-sync-dashboard.jpg?alt=media" alt="Company App Product sync dashboard for Demo Store showing a consumed system message, completed zero-object Shopify bulk operation, and skipped HotWax bulk import"><figcaption><p>Demo Store example with no product updates returned: Shopify export is Complete and the HotWax import is Skipped. This is not an example of a successful populated import.</p></figcaption></figure>

Use [Monitor Shopify product sync](https://github.com/hotwax/oms-documentation/tree/user-guides-pub/documents/system-admin/administration/company/manage-shopify-product-sync.md) for the complete operational workflow and recovery controls.

<details>

<summary>Developer details: services, system messages, and statuses</summary>

The flow runs on a single system message of type `BulkQueryShopifyProductUpdates`, which moves through the following services and statuses:

| Stage                                      | Service                                                                                                                                               | System message status |
| ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| Queue the request                          | `sync#ShopifyProductUpdates` (job `sync_ShopifyProductUpdates`)                                                                                       | `SmsgProduced`        |
| Send to Shopify                            | `send#ShopifyBulkQueryMessage` (saves the bulk operation ID to `remoteMessageId`)                                                                     | `SmsgSent`            |
| Confirm completion                         | `poll_ShopifyBulkOperationResult` job, or the `Bulk Operations Finish` webhook; the result downloads to `${receiveMovePath}/${systemMessageId}.jsonl` | `SmsgReceived`        |
| Prepare data                               | `consume#ShopifyProductDataFile` uploads to the master data management (MDM) queue `SYNC_SHOPIFY_PRODUCT`                                             | `SmsgConsumed`        |
| Identify changes, update, and save history | `sync#ShopifyProduct` computes the SHA-256 hashes, writes the deltas, and updates `ProductUpdateHistory`                                              | —                     |

For a completed export with no result URL, HotWax marks the system message consumed without creating a product import file. The import stage above applies when Shopify returns a result file.

</details>

***

### Product data mapping

#### Parent product

A virtual product, also known as a parent product, does not have a set size or color. All fields in the product JSON are imported, but only relevant fields are processed to improve system performance. Here is how parent product fields are mapped between Shopify and HotWax:

| No. | Shopify fields | HotWax fields      |
| --- | -------------- | ------------------ |
| 1   | ID             | Shopify Product ID |
| 2   | Title          | Product Name       |
| 3   | Body HTML      | Product Content    |
| 4   | Vendor         | Brand              |
| 5   | Product\_type  | Categories         |
| 6   | Tags           | Tags               |
| 7   | Variant        | Variant            |
| 8   | Media          | Overview           |

<div data-full-width="false"><figure><img src="https://1292394199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fq42f0puI9OYah51t08oQ%2Fuploads%2Fgit-blob-e97875ae226ef68f2ba1a42d22beb80f488d62f6%2Fshopify-product-catalog.jpg?alt=media" alt="Shopify demo catalog showing parent product titles, status, and inventory across fifteen variants per product"><figcaption><p>Demo catalog in Shopify. Each row represents a parent product with its variants; quantities are examples captured from the demo store.</p></figcaption></figure></div>

#### Variant product

The parent product comes in various sizes and colors, resulting in multiple variants. Here is how product variant fields are mapped:

| No. | Shopify fields     | HotWax fields      |
| --- | ------------------ | ------------------ |
| 1   | Product Variant ID | Shopify Product ID |
| 2   | Title              | Product Name       |
| 3   | Options            | Feature            |
| 4   | Image              | Image              |
| 5   | Parent Product     | Parent Product     |
| 6   | Price              | Price              |
| 7   | SKU                | SKU                |
| 8   | Quantity           | View inventory     |
| 9   | Shipping           | Shippable          |
| 10  | Product Type       | Product Type       |
| 11  | Weight             | Weight             |
| 12  | Metafields         | Product Tag        |

<figure><img src="https://1292394199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fq42f0puI9OYah51t08oQ%2Fuploads%2Fgit-blob-9e7aecf866fb4eab8e1a9bd6d163eb61463bb6c8%2Fshopify-variant-options.jpg?alt=media" alt="Abominable Hoodie XS Blue variant in Shopify with its parent product, size, color, image, and price"><figcaption><p>The XS / Blue variant belongs to the Abominable Hoodie parent product. Its size and color distinguish it from the other variants.</p></figcaption></figure>

<figure><img src="https://1292394199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fq42f0puI9OYah51t08oQ%2Fuploads%2Fgit-blob-0d1d90d251b23b62fdac337cfe8cadc56f04a8a3%2Fshopify-variant-identifiers.jpg?alt=media" alt="Shopify variant More details section showing SKU MH09-XS-Blue and barcode MH09XSBlue"><figcaption><p>SKU and barcode for the same demo variant. Use the configured primary identifier when matching the variant to a HotWax product.</p></figcaption></figure>

Shopify has multiple product identifiers, such as Shopify Product ID, Product SKU, Product Name, and UPC. Before importing products, set up the primary product identifier that maps to the product ID in HotWax. The primary product identifier can be configured in HotWax when setting up a new product store.

#### Manage sales orders for products not in HotWax

When orders are placed on Shopify, they transfer to HotWax. However, sometimes an order might include a newly launched product in Shopify that has not yet synced with HotWax. This can cause the order download to fail if the product import job has not yet run. To prevent this, HotWax creates a temporary placeholder product for the new item. Once the product import job runs, the system adds the necessary information, such as the product name, brand, price, and weight, to the placeholder product. This makes sure that the order download succeeds.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.hotwax.co/documents/learn-shopify/shopify-reference/products/download-products.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
