Someone asks you to switch off colour slicing for the whole catalog. Three hundred master products (the parent products that hold the colour and size options), each carrying its own copy of the variation attribute and its own slicing checkbox. You open Business Manager, click into the first master, find the setting, save, and look at the clock. Then you do the maths.

That is the moment most of us start looking for a script. And that is where the trouble starts, because the Script API cannot do it. The route that scales is export, transform, merge-import, reindex, validate, with the Admin Products API as an option for smaller batches. A sibling problem, which community members report in B2B catalogs, is that the same image ends up stored over and over on every variation.

Why Business Manager and the Script API Cannot Do This

In Business Manager, slicing is a checkbox on the variation attribute. You find it under Merchant Tools > (site) > Products and Catalogs > Variation Attributes, pick the catalog, open the attribute and tick Slicing Attribute. For a shared variation attribute that is one change covering every master that uses it, so the scale problem sits elsewhere: in local variation attributes (defined on each master, each with its own slicing-attribute flag in catalog.xsd) and in the category-level overrides covered below. The Variation Product Display page adds two rules: you can only slice by one variation attribute at a time, and the attribute should be searchable if you want it used in cross-category searches.

A quick recap of what slicing does, because I covered it in Slicing versus Variation Groups in Commerce Cloud: slicing decides what a search result tile represents. With slicing on, search returns variation products (the individual sellable variants under a master), so you get one tile per colour, for example. With it off, the base product (the master) is what shows up, as a single tile (or a variation group, if you use those and have assigned them to the category). Which model is better is a separate question; the task here is changing the setting at scale.

So why not script it? Because the Script API class dw.catalog.ProductVariationAttribute only exposes read-only attributeID, displayName and ID. There is no slicing getter and no setter. Nor does the rest of the Script API help: dw.catalog.Product has setters for a few flags (online, searchable, search rank), but nothing for variation attributes or variation relationships.

What about the APIs? The Admin Products API in the Commerce API does expose the flag. Its updateVariationAttribute operation is a PATCH on /products/{productId}/variation-attributes/{id}, and its request body includes a slicing boolean (the description lists name and slicing as the fields it updates). The general updateProduct call will not do it, because a product’s variationAttributes are read-only there. You need an Account Manager access token (the Admin APIs are secured by Account Manager, not by SLAS) with the sfcc.products.rw scope (see the Authorization Scopes Catalog). That endpoint only covers variation attributes on a product. The Admin Catalogs API has no endpoint for shared variation attributes, so a shared attribute cannot be changed this way.

The OCAPI Data API documents the same field in two places: a PATCH on /products/{product_id}/variation_attributes/{id} for local attributes, and a PATCH on /catalogs/{catalog_id}/shared_variation_attributes/{id} for shared ones, both listing name and slicing as the fields they update. OCAPI is deprecated, though. It still works, but Salesforce points new projects at the Commerce API, so I would only reach for it to change a shared attribute, which the Commerce API cannot do yet.

So there are two kinds of route, and they suit different jobs:

  • The APIs: one request per master per attribute (or one per shared attribute in OCAPI). Good for a few dozen masters, for a change you want to make from a pipeline, or for a fix you want to retry master by master. Neither API has an endpoint for category-level overrides that I could find, and neither rebuilds the search index for you.
  • Catalog XML import: one file for any number of masters, category overrides included, and it runs as a job next to the reindex. It also brings the merge-mode and element-order traps described below.

For hundreds of masters, or when category overrides are involved, the import is still the better tool, so that is what the rest of this post walks through. If you use an API, test the PATCH on a sandbox master first, and keep the reindex and validation checks further down.

The Workflow: Export, Transform, Merge-Import

Here is the shape of it. This order of steps comes from community advice rather than from a run against your catalog, so prove it on a sandbox with a fresh catalog first.

