Product Mapping
Product Mapping is the core feature of Tapestry Stitch that transforms Shopify product data into the format required by Bloomreach. Through customizable field mappings, you can control exactly how your product information is synchronized between systems.
Overview
Product Mapping allows you to:
- Define data transformations using Liquid templates
- Map Shopify fields to Bloomreach attributes
- Control data types to ensure proper JSON formatting
- Preview transformations before syncing
- Import/Export mappings for backup or replication
Basic Concepts
Entities
Product mappings operate on two entity types:
Product
Product-level attributes apply to the entire product and are the same across all variants.
Examples:
title- Product namedescription- Product descriptionbrand- Product vendor/brandthumb_image- Featured product imagecategory_paths- Product collections
Variant
Variant-level attributes apply to individual product variants and can differ between variants of the same product.
Examples:
price- Variant pricesku- Stock keeping unitinventory_quantity- Available inventorycolor- Variant color optionsize- Variant size option
Bloomreach Target
The Bloomreach Target is the field name in Bloomreach where the data will be stored. This should match the expected attribute names in your Bloomreach catalog schema.
Bloomreach has reserved field names that cannot be used as custom attributes. Common reserved words include: score, rank, query, and others. For a complete list, refer to the Bloomreach Reserved Words Documentation.
Common targets:
id- Unique product or variant identifiertitle- Display nameprice- Product priceavailability- Stock availabilitycustom_attribute_name- Any custom field you define
Shopify Source
The Shopify Source uses Liquid template syntax to reference and transform Shopify data. This powerful templating language allows you to access nested data, perform calculations, and apply transformations.
Simple examples:
{{ product.title }}
{{ variant.price }}
{{ product.vendor }}
Advanced examples:
{%- assign total = 0 -%}
{%- for variant in product.variants -%}
{%- assign total = total | plus: variant.inventoryQuantity -%}
{%- endfor -%}
{{ total }}
See the Liquid Filters documentation for available custom filters.
Types
Types determine how values are formatted in the final JSON output to Bloomreach:
String
Text values, properly escaped and quoted.
"title": "Example Product"
Use for: Names, descriptions, URLs, SKUs
Integer
Whole numbers without decimal points.
"quantity": 42
Use for: IDs, inventory counts, whole number values
Float
Decimal numbers with floating-point precision.
"price": 29.99
Use for: Prices, weights, ratings, percentages
Boolean
True/false values (unquoted).
"available": true
Use for: Flags, availability status, feature toggles
Object
Complex JSON objects or arrays. This type is special because it can:
- Build nested JSON structures
- Create arrays of any type
- Define a JSON schema for validation during sync
"category_paths": [
{"id": "collection-1", "name": "Category 1"},
{"id": "collection-2", "name": "Category 2"}
]
Use for: Arrays, nested objects, complex data structures
JSON Schema Validation
When using the object type, you can optionally define a JSON schema to validate the rendered output during the sync job. If validation fails, the sync job will log an error and skip the invalid data.
Benefits:
- Catch malformed data early
- Ensure consistent data structure
- Prevent invalid data from reaching Bloomreach
Creating & Editing Mappings
Creating a New Mapping
- Navigate to Product Mappings in the Tapestry Stitch admin
- Click "New mapping" in the top right
- Select the Entity (Product or Variant)
- Enter the Bloomreach Target (e.g.,
title,price,custom_field) - Choose the Type (string, integer, float, boolean, or object)
- Write the Shopify Source using Liquid syntax
- Click "Create" to save
Editing an Existing Mapping
- Click on any mapping in the table
- Update the fields as needed
- Click "Save" to apply changes
The Bloomreach Target and Entity cannot be changed after creation. To change these, delete the mapping and create a new one.
Example: Product Title with Translation
Entity: Product
Bloomreach Target: title
Type: string
Shopify Source: {{ "product.title" | translate }}
This mapping uses the translate filter to automatically return the localized product title based on the current locale.
Example: Total Inventory Calculation
Entity: Product
Bloomreach Target: total_inventory
Type: integer
Shopify Source:
{%- assign total_inventory = 0 -%}
{%- for variant in product.variants -%}
{%- assign total_inventory = total_inventory | plus: variant.inventoryQuantity -%}
{%- endfor -%}
{{ total_inventory }}
This mapping calculates the total inventory across all variants of a product.
Working with Object Types
The object type is the most powerful mapping type, allowing you to build complex JSON structures including arrays and nested objects.
Building Arrays
Arrays can contain strings, integers, floats, booleans, or nested objects:
String array:
[
{%- for option in product.options -%}
{{ "option.name" | translate | json }}
{%- unless forloop.last -%}, {% endunless -%}
{%- endfor -%}
]
Object array:
[
{%- for collection in product.collections -%}
{
"id": {{ "collection.handle" | translate | json }},
"name": {{ "collection.title" | translate | json }}
}{% unless forloop.last %},{% endunless %}
{%- endfor -%}
]
Schema Validation
When creating an object-type mapping, you can define a JSON schema to validate the rendered output:
{
"type": "array",
"items": {
"type": "object",
"required": ["id", "name"],
"properties": {
"id": { "type": "string" },
"name": { "type": "string" }
}
}
}
If the rendered Liquid template doesn't match this schema during sync, an error will be logged and the invalid data will be skipped.
Example: Category Paths
This is one of the default mappings that demonstrates the power of the object type:
Entity: Product
Bloomreach Target: category_paths
Type: object
Shopify Source:
[
{%- for collection in product.collections -%}
{
"id": {{ "collection.handle" | translate | string }},
"name": {{ "collection.title" | translate | string }}
}{% unless forloop.last %},{% endunless %}
{%- endfor -%}
]
This creates an array of category objects, each with an id and name property, translated to the current locale.
Preview Feature
The Preview feature is one of the most powerful tools for developing and debugging your product mappings. It allows you to see exactly how your Shopify data will be transformed before running a sync.
Opening the Preview
Click the "Preview" button in the top right of the Product Mappings page to open the preview modal.
Selecting a Product
- Click "Select Product" in the preview modal
- Use the Shopify resource picker to choose any product from your store
- The preview will automatically load and display the transformation
Understanding the Tabs
The preview modal has two tabs:
Shopify Tab
Shows the raw Shopify product data along with catalog context (locale, URL, etc.) that's available to your Liquid templates.
What you see:
- Complete product object with all fields
- Catalog configuration (locale, URL)
- All data available for reference in Liquid templates
Use this to:
- Understand the structure of Shopify data
- Find the correct field paths for your mappings
- See what data is available for a specific product
Bloomreach Tab
Shows the final transformed payload that will be sent to Bloomreach, exactly as it will appear after your mappings are applied.
What you see:
- Product-level attributes
- Array of variant objects
- Final JSON structure sent to Bloomreach
Use this to:
- Verify your mappings are working correctly
- Debug transformation issues
- Confirm data types are correct
Copy JSON Feature
Both tabs include a "Copy JSON" button that copies the current tab's JSON to your clipboard.
ChatGPT Prompt Example
After copying the Shopify JSON, you can use ChatGPT to help write Liquid templates. Here's an effective prompt pattern:
I have a Shopify product with this JSON structure:
[paste the Shopify JSON here]
I need to write a Liquid template that extracts [describe what you need].
The template should:
- [specific requirement 1]
- [specific requirement 2]
- Return [expected output format]
Please provide the Liquid template code.
Example:
I have a Shopify product with this JSON structure:
[paste JSON]
I need to write a Liquid template that creates an array of all image URLs
from the product, excluding the featured image.
The template should:
- Loop through product.media
- Filter for images only (not videos)
- Skip the featuredMedia
- Return a JSON array of URL strings
Please provide the Liquid template code.
Locale Selection
If your store has multiple locales configured, you can use the locale dropdown to preview how translations will appear in different markets.
Refresh Button
Click "Refresh" to re-fetch the product data and re-run all transformations. This is useful after editing mappings to see the changes immediately.
Import/Export
The Import/Export feature allows you to backup your mappings, replicate configurations across stores, or share mapping configurations with team members.
Exporting Mappings
- Click "Export mappings" in the Product Mappings page
- All mappings are copied to your clipboard as JSON
- Paste into a file for backup or sharing
Export format:
{
"shop": "example-store.myshopify.com",
"exportedAt": "2025-01-15T10:30:00.000Z",
"mappings": [
{
"resource": "product",
"targetAttribute": "title",
"sourceValue": "{{ product.title }}",
"type": "string"
}
// ... more mappings
]
}
Importing Mappings
- Click "Import mappings"
- Paste the exported JSON
- Click "Import"
Upsert Behavior
The import process uses upsert logic:
- Matching mappings (same entity + target) are updated with the new source value and type
- New mappings (no match) are created
- Existing mappings not in the import are left unchanged
This allows you to:
- Safely import partial mapping sets
- Update specific mappings without affecting others
- Merge configurations from multiple sources
Import results:
Import complete! 5 created, 12 updated, 8 unchanged
Use Cases
Backup before major changes:
1. Export current mappings
2. Save to file with date
3. Make changes
4. Restore if needed by importing the backup
Replicate across stores:
1. Export from production store
2. Import to staging/development store
3. Adjust as needed for environment differences
Share configurations:
1. Export your working mappings
2. Share JSON with team members
3. They import to their development stores
Default Mappings
Tapestry Stitch comes with a set of default mappings that cover common use cases. You can reset to defaults at any time using the "Reset to Defaults" button.
Default Product Mappings
id- Product IDtitle- Translated product titledescription- Product description (body)brand- Product vendortotal_inventory- Sum of all variant inventoryavailability- Product is active and in stockthumb_image- Featured image URLurl- Product URL on storefrontoption_names- Translated option namescategory_paths- Collection hierarchy as objects
Default Variant Mappings
id- Variant IDprice- Variant pricesku- Variant SKUinventory_quantity- Available inventorydefault_variant- True for first variantcolor- Color option valuesize- Size option value
Resetting to defaults will delete all custom mappings and restore only the default set. This action cannot be undone. Export your mappings first if you want to preserve them.
Best Practices
1. Use Type Filters for JSON Output
Always use the appropriate type filter when building JSON to ensure proper formatting:
{
"id": {{ product.id | integer }},
"title": {{ product.title | json }},
"price": {{ variant.price | float }},
"available": {{ product.available | boolean }}
}
See Liquid Filters for detailed documentation on all available filters.
2. Handle Null Values
Use the custom json filter to properly handle null/undefined values:
{{ potentially_null_var | json }}
This outputs null instead of an empty string, keeping JSON valid.
3. Test with Preview
Always use the Preview feature to verify your mappings before syncing:
- Select a representative product
- Check both Shopify and Bloomreach tabs
- Verify data types are correct
- Test edge cases (missing data, null values)
4. Use Translation Filters
For multi-locale stores, use the translate filter to ensure proper localization:
{{ "product.title" | translate }}
{{ "product.metafields.namespace.key" | translate }}
5. Export Regularly
Export your mappings periodically as backups:
- Before major changes
- After completing a new configuration
- When you have a stable working setup
6. Document Complex Mappings
For complex Liquid templates, consider adding comments to explain the logic (these won't appear in the output):
{%- comment -%}
Calculate total inventory across all variants
excluding discontinued variants (inventory_policy = continue)
{%- endcomment -%}
{%- assign total = 0 -%}
{%- for variant in product.variants -%}
{%- if variant.inventoryPolicy != 'continue' -%}
{%- assign total = total | plus: variant.inventoryQuantity -%}
{%- endif -%}
{%- endfor -%}
{{ total }}
7. Use Object Type for Arrays
When you need to send arrays to Bloomreach, always use the object type and build valid JSON arrays:
[
{% for item in collection %}
{{ item | json }}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
8. Consider Performance
Complex Liquid templates run for every product during sync. Keep performance in mind:
- Avoid deeply nested loops when possible
- Cache values in variables if used multiple times
- Use efficient Liquid patterns
Troubleshooting
Mapping Not Syncing
- Check that the mapping is saved correctly
- Verify the Liquid syntax is valid using Preview
- Check sync logs for errors
- Ensure the Bloomreach target is not a reserved word
Invalid JSON in Bloomreach
- Use Preview to inspect the Bloomreach tab
- Verify all type filters are applied correctly
- Check for missing commas or brackets in object types
- Validate JSON schema if using object type with schema
Translation Not Working
- Ensure locale is configured in shop settings
- Verify translation data exists for the locale
- Check that field path is correct (e.g.,
"product.title"notproduct.title) - Test with different locales in Preview
Missing Data
- Verify the Shopify field exists using the Shopify tab in Preview
- Check for null/undefined values
- Ensure filters are handling missing data gracefully
- Review conditional logic in Liquid templates
Additional Resources
- Liquid Filters - Complete reference for custom filters
- Getting Started - Initial setup and configuration
- Bloomreach Reserved Words - Fields to avoid
Need help? Contact support@tapestry-stitch.com