Putting Wunder details on your Shopify emails
Get the gift message, the buyer's details and the delivery date onto your Shopify order confirmations — with the Liquid to paste and the four things that silently return nothing.
You want your order confirmation email to show the gift message, or the buyer’s own name, or the delivery date. All of that is on the order — so it should be a matter of dropping in a variable.
It is, but not the variable you are expecting.
{{ gift_message }}, {{ buyer_name }} and the rest exist only inside Wunder Delivery's own print templates. Shopify's notification templates are rendered by Shopify, which has never heard of them, so pasting one produces nothing at all — no error, just a blank space.
What you do instead is read the same underlying value that Wunder reads. Every one of those variables is a shortcut to something stored on the Shopify order, and Shopify's own Liquid can reach it.
Where to edit
In your Shopify admin: Settings → Notifications → Customer notifications, then pick the email — usually Order confirmation. Edit the code, and use Preview and Send test before you save anything your customers will see.
The four things that silently return nothing
Read these first. Each one produces a blank rather than an error, so you will not be told you got it wrong.
attributes.Buyer-First-Name looks reasonable and returns nothing — Liquid reads the hyphens as minus signs and tries to do arithmetic.
Always write attributes["Buyer-First-Name"].
The per-product message is stored under a property whose name uses full-width brackets — 【 and 】, not the ASCII [ and ] on your keyboard.
Copy the key from this page rather than retyping it. A normal square bracket will never match, and the result is a blank.
The AI note, the AI-checked address and edited card messages are stored as order metafields. Shopify will not output an undefined metafield in an email template — it returns blank.
Create them under Settings → Custom data → Orders, namespace wunder:
ai_note— multi-line textai_address— multi-line textcard_messages— JSON
Order confirmation, shipping confirmation, order edited and similar all have it. Customer-account and abandoned-checkout templates do not, so none of this works there.
What maps to what
| What you want | Where it lives on the order | Shopify Liquid |
|---|---|---|
| Buyer’s first name | Attribute Buyer-First-Name |
attributes["Buyer-First-Name"] |
| Buyer’s last name | Attribute Buyer-Last-Name |
attributes["Buyer-Last-Name"] |
| Buyer’s phone | Attribute Buyer-Phone |
attributes["Buyer-Phone"] |
| Gift message for the order | Attribute Gift-Message |
attributes["Gift-Message"] |
| Message on one product | Line-item property 【Card message】 |
Loop the line items — see below |
| Delivery date and time | Whatever your delivery app writes | attributes["Delivery-Date"] |
| AI note | Metafield wunder.ai_note |
order.metafields.wunder.ai_note.value |
| AI-checked address | Metafield wunder.ai_address |
order.metafields.wunder.ai_address.value |
Two more worth knowing about:
delivery_statusis a placeholder in the app — it is hard-coded to an empty string and prints blank even on your dispatch sheets. Use Shopify’s own{{ fulfillment_status }}.- The QR code variables point at your Shopify admin and at the driver portal. They are staff and driver links. Do not put either in a customer email.
Gift message and item list
This handles both places a per-product message can live: an edit your team made after checkout wins, and the original checkout property is the fallback.
{% assign gift = attributes["Gift-Message"] %}
{% if gift != blank %}<p><strong>Gift message:</strong> {{ gift }}</p>{% endif %}
<table width="100%" cellpadding="6" cellspacing="0">
{% for line in line_items %}
{% assign lk = "gid://shopify/LineItem/" | append: line.id %}
{% assign edited = order.metafields.wunder.card_messages.value[lk] %}
{% assign msg = edited | default: line.properties["【Card message】"] %}
<tr>
<td>{{ line.quantity }} × {{ line.title }}
{% if msg != blank %}<br><em>{{ msg | newline_to_br }}</em>{% endif %}
</td>
<td align="right">{{ line.final_line_price | money }}</td>
</tr>
{% endfor %}
</table>
final_line_price, not price
line.price is the price before discounts. On a discounted order it will not match what the customer paid, which is the sort of thing that generates an email back.
The buyer’s own details
With fallbacks for orders placed before the field names were tidied up.
{% assign bf = attributes["Buyer-First-Name"] | default: attributes["Buyer first name"] %}
{% assign bl = attributes["Buyer-Last-Name"] | default: attributes["Buyer last name"] %}
{% assign bp = attributes["Buyer-Phone"] | default: attributes["Buyer phone"] %}
{% if bf != blank or bl != blank %}
<p><strong>Ordered by:</strong> {{ bf }} {{ bl }}{% if bp != blank %} · {{ bp }}{% endif %}</p>
{% endif %}
Orders placed before the rename use "Buyer first name", "Buyer phone", "Gift message" and "Card message" — with spaces instead of hyphens.
If you only ever email on new orders this does not matter. If you resend confirmations on historical orders, chain a | default: fallback as above, or old orders will quietly show nothing.
On current orders Buyer-Phone includes the + code. Older orders kept it separately in Buyer-Phone-Country.
Delivery or collection, with the date
This mirrors how the app decides between the two headings.
{% if attributes["Checkout-Method"] == "pickup" %}
<h3>PICKUP</h3>
<p>{{ attributes["Pickup-Location-Company"] }}<br>
{{ attributes["Pickup-Location-Address-Line-1"] }}, {{ attributes["Pickup-Location-Address-City"] }}</p>
{% else %}
<h3>DELIVERY</h3>
<p>{{ shipping_address | format_address }}</p>
{% endif %}
<p>{{ attributes["Delivery-Date"] }} {{ attributes["Delivery-Time"] }}</p>
Delivery-Date and the pickup fields are Zapiet's names. If you use a different app, check a real order's Additional details and substitute yours — the same names you used when setting up the integration mapping.
The AI note and checked address
Only useful once the metafield definitions above exist.
{% assign checked = order.metafields.wunder.ai_address.value %}
{% assign note = order.metafields.wunder.ai_note.value %}
{% if checked != blank %}<p><strong>Address:</strong> {{ checked | newline_to_br }}</p>{% endif %}
{% if note != blank %}<p><strong>Note:</strong> {{ note | newline_to_br }}</p>{% endif %}
The AI note is written for whoever is packing or delivering. It can say an address looks incomplete, or that the delivery fee does not match the destination. That is operational information, and it usually reads oddly in a customer's inbox.
These are worth adding to a staff-facing notification. Be deliberate about a customer-facing one.
Before you save
- Use Preview on the notification template.
- Use Send test to your own address.
- Then test against a real order that actually has the data — a preview uses sample data, and sample data has no Wunder attributes on it, so everything you just added will look blank whether or not it works.
That last point catches almost everyone.
Next
Still stuck? Ask us about this page and we will answer directly.