flowchart LR A["Export catalog\nto XML"] --> B["Drop masters and\nattributes you do not change"] B --> C["Script the edits\n(slicing flag)"] C --> D["Import in\nmerge mode"] D --> E["Rebuild product-related\nsearch indexes"] E --> F["Validate on the\nstorefront"]
  1. Export: Export the catalog from Business Manager (or with an export job) as one XML file.
  2. Trim: Remove every master and top-level variation attribute you do not intend to touch. Merge leaves objects the file does not mention alone, so a smaller file is a safer file, and it makes the diff reviewable. For the masters you keep, leave out <variants> or keep that list complete: variants defaults to merge-mode="replace", so a trimmed list can unlink the variants you left out. Keep any <attributes> list complete too, for the reason given under the snippet below.
  3. Transform: Script the edit with whatever you like (Node, Python, XSLT). The slicing flag is a boolean slicing-attribute in catalog.xsd, the XML schema file that defines what a valid catalog import file looks like. It is an XML attribute on <variation-attribute>, either as a top-level element next to <product> (a shared definition) or inside a master’s <variations><attributes> (a local one). A <shared-variation-attribute> reference carries no flag, so for shared attributes the change belongs on the shared definition. The snippet after this list shows the local case.
  4. Import with merge: Use import mode MERGE, which leaves objects and elements the file does not mention alone (a variants or variation-attribute-values list you do include is replaced wholesale by default). The Import Modes page describes MERGE as create-or-update, while REPLACE is a delete followed by a merge. You do not want that delete on a live catalog.
  5. Chain it in a job: A job (a scheduled or on-demand sequence of steps in Business Manager) can chain the ExportCatalog, ImportCatalog and SearchReindex steps. The transform in the middle needs a custom job step, because a job will not run your Node, Python or XSLT for you. That matters because storefront search reads from a search index, a separate copy of product data that is refreshed by a rebuild or, for some changes only, by incremental indexing. Chaining the steps means nobody forgets the last one at 17:55 on a Friday. Set ImportFailedHandling on the import step to ERROR (the default is WARN), and tick the product-related indexes on SearchReindex, because every index option there defaults to off.

For a master with local colour and size attributes, the trimmed and transformed product looks like this. Leaving out <variation-attribute-values> keeps the stored values untouched, because the element’s replace default only applies when the element is in the file. Leaving out <variants> keeps the variant links untouched for the same reason.

<catalog xmlns="http://www.demandware.com/xml/impex/catalog/2006-10-31" catalog-id="apparel-catalog">
    <product product-id="M-1001">
        <variations>
            <attributes>
                <variation-attribute attribute-id="color" variation-attribute-id="color" slicing-attribute="false"/>
                <variation-attribute attribute-id="size" variation-attribute-id="size"/>
            </attributes>
        </variations>
    </product>
</catalog>

Both attributes stay in the list on purpose. The import reference only says that an omitted <attributes> element leaves the attributes alone and that the order of the elements sets the sort order. It does not say what a partial list does to the attributes you left out, and catalog.xsd gives <attributes> no merge-mode to control it. Do not find out on production: keep the list complete, in the exported order.

Salesforce recommends keeping all entities of a catalog in one XML file, and the same reference explains why: the import runs in two passes. Pass one creates, updates and deletes objects. Pass two establishes relationships. And the import is not one big transaction: standard imports commit to the database per business object (Transaction Handling and Feed Size), so an aborted import can leave you with objects and no relationships.

That one fact is a plausible explanation for some of the “silently broken” reports: a new or changed master can be left behind with its relationship changes never applied, and the storefront will not necessarily tell you. That is my inference from the docs, not a documented failure mode.

Warning

If a run aborts halfway, do not just run it again and hope. Check which masters made it through and whether their variants are still linked before you retry.

Checks Before the Import

