Shopify’s default abandoned checkout button usually points at a checkout or cart permalink. That can drop Appify CPO options. This article adds:
There are three ways to send the recover link. Use the one this shop actually sends:
If Abandoned checkout in Notifications is marked Read only and tells you to visit Marketing Automations, use method 2. If Shopify is not sending the email at all, use method 3.
Search for APPIFY CPO PROPERTIES or APPIFY CPO RECOVER later if you need to find or remove a notification-email block.
Do not use a per-line Reorder link as the main button. Recover restores the entire cart. Fee and shipping-weight rows are recreated from the product.
Each customized product lists the options they chose. Names that start with _ stay hidden.
Restore your cart opens https://your-store.com/apps/calculator-ai/recover?id=… with your theme header and footer. They see “Restoring your cart…” (and “12 of 50…” on large carts). The current cart in that browser is cleared, then the abandoned lines are added. They land on /cart, not checkout.
If one product’s calculator changed, clean lines are added first; that line waits for a review banner.
Custom options — paste under each product title in the line-item loop.
<!-- APPIFY CPO PROPERTIES -->
{% for property in line.properties %}
{% assign property_first_char = property.first | slice: 0 %}
{% if property.last != blank and property_first_char != '_' %}
<span class="order-list__item-property">
• {{ property.first }}: {{ property.last }}
</span>
{% endif %}
{% endfor %}
<style>
td.order-list__image-cell {
display: flex;
}
span.order-list__item-property {
display: block;
height: max-content;
margin-top: 5px;
padding-left: 1.5em;
}
</style>
<!-- APPIFY CPO END PROPERTIES -->
Restore your cart — use this as the primary button URL.
<!-- APPIFY CPO RECOVER -->
{% if checkout.attributes._recover != blank %}
<a href="{{ shop.url }}/apps/calculator-ai/recover?id={{ checkout.attributes._recover }}">Restore your cart</a>
{% endif %}
<!-- APPIFY CPO END RECOVER -->
To keep Shopify’s original checkout link when _recover is blank, replace only the href value:
href="{% if checkout.attributes._recover != blank %}{{ shop.url }}/apps/calculator-ai/recover?id={{ checkout.attributes._recover }}{% else %}{{ url }}{% endif %}"
Use this when Edit code is still available on Abandoned checkout.
On an unmodified Shopify default template, make the replacements below. If your template differs, run the same searches.
href="{{ url }}".{{ url }} with:{% if checkout.attributes._recover != blank %}{{ shop.url }}/apps/calculator-ai/recover?id={{ checkout.attributes._recover }}{% else %}{{ url }}{% endif %}
<!-- APPIFY CPO RECOVER --> on the line before that <a tag and <!-- APPIFY CPO END RECOVER --> on the line after the closing </a>.If you also have a second href="{{ url }}" (a fallback “Complete your purchase” link), make the same href change there.
{% for line in subtotal_line_items %}. If that is missing, search for {% for line in line_items %}.{{ line_title }} or order-list__item-title.<span class="order-list__item-title">{{ line_title }} × {{ line_display }}</span><br/>
Some templates print the line items twice (a short list near the button and a full list below). Paste options only after {{ line_title }} × {{ line_display }}.
Do not paste options after an expanded child title such as {{ item_display }} × {{ item_title }}. That row is Cart Transform’s duplicate of the same product.
If the title uses component instead of line, change line.properties to component.properties in that paste.
Search for {% for child_line in line.bundle_components %} and {% for child_line in line.nested_lines %}. Replace each of those opening tags with:
{% comment %}APPIFY CPO HIDE EXPAND{% endcomment %}{% assign appify_cpo_hide_expand = nil %}{% for child_line in appify_cpo_hide_expand %}
Leave the matching {% endfor %} in place. The parent line still shows the product and options.
If _recover is blank (the cart never went through the Online Store theme, or Buy Now), the button keeps Shopify’s default URL.
Use this when the shop upgraded to Shopify Messaging.
_recover or the abandoned checkout URL is available). Do not add a regular Button section — that URL field cannot use Liquid.The recover URL is per checkout (_recover). You cannot hard-code one store-wide link. This editor cannot show Appify options under each product.
On the dashboard setup card, choose Abandoned checkout / cart email or Klaviyo / 3rd-party email.
Mark the email complete when you are done.
This is a full abandoned checkout email after both snippets are added.
{% capture email_title %}
{% if item_count == 1 %}
You left an item in your cart
{% else %}
You left items in your cart
{% endif %}
{% endcapture %}
{% capture email_body %}
{% if billing_address.first_name %}
Hi {{ billing_address.first_name }}, you added items to your shopping cart and haven't completed your purchase.
{% else %}
Hi, you added items to your shopping cart and haven't completed your purchase.
{% endif %}
{% endcapture %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ email_title }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="/assets/notifications/styles.css">
<style>
.button__cell { background: {{ shop.email_accent_color }}; }
a, a:hover, a:active, a:visited { color: {{ shop.email_accent_color }}; }
</style>
</head>
<body>
<table class="body">
<tr>
<td>
<table class="header row">
<tr>
<td class="header__cell">
<center>
<table class="container">
<tr>
<td>
<table class="row">
<tr>
<td class="shop-name__cell">
{%- if shop.email_logo_url %}
<img src="{{shop.email_logo_url}}" alt="{{ shop.name }}" width="{{ shop.email_logo_width }}">
{%- else %}
<h1 class="shop-name__text">
<a href="{{shop.url}}">{{ shop.name }}</a>
</h1>
{%- endif %}
</td>
</tr>
</table>
</td>
</tr>
</table>
</center>
</td>
</tr>
</table>
<table class="row content">
<tr>
<td class="content__cell">
<center>
<table class="container">
<tr>
<td>
<h2>{{ email_title }}</h2>
{% if custom_message != blank %}
<p>{{ custom_message }}</p>
{% else %}
<p>{{ email_body }}</p>
{% endif %}
<table class="row actions">
<tr>
<td class="actions__cell">
<table class="button main-action-cell">
<tr>
<td class="button__cell">
<!-- APPIFY CPO RECOVER -->
<a href="{% if checkout.attributes._recover != blank %}{{ shop.url }}/apps/calculator-ai/recover?id={{ checkout.attributes._recover }}{% else %}{{ url }}{% endif %}" class="button__text">Restore your cart</a>
<!-- APPIFY CPO END RECOVER -->
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</center>
</td>
</tr>
</table>
<table class="row section">
<tr>
<td class="section__cell">
<center>
<table class="container">
<tr>
<td>
<h3>Items in your cart</h3>
</td>
</tr>
</table>
<table class="container">
<tr>
<td>
<table class="row">
{% for line in subtotal_line_items %}
{% if line.product.title %}
{% assign line_title = line.product.title %}
{% else %}
{% assign line_title = line.title %}
{% endif %}
{% assign line_display = line.quantity %}
<tr class="order-list__item">
<td class="order-list__item__cell">
<table>
<tr>
<td>
<span class="order-list__item-title">{{ line_title }} × {{ line_display }}</span><br/>
<!-- APPIFY CPO PROPERTIES -->
{% for property in line.properties %}
{% assign property_first_char = property.first | slice: 0 %}
{% if property.last != blank and property_first_char != '_' %}
<span class="order-list__item-property">
• {{ property.first }}: {{ property.last }}
</span>
{% endif %}
{% endfor %}
<style>
td.order-list__image-cell {
display: flex;
}
span.order-list__item-property {
display: block;
height: max-content;
margin-top: 5px;
padding-left: 1.5em;
}
</style>
<!-- APPIFY CPO END PROPERTIES -->
{% if line.variant.title != 'Default Title' %}
<span class="order-list__item-variant">{{ line.variant.title }}</span>
{% endif %}
</td>
</tr>
</table>
</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
</table>
</center>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
Appify does not install Klaviyo or any other email app. You only change that app’s abandoned-cart button so it opens Appify’s restore page.
On the dashboard, choose Klaviyo / 3rd-party email.
A finished link looks like this (the ID at the end is only an example):
https://your-store.com/apps/calculator-ai/recover?id=r_abc123
Every restore link starts the same way, then adds that cart’s recover ID. Appify saves the ID on the cart as _recover.
Open your abandoned cart email, click the button, and paste the Klaviyo button link from the dashboard. You do not need to build the URL yourself.
_recover at the end.Each app has its own way to insert a Shopify cart field — check that app’s help. Do not paste the Klaviyo link into another app.
The Appify embed in your theme must be on, or carts will not get a recover ID. Do not use a cart permalink such as /cart/123:1 — that drops the customer’s options.
_recover.