A Centra fashion storefront can take the order and still leave the shopper's inbox empty. I wired receipts, shipping updates, and back-in-stock through the Klaviyo plugin that already ships the catalog and the events into Klaviyo. One tag a character off and Klaviyo did not error. It just never entered the flow.
That silence is the whole bug. An order sits in Centra while the inbox stays empty, and a back-in-stock email can still go out with a blank product block. The flow looks live in the UI. The metric dropdown does not list the name I invented in Slack, so nobody gets mail and nobody gets a red banner either.
A live flow that never sends mail
Klaviyo will happily host a flow that never starts. I picked a metric, designed the email, hit live. The metric was a name I made up, so I had built a second event that nothing in Centra will ever emit.
I wanted order_placed because that is how I name things. Snake case. Engineer brain. The plugin does not care. Close enough is a different metric, and a different metric is a flow that waits forever.
The plugin already did the hard part. Centra holds products and orders. The plugin ships both the catalog and the events. My job is to match the list.
Copy the plugin list, including resends
The Centra Klaviyo plugin sends Placed Order. Same for Confirmed Order, Shipping Update, Cancelled Order, Refunded Order, Created Account, Reset Password, and Ordered Product. Those strings are the contract. I did not get to rename them for taste.
Resends are not aliases. They are Placed Order - resend. Point a flow at Placed Order and then resend from Centra, and you are listening to the wrong metric again. The suffix is part of the name. Drop it and you are back to a live flow that never starts.
The plugin docs are rude about this, in a useful way: when you create a flow, tags need to match the list. I stopped arguing with the docs. I copied the names into the metric picker the way they appear, spaces and capitals included.
That is the first half of the contract. Events fire and mail can send. Then the product block in the email still has to find a catalog row.
Catalog lookup uses the display-item id
Catalog lookup is the second half of the same contract. The top-level catalog product id is the Centra display-item id. That is what Placed Order and Ordered Product put on the line items. Feed that id to the catalog tag and you get a title and an image. Invent a prettier key and you get a hole.
Back-in-stock is meaner. It hands you a compound VariantID like 12366_SE_00_23400. It looks like the lookup key, and it is not. Feed the whole string to {% catalog %} and Klaviyo looks up a product that does not exist. The shopper gets a restock email with a blank product block, which is a special kind of useless.
I split on _ and took the first part. That is the display-item id again. Same contract as the order events, wearing a longer costume.
{% with idParts=event.VariantId|split:"_" %}
{% catalog idParts.0 %}
<p>The {{ catalog_item.title }} is back.</p>
{% endcatalog %}
{% endwith %}The split is the contract. It maps the plugin's variant id back to the same display-item row the order events already used.
Language lookup is not default
Prices and names in the catalog metadata are keyed by currency and language. lookup:"default" is not Dutch. If the shopper is shopping in Dutch and I render the default bag, I have the right product and the wrong copy.
lookup:customer_lang is Dutch, if Centra synced Language onto the profile. That "if" is load-bearing. No Language on the profile, and the customer-lang lookup has nothing to stand on. I sync the field, then look up. Skip the sync and you are back to default names on a Dutch receipt.
I stopped inventing metric names and copied the plugin list. Flows started firing, and the shopper got a product image instead of a hole. The inbox finally matched the order that Centra already knew about.
A silent metric in Slack is usually a name I invented.
Happy coding! Sander