> ## Documentation Index
> Fetch the complete documentation index at: https://docs.selektable.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Shopify

> Integrate Selektable with your Shopify store

# Shopify integration

Integrate Selektable into your Shopify store by adding the embed script and widget button to your product template.

## Setup

### 1. Add the embed script

Add the script to your theme's `theme.liquid` file, before the closing `</body>` tag. Replace `store_xxx` with your Store ID from the Selektable dashboard:

```liquid theme={null}
<script src="https://app.selektable.com/widgets/embed.js" data-store-id="store_xxx" async></script>
```

### 2. Add the widget button

Add the following to your product template (typically `sections/main-product.liquid` or similar):

```liquid theme={null}
<button
  type="button"
  class="selektable-try-on"
  id="selektable-btn"
  data-product-id="{{ product.selected_or_first_available_variant.id }}"
  data-product-image="{{ product.selected_or_first_available_variant.featured_image | default: product.featured_image | image_url: width: 1024 | prepend: 'https:' }}"
>
  View in your room
</button>

<script>
document.getElementById('selektable-btn').addEventListener('click', function() {
  var btn = this;
  Selektable.open('widget_abc123', {
    productId: btn.dataset.productId,
    productTitle: {{ product.title | json }},
    productImage: btn.dataset.productImage,
    productUrl: {{ shop.url | append: product.url | json }},
    productImages: [
      {% for image in product.images limit: 5 %}
      {
        id: {{ image.id }},
        src: {{ image.src | image_url: width: 1024 | prepend: 'https:' | json }},
        alt: {{ image.alt | json }}
      }{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ],

    // Cart integration using Shopify AJAX API
    onAddToCart: async function(product, qty) {
      const response = await fetch('/cart/add.js', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ id: product.id, quantity: qty })
      });
      return { success: response.ok };
    },

    onViewCart: function() {
      window.location.href = '/cart';
    },

    onCheckout: function() {
      window.location.href = '/checkout';
    }
  });
});
</script>
```

### 3. Handle variant changes

Update the button data when the customer selects a different variant:

```html theme={null}
<script>
document.addEventListener('variant:changed', function(e) {
  var btn = document.getElementById('selektable-btn');
  if (btn && e.detail && e.detail.variant) {
    btn.dataset.productId = e.detail.variant.id;
    if (e.detail.variant.featured_image) {
      btn.dataset.productImage = e.detail.variant.featured_image.src;
    }
  }
});
</script>
```

<Note>
  The `variant:changed` event name depends on your theme. Some themes use `variantChange` or dispatch custom events. Check your theme's JavaScript for the correct event name.
</Note>

## Order webhooks

To enable conversion tracking, set up an order webhook:

1. Go to **Settings → Notifications → Webhooks**
2. Create a webhook:
   * **Event**: Order creation
   * **URL**: `https://app.selektable.com/api/webhooks/shopify/orders`
   * **Format**: JSON

## Troubleshooting

<AccordionGroup>
  <Accordion title="Schema validation error: Invalid URL for imageUrl or productUrl">
    This happens when Shopify's Liquid filters produce incomplete URLs:

    * **`image_url`** returns protocol-relative URLs (`//cdn.shopify.com/...`). Always append `| prepend: 'https:'` after the `image_url` filter.
    * **`product.url`** returns a relative path (`/products/...`). Prepend `shop.url` to produce a full URL: `{{ shop.url | append: product.url }}`.
    * **`featured_image`** can be `nil` if a variant has no image. Use the `default` filter to fall back to the product's featured image: `product.selected_or_first_available_variant.featured_image | default: product.featured_image`.
  </Accordion>

  <Accordion title="Widget button doesn't do anything">
    Make sure the embed script has loaded before calling `Selektable.open()`. The script loads asynchronously, so if your button fires before the script is ready, `Selektable` will be `undefined`.
  </Accordion>
</AccordionGroup>

## Styling the button

Add CSS to match your theme:

```css theme={null}
.selektable-try-on {
  /* Match your theme's button styles */
  display: inline-block;
  padding: 10px 20px;
  margin-top: 10px;
  cursor: pointer;
}
```
