Set up Abandoned Checkout and Cart Emails

Set up Abandoned Checkout and Cart Emails

Overview

Shopify’s default abandoned checkout button usually points at a checkout or cart permalink. That can drop Appify CPO options. This article adds:

  • The customer’s visible options under each product, when the editor can print line-item properties
  • A whole-cart Restore your cart link that rebuilds customized products and other products together

There are three ways to send the recover link. Use the one this shop actually sends:

  1. Customer notification emailsSettings → Notifications → Abandoned checkout → Edit code. Paste Liquid or use Update with AI on the Appify CPO dashboard.
  2. Marketing AutomationsApps → Messaging → Automations. Automation Recover abandoned checkout, message Complete your order. This is a visual customizer. There is no Edit code for the whole email.
  3. Klaviyo or another email tool — change that app’s abandoned-cart button so it uses Appify’s restore link. Choose Klaviyo / 3rd-party email on the dashboard for the link to copy.

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.

What the customer sees

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.

Snippets to paste

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 %}"

Method 1 — Customer notification emails

Use this when Edit code is still available on Abandoned checkout.

Step 1: Open the template

  1. In Shopify admin go to Settings → Notifications.
  2. Open Abandoned checkout (and later Abandoned cart if it is listed).
  3. Click Edit code.
  4. Place the cursor in the Email body (HTML) editor and press Ctrl + F (Windows) or Command + F (Mac).

On an unmodified Shopify default template, make the replacements below. If your template differs, run the same searches.

Replacement 1 — primary button URL

  1. Search for href="{{ url }}".
  2. On an unmodified template this is the Items in your cart or Complete your purchase button.
  3. Replace {{ url }} with:
{% if checkout.attributes._recover != blank %}{{ shop.url }}/apps/calculator-ai/recover?id={{ checkout.attributes._recover }}{% else %}{{ url }}{% endif %}
  1. Put <!-- 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.

Replacement 2 — first product title in the line-item loop

  1. Search for {% for line in subtotal_line_items %}. If that is missing, search for {% for line in line_items %}.
  2. Inside that loop, search for {{ line_title }} or order-list__item-title.
  3. On an unmodified template the title looks like:
<span class="order-list__item-title">{{ line_title }}&nbsp;&times;&nbsp;{{ line_display }}</span><br/>
  1. Paste the Custom options snippet on the next line after that title.

Replacement 3 — parent titles only

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.

Replacement 4 — hide the expanded child row

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.

Step 3: Save

  1. Click Save.
  2. Repeat these replacements on Abandoned cart if that template exists.
  3. Wait about 30 seconds.

If _recover is blank (the cart never went through the Online Store theme, or Buy Now), the button keeps Shopify’s default URL.

Method 2 — Marketing Automations

Use this when the shop upgraded to Shopify Messaging.

  1. Open Apps → Messaging → Automations.
  2. Open Recover abandoned checkout, then open the Complete your order email and edit that message. The changes below go in that email, not in the automation settings.
  3. Select the Abandoned checkout section and hide the button for Complete your order. Do not add a Custom Liquid product list — that would duplicate the items.
  4. Add section → Custom → Custom Liquid. Paste the restore-button snippet from the Appify CPO dashboard (Abandoned checkout / cart email → Marketing Automations). The button label is Complete Your Order. The preview should show that button immediately (it falls back to the shop URL until _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.

Faster setup in Appify CPO

On the dashboard setup card, choose Abandoned checkout / cart email or Klaviyo / 3rd-party email.

  • Customer notification emails — open the Shopify editor, copy the Email body (HTML), paste it into Update with AI, then copy the result back into Shopify and save.
  • Marketing Automations — hide the built-in button, then add a Custom Liquid section with the Complete your order snippet.
  • Klaviyo / 3rd-party email — copy the start of the restore link (or the ready-made Klaviyo button link) and paste it as the button URL in that app.

Mark the email complete when you are done.

Completed example

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 }}&nbsp;&times;&nbsp;{{ 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>

Klaviyo and other email tools

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.

If you use Klaviyo

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.

If you use a different email app

  1. Copy the start of the link from the dashboard.
  2. Paste it as the button URL.
  3. Add the cart field named _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.

Limits

  • Product-page Shop Pay / Buy Now that never builds a theme cart will not get _recover.
  • There is no line-count cap. Large carts restore one line at a time in the browser.