Learn how to customize your product information for different markets or brands, which are represented as Stores in your project.
After completing this page, you should be able to:
- Identify how Product Tailoring can help you present your products to different audiences.
- Apply tailored information to your Product Catalog using the Typescript/Java SDK.
Time to complete page: 15 minutes
You should already know that commercetools Composable Commerce allows you to have your product information available in different languages. But what if you would like to have a different description or image for your product depending on which Store it’s being viewed in? This is now possible thanks to Product Tailoring!
Product tailoring in commercetools Composable Commerce allows you to customize product information for different markets or brands, which are represented as Stores in your Project. Here's a breakdown of its benefits:
- Enhanced Targeting: Tailor product names, descriptions, images, and attributes to resonate with specific customer segments, improving their shopping experience.
- Improved Brand Consistency: Maintain brand consistency across multiple regions by adapting product information to match local preferences and languages.
- Increased Visibility: Optimize product data for different markets to rank higher in search results and attract a wider audience.
- Streamlined Operations: Manage market-specific product information efficiently within a single place, reducing complexity and potential errors.

As you can see in the above graphic, tailored data, once published, is used when viewing the product in a Store. If some tailored data is missing, original data will be used as a fallback.
Let’s see this first hand by creating some tailored information for the Cocktail Shaker Product within the context of the B2C Retail Store:
import com.commercetools.api.client.ProjectApiRoot;
import com.commercetools.api.models.common.ImageBuilder;
import com.commercetools.api.models.common.ImageDimensionsBuilder;
import com.commercetools.api.models.common.LocalizedStringBuilder;
import com.commercetools.api.models.product.ProductResourceIdentifierBuilder;
import com.commercetools.api.models.product_tailoring.*;
import com.commercetools.api.models.store.StoreResourceIdentifierBuilder;
public class SelfLearningExample {
public static void main(String[] args) {
ProjectApiRoot apiRoot = Client.createApiClient();
System.out.println("Product tailoring created: " +
apiRoot.productTailoring().post(
ProductTailoringDraftBuilder.of()
.key("retail-store-cocktail-shaker-data")
.store(StoreResourceIdentifierBuilder.of()
.key("b2c-retail-store")
.build())
.product(ProductResourceIdentifierBuilder.of()
.key("cocktail-shaker")
.build())
.name(LocalizedStringBuilder.of()
.addValue("en-GB", "B2C Premium Cocktail Shaker")
.addValue("en-US", "B2C Premium Cocktail Shaker")
.build())
.variants(ProductVariantTailoringDraftBuilder.of()
.sku("COCT-09")
.attributes(ProductTailoringAttributeBuilder.of()
.name("finish")
.value(LocalizedStringBuilder.of()
.addValue("en-GB", "Shining Silver")
.addValue("en-US", "Shining Silver")
.build())
.build())
.images(ImageBuilder.of()
.url("https://storage.googleapis.com/merchant-center-europe/sample-data/b2c-lifestyle/Cocktail_Strainer-1.2.jpeg")
.dimensions(ImageDimensionsBuilder.of()
.h(200)
.w(200)
.build())
.build())
.build())
.publish(true)
.build()
)
.executeBlocking().getBody().getKey()
);
apiRoot.close();
}
}
You probably noticed that we skipped the de-DE
locale in our tailored data. Good catch!
Once we have our tailored data created and published, we can see how it will look when viewing the Product within and without the context of the B2C Retail Store for all locales:
// Ensure all necessary imports are included and the API client is instantiated as demonstrated in the first example.
System.out.println(
"Tailored names: " +
apiRoot
.inStore("b2c-retail-store")
.productProjections()
.withKey("cocktail-shaker")
.get()
.executeBlocking()
.getBody()
.getName()
);
apiRoot.close();
We do see in our results:
{
'en-US': 'B2C Premium Cocktail Shaker',
'en-GB': 'B2C Premium Cocktail Shaker',
'de-DE': 'Cocktail Shaker'
}
The English versions of the name show our tailored data while the German version has the general name, which is exactly what we wanted. Because we did not specify tailored data for the de-DE
version of the name, the default non-tailored data is returned.
You can learn more about Product tailoring, its features, and how to use it in the Product Tailoring documentation.