Most import surprises are visible in the file before you ever upload it.

  • Element order: Element order inside a <product> matters. catalog.xsd declares the children of product as a strict sequence, so validate the file against the schema before you upload it. Community reports say a wrong order can make data go missing after a merge. That is not documented, and I would expect a schema-invalid file to be rejected outright, so treat either outcome as a warning sign. Export a product from your own catalog, and mirror that order. I went deeper on this in SFCC Import and Export File Quirks, so I will not repeat it here.
  • The merge mode of the values: variation-attribute-values takes a merge-mode of add, merge, remove or replace, and the default is replace (from catalog.xsd). If the element is in your file without a merge-mode, the whole list in the system is replaced by the contents of your file, even though the import itself runs in MERGE mode. The values-level merge setting adds new values at the end, updates existing ones in place, and removes values that are not in the file. Pick add when you only want to append.
  • Variants are not deleted, they are orphaned: If the variants list in your file leaves out variation products the master currently has, those products are not deleted. They are unlinked from the base product and become standalone products. The variants list defaults to replace as well, and merge drops anything it does not list, so a trimmed file can do this without you noticing. A variation product has exactly one base product, and ownership cannot reliably change in one import (Product Types and Variations).
  • Site-specific attributes: These are attributes that carry a default value plus optional per-site overrides. online, searchable, search rank and sitemap attributes are site-specific and cannot be variation attributes. The import logs a data warning if you try (Site-Specific Product Attributes).
  • New products default to offline: In MERGE or REPLACE, a new product with no online status in the file comes in offline. Existing products keep their status unless you specify one.
  • Image groups: Salesforce says to set merge-mode="replace" on the images element (the default is merge) when you change the variation attributes a master varies its images by. It erases all stored image information for the product before reimport, so the file then has to carry every image group. view-type is required on each image-group.

The Category Override Nobody Remembers

You switched slicing off on the attribute, rebuilt the index, and the listing page still shows one tile per colour. Before you blame the import, check the category.

Slicing is not only the attribute-level default. A product’s category assignment can carry its own rule: on the master’s Categories tab, open the category’s Details, go to the Variation Values tab (the Help page calls it Variation Attribute Values), untick Use Default for the attribute and set Slicing Attribute to Yes, as the Trailhead module walks through. In the XML it sits on the category-assignment, as a variation-assignment element (inside variation-assignments) with a slicing-attribute boolean, as defined in catalog.xsd. The import reference calls it variation-configuration, but that name is not in the schema, and Variation Slicing by Category confirms that import and export include the category-assignment slicing rule. That override applies to searches refined by that category.

So a bulk change needs two passes of thought: the attribute default, and every category-level override that disagrees with it. I would grep the export for variation-assignment before writing a single line of transformation code (slicing-attribute alone also matches the attribute-level flag, so it is noisier).

Slicing, Variation Groups and the Image Side Effect

A short comparison, since the two get confused. If at least one variation group is assigned to a base product, slicing is disabled for that product, whether it comes from the attribute or from a category. Variation groups can then be used to choose images or swatches instead. Attribute inheritance runs from the variation product, to the variation group (by position), to the base product. The long version lives in Attribute Fallback in SFCC Variation Groups.

Then there is a side effect that community members have reported: a sliced attribute may return the swatch view type instead of the large one. I could not find that documented anywhere official (the docs only say what each view type is for: large on the product detail page, medium on search results, swatch to tell variation products apart), so treat it as community-reported until you have seen it on your own sandbox. If your tiles suddenly show tiny images after a slicing change, check which view type your tile template asks for first.

Reindex and Validate

Salesforce tells you to rebuild the product index after changing slicing (Merchant Tools > Search > Search Indexes, tick Product, click Rebuild). There is no separate catalog index to rebuild alongside it. Until you do, the storefront keeps answering from the old index, so the tiles stay as they were even though the catalog data has changed. Incremental indexing can narrow that gap for some product changes, but it postpones updates while an import is running and leaves out catalog structure, prices and searchable attributes, so I would not lean on it for a bulk change. For a big import, Salesforce suggests switching incremental indexing off and rebuilding the product index at the end.

Prices are a separate case. Price books can be imported on their own, as described in How SFCC Price Books Actually Work, and the price on a product page does not come from the search index. Search does use it: price refinements read the prices stored in the product index (see Price Books for Developers), so with standard price books the product index needs a rebuild after a price import too. Read-only price books are the documented exception.

