# Membership Cart Drawer Upsell with Dynamically Calculated Cashback: Implementation Guide

{% hint style="danger" %}
This is an advanced theme customization meant for developers that not is supported by the Inveterate team. You should ensure you have the appropriate development resources to implement before proceeding.&#x20;

Functionality can vary theme-by-theme and some small adjustments may be required.&#x20;
{% endhint %}

### File Structure

| File                              | Purpose                                         |
| --------------------------------- | ----------------------------------------------- |
| snippets/membership-upsell.liquid | Renders the upsell block inside the cart drawer |
| assets/membership-upsell.js       | Handles AJAX add-to-cart and drawer refresh     |

### Step 1: Create the Snippet

In the Snippets folder of your theme, create a new file called `membership-upsell.liquid`&#x20;

Then, paste the following code:

```liquid
{%- comment -%}
Adjust this percentage to reflect your actual cashback offer.
{%- endcomment -%}
{% assign cashback_percentage = 20 %}
{% assign cashback_amount = cart.total_price | times: cashback_percentage | divided_by: 100 %}

<div class="drawer-membership-upsell">
  <h3 class="drawer-upsell-heading">Become a Member</h3>
  <p class="drawer-upsell-subheading">Join now to unlock your benefits</p>

  <ul class="drawer-benefits">
    {%- comment -%}
    Customize the list of membership benefits below to reflect your actual offering.
    These items are placeholder examples — replace them with your own benefits.
    {%- endcomment -%}
    <li>
      <strong>{{ cashback_percentage }}% Cashback</strong>
      {% if cart.item_count > 0 %}
        <span class="drawer-cashback-amount">
          ({{ cashback_amount | money }} on today's order!)
        </span>
      {% endif %}
    </li>
    <li>Free Shipping</li>
    <li>Exclusive Product Access</li>
    <li>Member-Only Discounts</li>
    <li>$10 Birthday Credit</li>
    <li>Priority Support</li>
  </ul>

  <button
    class="drawer-upsell-button"
    data-membership-variant="REPLACE_WITH_VARIANT_ID"  <!-- Replace with your membership product's variant ID -->
    data-membership-selling-plan="REPLACE_WITH_SELLING_PLAN_ID">  <!-- Replace with your selling plan ID -->
    Join Now for $10 Annually!  <!-- Replace with your price & CTA -->
  </button>
</div>

{%- comment -%}
Ensure this script is included so the JS functionality is loaded when the snippet renders.
{%- endcomment -%}
<script type="module" src="{{ 'membership-upsell.js' | asset_url }}"></script>


```

{% hint style="warning" %}
Ensure that you replace all of the placeholder content in the code snippet *(Cashback %, Benefits, Variant ID, Selling Plan ID, Price and CTA)* with those that are relevant & specific to your program.
{% endhint %}

### Step 2: Create the JavaScript File

In the assets folder of your theme, create a new file called `membership-upsell.js`

Then, paste the following code:

```javascript
document.addEventListener('click', async (event) => {
  const btn = event.target.closest('.drawer-upsell-button');
  if (!btn || btn.disabled) return;

  const variantId = parseInt(btn.dataset.membershipVariant);
  const sellingPlanId = parseInt(btn.dataset.membershipSellingPlan);

  const payload = {
    items: [{
      id: variantId,
      quantity: 1
    }]
  };

  if (!isNaN(sellingPlanId)) {
    payload.items[0].selling_plan = sellingPlanId;
  }

  btn.disabled = true;
  const originalText = btn.textContent;
  btn.textContent = 'Adding...';

  try {
    const res = await fetch('/cart/add.js', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json'
      },
      body: JSON.stringify(payload)
    });

    if (!res.ok) throw new Error('Cart add failed');

    const cart = await fetch('/cart.js').then(r => r.json());
    const exists = cart.items.find(item => item.variant_id === variantId);
    if (!exists) throw new Error('Membership not found in cart');

    btn.textContent = 'Added!';
    const upsell = btn.closest('.drawer-membership-upsell');
    if (upsell) setTimeout(() => upsell.remove(), 400);

    const drawerRes = await fetch(window.location.pathname + '?sections=cart-drawer');
    const html = await drawerRes.text();
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');
    const newDrawer = doc.querySelector('.cart-drawer');
    const currentDrawer = document.querySelector('.cart-drawer');
    if (newDrawer && currentDrawer) {
      currentDrawer.innerHTML = newDrawer.innerHTML;
    }

  } catch (err) {
    console.error('[Membership Upsell Error]', err);
    btn.textContent = 'Error';
    alert('Could not add membership.');
  }

  setTimeout(() => {
    btn.textContent = originalText;
    btn.disabled = false;
  }, 2000);
});

```

### Step 3: Add the Snippet to the Cart Drawer

In your theme’s code editor open the file: `snippets/cart-drawer.liquid`

Find this section of the code:

```liquid
<scroll-hint class="cart-drawer__items">
  {% render 'cart-products' %}
</scroll-hint>

<div class="cart-drawer__summary">
  {% render 'cart-summary' %}
</div>
```

{% hint style="warning" %}
The exact location of the cart summary block can vary slightly theme by theme.&#x20;
{% endhint %}

Insert the upsell snippet **above** the cart summary block, like so:

<pre class="language-liquid"><code class="lang-liquid">&#x3C;scroll-hint class="cart-drawer__items">
  {% render 'cart-products' %}
&#x3C;/scroll-hint>

<a data-footnote-ref href="#user-content-fn-1">{% render 'membership-upsell' %}</a>

&#x3C;div class="cart-drawer__summary">
  {% render 'cart-summary' %}
&#x3C;/div>
</code></pre>

### Step 4: Style with CSS

Add this to your main stylesheet (theme.css, base.css, or equivalent), or inline within the snippet, and customize to your branding needs. All current values are placeholders and should be replaced to match your branding needs:

```css
.drawer-membership-upsell {
  background: #f5f0ff;
  padding: 16px;
  margin: 16px 0;
  border-radius: 6px;
  font-size: 14px;
}

.drawer-upsell-heading {
  font-size: 16px;
  font-weight: 600;
}

.drawer-upsell-subheading {
  font-size: 13px;
  margin-bottom: 10px;
  color: #666;
}

.drawer-benefits {
  list-style: none;
  padding: 0;
  margin: 0 0 12px;
}

.drawer-upsell-button {
  width: 100%;
  background: #7b3fdb;
  color: white;
  padding: 10px 0;
  border-radius: 4px;
  font-weight: 600;
  border: none;
  cursor: pointer;
}

.drawer-upsell-button:hover {
  background: #5f2bbb;
}

.drawer-cashback-amount {
  font-weight: 600;
  color: #7b3fdb;
  margin-left: 4px;
}
```

Once all of the above is implemented & styled, your cart upsell will appear in the cart drawer - visually looking similar to this - but matching the CSS styling that you have adjusted to match your needs:

<figure><img src="https://231758148-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FLjNbd2MWKOWi5A1HvQtH%2Fuploads%2FDrvfefFIRZI5gGO45hxY%2FScreenshot%202025-06-20%20at%203.29.27%E2%80%AFPM.png?alt=media&#x26;token=4ec23da9-7c46-4c7f-b0dd-77f55ea78b71" alt=""><figcaption></figcaption></figure>

Functionally, the cart upsell will automatically calculate the cashback amount based on your cart total & the percentage you have defined in the snippet *(note: this implementation assumes that you provide credits for orders/cashback on all products).* The cart upsell will be present if a membership product has not been added to cart. If the membership product has been added to cart, the upsell will no longer be visible.&#x20;

[^1]: The snippet added directly above the cart summary
