Skip to main content
Displays products frequently bought together with specific items using Algolia’s Recommend API.

Usage

import instantsearch from 'instantsearch.js';
import { frequentlyBoughtTogether } from 'instantsearch.js/es/widgets';

const search = instantsearch({
  indexName: 'instant_search',
  searchClient
});

search.addWidgets([
  frequentlyBoughtTogether({
    container: '#frequently-bought-together',
    objectIDs: ['product-1']
  })
]);

search.start();

Parameters

container
string | HTMLElement
required
CSS selector or HTMLElement to insert the widget.
objectIDs
string[]
required
Array of objectIDs of the items to get frequently bought together recommendations for.
limit
number
Number of recommendations to retrieve.
threshold
number
Threshold for the recommendations confidence score (between 0 and 100).
queryParameters
object
Additional search parameters to send to the Algolia API.
fallbackParameters
object
Search parameters to use when not enough recommendations are available.
escapeHTML
boolean
default:"true"
Whether to escape HTML tags from items string values.
transformItems
function
Function to transform the items before rendering.
(items: Hit[], { results: RecommendResponse }) => Hit[]
templates
object
Templates to use for the widget.
cssClasses
object
CSS classes to add to the widget elements.

Examples

Basic usage

frequentlyBoughtTogether({
  container: '#frequently-bought-together',
  objectIDs: ['product-123'],
  limit: 4,
  templates: {
    item(hit, { html, components }) {
      return html`
        <div>
          <img src="${hit.image}" alt="${hit.name}" />
          <h3>${components.Highlight({ hit, attribute: 'name' })}</h3>
          <p>$${hit.price}</p>
          <button>Add to cart</button>
        </div>
      `;
    }
  }
});

With header

frequentlyBoughtTogether({
  container: '#frequently-bought-together',
  objectIDs: ['product-123'],
  templates: {
    header() {
      return '<h2>Frequently Bought Together</h2>';
    },
    item(hit) {
      return `
        <article class="product-card">
          <img src="${hit.image}" />
          <h4>${hit.name}</h4>
          <span class="price">$${hit.price}</span>
        </article>
      `;
    }
  }
});

Bundle display

frequentlyBoughtTogether({
  container: '#bundle',
  objectIDs: ['product-123'],
  transformItems(items) {
    const total = items.reduce((sum, item) => sum + item.price, 0);
    return items.map(item => ({ ...item, bundleTotal: total }));
  },
  templates: {
    header({ items }) {
      if (items.length === 0) return '';
      const total = items[0].bundleTotal;
      return `
        <div class="bundle-header">
          <h3>Complete the Bundle</h3>
          <span class="total">Total: $${total.toFixed(2)}</span>
        </div>
      `;
    },
    item(hit) {
      return `
        <div class="bundle-item">
          <input type="checkbox" checked />
          <img src="${hit.image}" />
          <span>${hit.name}</span>
          <span>$${hit.price}</span>
        </div>
      `;
    }
  }
});

With add to cart

frequentlyBoughtTogether({
  container: '#frequently-bought-together',
  objectIDs: ['product-123'],
  templates: {
    item(hit, { html }) {
      return html`
        <div class="product">
          <img src="${hit.image}" />
          <h4>${hit.name}</h4>
          <p>$${hit.price}</p>
          <button onclick="addToCart('${hit.objectID}')">
            Add to cart
          </button>
        </div>
      `;
    }
  }
});

With empty state

frequentlyBoughtTogether({
  container: '#frequently-bought-together',
  objectIDs: ['product-123'],
  templates: {
    item(hit) {
      return `<div class="product">${hit.name}</div>`;
    },
    empty() {
      return '<p>No bundle recommendations available.</p>';
    }
  }
});

Multiple source products

frequentlyBoughtTogether({
  container: '#frequently-bought-together',
  objectIDs: ['product-123', 'product-456'],
  limit: 6,
  templates: {
    header: 'Complete Your Purchase',
    item(hit) {
      return `
        <div class="recommendation">
          <img src="${hit.image}" />
          <div>${hit.name}</div>
          <div>$${hit.price}</div>
        </div>
      `;
    }
  }
});

HTML output

<div class="ais-FrequentlyBoughtTogether">
  <ol class="ais-FrequentlyBoughtTogether-list">
    <li class="ais-FrequentlyBoughtTogether-item">
      <!-- Item template content -->
    </li>
    <!-- More items -->
  </ol>
</div>

Notes

  • Requires Algolia Recommend to be enabled on your account.
  • The widget uses the Frequently Bought Together model.
  • Perfect for product detail pages and cart pages.
  • Results are based on purchase history and co-occurrence patterns.
  • Use to increase average order value with intelligent bundling.

Build docs developers (and LLMs) love