After the rebuilds, run this list.

  1. Document count: The index rebuild finishes with a sensible number of documents. Indexed Elements on the Statistics tab of the product index is the number of products in the active index, and the Search Index Statistics page warns that a lower count can mean products are not searchable or a build did not finish. If you end up with zero, or a message that the loaded index does not match the active index, community reports point to the catalog or inventory list assignment of the site. The docs do not name those causes, so check both assignments first and keep looking if they are fine.
  2. Listing pages: Open a handful of categories, including at least one with a category-level override. Count the tiles for one master with several colours.
  3. Variant relationships: Open a master in Business Manager and confirm its variants are still listed. Search for a variant that was part of the file and confirm it is not standalone.
  4. Product detail pages: Switch every colour and size, and check the image view types.
  5. Import log: Read the warnings, not only the errors. A deprecated raw variation values warning only means the file still uses the old values element instead of variation-attribute-values; I treat it as noise. A data warning about site-specific attributes is not.

Duplicate Variation Media

Now for the sibling problem. In B2B catalogs, every colour needs its own images, and teams often assign the same external image path to every colour of every master. Images live on the base product, in image groups keyed by variation value (Understanding View Types: you can assign images only to the base product, not to the variation product). The documented external-image model keeps the host once in the catalog’s Image Settings and only a relative path in each image entry (Image Management), so check that you are using it before you build anything custom.

What the community reports is that the same path, repeated in every image group, still becomes a separate remote media object for each reference. These are records pointing at the same file, not copies of the file, but multiply them across every colour of every master, and your catalog carries a lot of redundant records. The docs say nothing about how these records are stored or whether identical paths share one, so treat this as reported behaviour and measure it on your own catalog.

The pattern that should avoid it is to stop storing the URL on the variation at all.

  • Base URL in a custom setting: Keep one base URL per environment (staging and production differ) in a custom site preference. Build the full image URL at render time from the base and the product ID or SKU.
  • CDN keyed by SKU: Serve images from an external CDN with a predictable path per SKU, and pull them in dynamically. The catalog then holds no per-variant image record to duplicate.

Both come at the same price: those images never enter the product image model, so anything that reads it (search tiles, feeds, headless storefronts) will not see them. Check what your storefront and integrations rely on before you go down this road.

Here is a sketch of the rendering side, as it might appear in a storefront script or template helper, with the anti-pattern first. It assumes product is the current dw.catalog.Product and that you have created a custom site preference (here called imageBaseUrl, but the name is yours to choose) by adding an attribute to the SitePreferences system object type.

var Site = require('dw/system/Site');

// DO NOT DO THIS: a hardcoded URL, repeated on every variation
var hardcoded = 'https://cdn.example.com/images/shirt-blue-front.jpg';

// Better: one configured base per environment, built per SKU at render time
function getFrontImageUrl(product) {
    var base = Site.getCurrent().getCustomPreferenceValue('imageBaseUrl');

    if (!base) {
        // No base configured on this instance: fall back to the catalog image
        var image = product.getImage('large');
        return image ? image.getAbsURL().toString() : null;
    }

    return base.replace(/\/$/, '') + '/' + encodeURIComponent(product.ID) + '-front.jpg';
}

In the second version the host lives in one custom site preference, so staging and production differ in a single place, and the SKU does the rest. If someone forgets to set the preference on a new sandbox, you get the catalog image instead of null/M-1001-front.jpg. And encodeURIComponent keeps an SKU with a space or a slash from breaking the path. The CDN still answers 404 for an SKU it has no image for, so give your <img> a fallback too. If the images live in the platform instead of on a CDN, let the platform build the URL: the product image model’s MediaFile for catalog images, or URLUtils.staticURL for static files, which the URLUtils reference says adds cache-related information to the path. Neither can build a CDN URL for you. There, versioned file names or sensible cache headers are your job. Community advice is that hardcoded image URLs can serve stale cached images, which fits that cache-related path segment, so I would not paste them in by hand either way.

Which one should you pick? They are the same pattern. If your images already live on a CDN keyed by SKU, the custom preference just makes the host configurable per environment. If they live on the platform, skip both and use URLUtils or the product image model. Either beats repeating the URL.

So the next time the request is “just flip it for every master”, start with the sandbox and a very boring checklist. Let us keep Business Manager for the one-off fixes!