Display a customer’s teeinblue personalization preview image in an Omnisend email using Shopify line-item properties.
How It Works
teeinblue saves personalization data on the Shopify order as line-item properties. Omnisend receives the full raw order data with the Shopify Placed order and Paid for order events.
You can use a Liquid loop in a Custom HTML block to find the _customization_image property and display the image in an email.
This setup uses Omnisend’s native Shopify event data. It does not require custom code outside the email, middleware, a custom event, an API relay service, or a separate paid add-on.
teeinblue adds four properties to the customized line item:
_customization_id_tib_fulfilled_sku_customization_image_tib_design_link_1
💡 This article focuses on _customization_image, which is the property used to display the customer’s personalization preview. You can also extract the other properties with the same loop-and-match method.
Before You Begin
Make sure that:
Your Shopify store is connected to Omnisend.
teeinblue is installed.
At least one personalized product is configured in teeinblue.
You can place a real Shopify test order.
Your Omnisend account has access to Automation Workflows and Custom HTML blocks.
This integration involves three platforms. Here’s what each one requires:
Platform | Requirement |
teeinblue | Any plan. Line-item properties are core functionality, available on every tier. |
Shopify | Any plan. Line-item properties are a standard Shopify feature, not tied to a specific store tier. |
Omnisend | Any plan, including Free. Automation Workflows, Custom HTML blocks, and Liquid loops are available on all Omnisend plans. |
This setup works with any teeinblue plan and any Omnisend plan, including Free.
Always use a standard Custom HTML block for teeinblue. Do not use a Dynamic Content block. Although Omnisend’s paid Dynamic Content feature supports conditional content, it does not support the Liquid loops required to iterate through event.raw.line_items and their properties.
Setup Process
Note: Your Omnisend account must be connected to Shopify for the integration to work.
Step 1. Install teeinblue on your Shopify store.
Step 2. Create a new personalized product or enable personalization for an existing product. Combine a product base, such as a T-shirt or mug, with an artwork template, or upload your own design.
Step 3. Test the connection works.
Place a test order through the personalized product’s checkout flow. Then check the contact’s activity in Omnisend. You should see a Shopify Placed order or Paid for order event.
Once done, teeinblue personalization data is included in orders placed through the personalized product. No additional data setup is required. Continue with the workflow and email setup below.
Choose Your Workflow Setup
You can add the image to a separate workflow or include it in an existing order-confirmation email.
Setup | Use it when | Trigger filters |
Separate workflow | The email should be sent only for customized orders | Add the |
Existing order-confirmation workflow | The email should handle both customized and standard orders | Do not add the customization filters |
Use a Separate Workflow For Customized Orders
Choose this setup when you want the email to send only for orders containing a teeinblue personalization image.
Go to Automation.
Select Create Workflow.
Choose Create from scratch.
Select Placed order or Paid for order as the trigger.
Set the event origin to Shopify.
Add these trigger filters:
Raw → Line Items → Properties → Name is
_customization_imageRaw → Line Items → Properties → Value exists
Add an Email action.
Open the Email Builder.
Add a Custom HTML block.
Paste the image snippet from the next section.
Enable the workflow.
The filters allow only orders with a matching customization image property to enter this workflow. The fallback version of the code is optional in this setup.
Add Image To Existing Order-Confirmation Workflow
Choose this setup when the same email should handle every order.
Open the existing Shopify order-confirmation workflow.
Use the existing Placed order or Paid for order trigger.
Do not add the
_customization_imagetrigger filters.Add the image block to the email.
Use the fallback version of the code.
Save and enable the workflow.
This setup handles different order types:
Customized products display their personalization images.
Standard products are skipped because they do not have
_customization_image.Orders without customization data display the fallback message.
This also works when an order contains both customized and non-customized products.
Display the Personalization Image
Add a Custom HTML block to the email and paste this code:
[% for li in event.raw.line_items %]
[% for prop in li.properties %]
[% if prop.name == '_customization_image' %]
<img src="[[ prop.value ]]" alt="Your customization">
[% endif %]
[% endfor %]
[% endfor %]
Use a standard Custom HTML block. You do not need the dedicated Dynamic Content Layout block.
💡 How the code works:
Omnisend receives Shopify line-item properties as an array of name and value pairs. The outer loop checks each product in the order, and the inner loop checks each property attached to that product. When the code finds _customization_image, it uses the matching value as the image URL.
Because the code checks every line item, the customized product does not need to appear first in the order.
The standard personalization tag picker does not expose these custom line-item properties. Enter the Liquid loop directly in the Custom HTML block.
Use a Clickable Image
To link the image to its source URL, use this version:
[% for li in event.raw.line_items %]
[% for prop in li.properties %]
[% if prop.name == '_customization_image' %]
<a href="[[ prop.value ]]" target="_blank" rel="noopener">
<img src="[[ prop.value ]]" alt="Your customization" style="max-width:220px;">
</a>
[% endif %]
[% endfor %]
[% endfor %]
Add a Fallback Message
Use this version when the email can be sent for orders without personalization data:
[% assign found_image = "" %]
[% for li in event.raw.line_items %]
[% for prop in li.properties %]
[% if prop.name == '_customization_image' %]
[% assign found_image = prop.value %]
[% endif %]
[% endfor %]
[% endfor %]
[% if found_image != "" %]
<img src="[[ found_image ]]" alt="Your customization">
[% else %]
<p>Thanks for your order!</p>
[% endif %]
Without a fallback, the block renders no content when the order has no customization image.
Display Another teeinblue Property
You can display the image and the design file link in the same loop:
[% for li in event.raw.line_items %]
[% for prop in li.properties %]
[% if prop.name == '_customization_image' %]
<img src="[[ prop.value ]]" alt="Your customization">
[% endif %]
[% if prop.name == '_tib_design_link_1' %]
<p>
<a href="[[ prop.value ]]">Download your print-ready design</a>
</p>
[% endif %]
[% endfor %]
[% endfor %]
You can use the same pattern to find other line-item properties by changing the value in the condition:
prop.name == 'property_name'
Multi-Item Orders
The nested loop checks every line item in the order. It does not depend on the product’s position in the cart.
This behavior was confirmed with a real order containing:
One customized teeinblue product with all four personalization properties.
One unrelated product without customization properties.
The result was:
The customized product’s image rendered correctly and only once.
The unrelated product displayed no image.
There was no data leakage between line items.
The customized product did not need to be first in the order.
Important: Do not use a hardcoded index such as event.raw.line_items[0]. The [0] reference checks only the first line item. If the customized product is not first, the image may not appear.
Combine the Image with Title, Price, and Quantity
The product title, price, quantity, and personalization image have been confirmed together in a real delivered email, including with a quantity greater than one on a single line item:
[% for li in event.raw.line_items %]
<p><strong>[[ li.title ]]</strong> – qty [[ li.quantity ]] × [[ li.price ]] [[ order.currency ]]</p>
[% for prop in li.properties %]
[% if prop.name == '_customization_image' %]
<img src="[[ prop.value ]]" alt="[[ li.title ]]">
[% endif %]
[% endfor %]
[% endfor %]
Verified Scope
Image-only loop: verified.
Multi-item orders: verified.
Image with product title and price: verified.
Image with product title, price, and quantity: verified.
Verify the Integration
Use a real Shopify checkout to test the setup.
Place an order with a customized teeinblue product.
Check the Contact’s event history in Omnisend.
Confirm that the event contains populated
line_items[].propertiesdata.Check the delivered email.
Confirm that the image loads correctly.
Test an order with multiple line items.
If using a shared order-confirmation workflow, test an order without customization data.
Dynamic Preview and delivered emails can produce different results. Use a real delivered email as the final verification.
You can also create a segment using this condition to confirm that the event data arrived: Raw → Line Items → Properties → Name is _customization_image
Troubleshooting
The image does not appear
Check the following:
The Shopify order contains
_customization_image.The image URL in
prop.valueis available.The code is inside a Custom HTML block.
The workflow uses a real Shopify Placed order or Paid for order event.
The email was tested with a customized product.
The code does not use a hardcoded
[0]index.The trigger filters match the workflow setup.
The customized product is not first in the order
Check whether the email uses a reference such as:
event.raw.line_items[0]
This checks only the first line item. Replace it with the nested loop from this article so that Omnisend checks every line item.
The workflow does not send
Check the workflow’s frequency limiter: Automation Workflow → Settings → Frequency
The limiter can skip repeated test sends to the same Contact. This can look like a trigger failure.
API-edited email content disappears
If you edit the email through an API while the Email Builder is open in another browser tab, autosave can overwrite your changes.
Close the editor before making API-based edits. Recheck the email content before sending a test.
A synthetic order event does not work
An API request that creates a synthetic placed order event may be accepted without an error, but still fail to process or attach to the Contact.
Use a genuine Shopify checkout to generate a usable order event.
FAQ
Do I need a custom event?
No. The setup uses the native Shopify order event received by Omnisend.
Do I need middleware or a relay service?
No. The teeinblue data is already included in the Shopify order’s line-item properties.
Should I create a separate workflow?
Create a separate workflow for when the email should be sent only for customized orders. Add the _customization_image trigger filters for that workflow.
Can I add the image to an existing order-confirmation workflow?
Yes. Do not add the customization filters if the workflow should handle all orders. Use the fallback version of the code for orders without personalization data.
Does the standard personalization picker support this property?
No. The picker does not expose custom line-item properties. Use a Custom HTML block and enter the Liquid loop manually.
Does the loop work with multiple line items?
Yes. The loop checks every line item and skips products without _customization_image.
Does the customized product need to be first in the cart?
No. The nested loop does not depend on the cart position. Avoid using a hardcoded [0] index, which checks only the first line item.
Can I use a synthetic API event for testing?
No. Use a genuine Shopify checkout to generate a usable order event.
Didn't find the answer to your question? Reach out to our support team through the in-app chat or at [email protected] – we're available 24/7.

