Shop Integration

This guide explains how to integrate the Stripe-powered shopping cart into your site.

Overview

The shop integration provides:

  • Client-side cart — localStorage-based cart with add/remove/update functionality
  • Floating cart icon — Automatically injected, shows item count badge
  • Stripe Checkout — Secure payment processing via connected Stripe account
  • Server-side validation — Product prices are verified by crawling your built site

Prerequisites

  1. Site owner must connect Stripe — See Connecting Stripe
  2. Include the cart script — Add cart.js to your pages

Quick Start

1. Include the Cart Script

Add this to your pages:

<script src="https://cdn.r2ware.dev/dash/static/v0.0.1/shop.min.js"></script>

This script:

  • Creates a floating cart icon in the bottom-right corner
  • Handles "Add to Cart" button clicks
  • Manages localStorage cart state
  • Shows toast notifications

2. Add "Add to Cart" Buttons

Add buttons with the required data attributes:

<button
  data-add-to-cart
  data-product-id="tshirt-001"
  data-name="Classic T-Shirt"
  data-price="2500">
  Add to Cart
</button>

That's it. The cart handles the rest.


Add to Cart Button

The cart script listens for clicks on any element with the data-add-to-cart attribute.

Required Data Attributes

  • data-add-to-cart — Marks the element as an add-to-cart trigger
  • data-product-id — Unique identifier for the product
  • data-name — Product display name
  • data-price — Price in cents (e.g., 2500 = $25.00)

Optional Data Attributes

  • data-currency — Three-letter currency code (default: usd)
  • data-image-url — Product image URL (shown in cart)
  • data-max-quantity — Maximum quantity per order (default: 99)
  • data-esign-template-id — E-signature template ID. When present, the cart will redirect to /checkout for agreement signing before Stripe payment.

Full Example

<button
  data-add-to-cart
  data-product-id="tshirt-001"
  data-name="Classic T-Shirt"
  data-price="2500"
  data-currency="usd"
  data-image-url="/images/tshirt.jpg"
  data-max-quantity="10">
  Add to Cart
</button>

Button States

When localStorage is unavailable (e.g., private browsing), buttons are automatically disabled and an error alert is shown.


Cart JavaScript API

The Cart object is available globally for advanced use cases.

Methods

// Get all cart items
const items = Cart.getItems();

// Add an item (quantity defaults to 1)
Cart.addItem({
  productId: 'tshirt-001',
  name: 'Classic T-Shirt',
  price: 2500,
  currency: 'usd',
  imageUrl: '/assets/images/tshirt.jpg'
}, 2);

// Update quantity (removes item if quantity <= 0)
Cart.updateQuantity('tshirt-001', 3);

// Remove item
Cart.removeItem('tshirt-001');

// Clear entire cart
Cart.clear();

// Get totals
const totals = Cart.getTotals();
// { itemCount: 3, subtotal: 7500, currency: 'usd' }

// Check if localStorage is available
if (Cart.isAvailable()) {
  // Cart functions will work
}

Events

The cart dispatches a cartUpdated event on the window whenever the cart changes:

window.addEventListener('cartUpdated', function(event) {
  console.log('Cart updated:', event.detail);
  // event.detail contains: { items: [...], updatedAt: timestamp, version: 1 }
});

Cart Page

The platform provides a built-in cart page at /app/shop/cart. Users can:

  • View cart contents
  • Adjust quantities
  • Remove items
  • Proceed to checkout

The floating cart icon links to this page automatically.

Custom Cart Page (Optional)

To build a custom cart page, use the initShoppingCart function:

<div data-init="initShoppingCart">
  <div id="cart-items"></div>
  <div id="empty-cart" style="display: none;">
    <p>Your cart is empty.</p>
  </div>
  <div id="cart-summary" style="display: none;">
    <p>Items: <span id="summary-item-count">0</span></p>
    <p>Subtotal: <span id="summary-subtotal">$0.00</span></p>
    <button id="checkout-button" class="btn btn-primary">
      Proceed to Checkout
    </button>
  </div>
</div>

Checkout Flow

  1. User clicks "Proceed to Checkout"
  2. If any cart items have an esignTemplateId, redirect to /checkout for agreement signing before proceeding to Stripe
  3. Cart items are sent to /api/shop/checkout
  4. Server validates products by crawling built site HTML
  5. Server creates Stripe Checkout Session
  6. User is redirected to Stripe's hosted checkout
  7. After payment, user returns to success/cancel page

E-Sign Before Payment

Some products may require a signed agreement before payment (e.g., a puppy purchase agreement). Add data-esign-template-id to the product's add-to-cart button:

<button
  data-add-to-cart
  data-product-id="puppy-ruby"
  data-name="Deposit — Ruby"
  data-price="50000"
  data-esign-template-id="your-template-uuid">
  Reserve with $500 Deposit
</button>

When the user clicks "Proceed to Checkout" from the cart page, the cart checks all items for e-sign template IDs. If any are found, it redirects to /checkout where the site's e-sign flow collects the signer's name and email, presents the agreement for signing, and then triggers Stripe checkout after the agreement is signed.

Success/Cancel Pages

Default pages are provided at:

  • /app/shop/checkout-success
  • /app/shop/checkout-cancel

Custom Success/Cancel Pages

Site owners can configure custom URLs in Stripe settings. Create your own pages at any URL:

<h1>Thank you for your order!</h1>
<p>We've received your payment and will process your order shortly.</p>
<a href="/products/">Continue Shopping</a>

Server-Side Validation

The platform validates products during checkout by crawling your built site. This prevents price tampering.

How it works:

  1. Checkout request includes product IDs and quantities
  2. Server crawls your site's HTML files
  3. Finds elements with matching data-product-id attributes
  4. Extracts prices from data-price attributes
  5. Validates quantities against data-max-quantity
  6. Creates Stripe session with server-side prices

Important: Product data is extracted from your built site, not from the cart request. This means:

  • Prices must be present in your HTML via data attributes
  • Products not in your built site will fail validation
  • Rebuild your site after changing product data

Troubleshooting

"Cart unavailable" error

localStorage is disabled or unavailable. Common causes:

  • Private/incognito browsing mode
  • Browser storage settings
  • Third-party cookie blocking

Checkout fails with "Product not found"

The product isn't in your built site HTML. Ensure:

  • Button has data-product-id attribute
  • Site has been rebuilt after adding/changing products

Checkout fails with "Stripe not connected"

The site owner hasn't connected their Stripe account. See Connecting Stripe.

Prices don't match

The server uses prices from your built HTML, not from the cart. Ensure:

  • data-price attribute is correct in your HTML
  • Site has been rebuilt after price changes

Cart badge not updating

Check browser console for JavaScript errors. Ensure:

  • cart.js is loaded
  • No conflicting scripts

Jekyll Example

The example site in sites/example/ includes a complete Jekyll shop implementation:

  • _products/ — Product collection files
  • _layouts/product.html — Product detail template
  • _pages/products.html — Product listing page
  • _config.yml — Collection configuration

Review these files for a working reference.