Skip to main content

Tangiblee Help Center

Self-Service Integration

Last Updated:
May 11, 2026

[[error=Please Note]] Self-Service integration is not recommended except for very specific use-cases.[[error]]

Tangiblee recommends managed integration for 95% of our clients. Through managed integration, Tangiblee runs QA and is responsible for ensuring that Tangiblee CTA and modal adhere to clients' ongoing changes and deployments. However, it is important to note that you should notify Tangiblee (success@tangiblee.com) if you have an ongoing product layout page or replatforming changes to take place that we should be aware of. If not, we will only see that change on the page after it is deployed to production and the Tangiblee CTA will not appear until we update our mapping to reflect these changes. 

What is a possible use case for Self-Service Integration? 

If you take advantage of a Progressive Web Application that is running on top of your existing e-commerce platform, then it might be advised to utilize self-service integration. However, we would recommend a conversation outlining all potential integration options with the Tangiblee engineering team. 

In the case of a Self-Service Integration, the client implements its own mapping code (tangiblee-mapper.js) and has full control of its logic.

Self-Serviced integration consists of two code blocks:

  1. Mapping Code (tangiblee-mapper.js)
  2. Tangiblee API code (tangiblee.min.js)

Tangiblee recommends to place that tag in the same place where the other Javascript tags are added to the page - it may be the end of the <head> or <body> section. If Tangiblee tags are added via Google Tag Manager (GTM) then GTM manages that automatically. 

For example, if a client needs two versions of the Snippet to support two different environments like PRD and STD, it may be done by using two separate tangiblee-mapper.js files for the PRD and STG environments.

Typical Self-Service Integration

The tangiblee-mapper.js is similar to Managed Integration Production PDP version example but now written by the client and hosted on the PDP directly instead of loading it from Tangiblee CDN.

[[info]]Only generic Tangiblee API calls are made to the Tangiblee CDN equaling one less round trip to load the mapper.js from the Tangiblee CDN.[[info]]

  1. One SKU on a PDP
  2. One active Locale
  3. No Price/Currency/ATC in-widget
  4. No Order Tracking
<script>
  (function() {
    var showTangibleeCta = function(ctaThumbs) {
      var ctaClassName = 'tangiblee-shopify-cta';
      var ctaContainer = document.getElementById('ProductThumbs');
      var cta = document.getElementsByClassName(ctaClassName)[0];

      if (cta) {
        cta.style.display = 'block';
      } else if (ctaContainer) {
        var li = document.createElement('li');
        li.className = 'grid__item small--one-third medium-up--one-third';
        
        var btn = document.createElement('button');
        btn.className = 'product-single__thumbnail ' + ctaClassName;
        btn.innerText = 'Will It Fit?';
        
        // Button Styling
        Object.assign(btn.style, {
          border: '1px solid #333',
          padding: '0',
          margin: '0',
          backgroundColor: '#fff',
          width: '76px',
          height: '76px',
          fontSize: '1.4em',
          fontWeight: 'bold',
          lineHeight: '1.1em',
          textAlign: 'center'
        });

        li.appendChild(btn);
        ctaContainer.appendChild(li);
      }
      return ctaClassName;
    };

    window.tangiblee = window.tangiblee || function() {
      (tangiblee.q = tangiblee.q || []).push(arguments);
    };

    tangiblee('domain', 'www.example.com');
    tangiblee('useCookies', true);
    tangiblee('showCTA', showTangibleeCta);
    tangiblee('startOnSKUs', ['2275915']);
  })();
</script>

<script async src="https://cdn.tangiblee.com/integration/3.1/tangiblee.min.js"></script>

Multi SKU Multi Locale Self-Service Integration

Advanced Self-Service Integration example: Advanced Self-Service Integration Sample Link.

Same as in the previous example, also in the Advanced example, the Mapping Code is written by the client and hosted on the client's PDP.

This example shows how to use Tangiblee on:

  1. Multiple SKUs on a PDP (in this case two).
  2. Multiple locales
  3. Price/Currency/ATC in-widget
  4. Order Tracking on Thank You Page
<script>
  (function() {
    // 1. CTA Injection Logic
    var showCta = function (ctaThumbs) {
      var ctaClassName = 'tangiblee-cta';
      var cta = document.getElementsByClassName(ctaClassName)[0];

      if (!cta && window.thumbsCarousel) {
        var existingThumb = document.querySelector('.thumbsCarousel img');
        var wrapper = document.createElement('div');
        
        Object.assign(wrapper.style, {
          position: 'relative',
          width: existingThumb.width + 'px',
          height: existingThumb.height + 'px'
        });

        var btn = document.createElement('button');
        btn.className = ctaClassName;
        btn.innerText = 'Will It Fit?';
        
        Object.assign(btn.style, {
          position: 'absolute',
          top: '50%',
          left: '50%',
          display: 'block',
          margin: '-38px 0 0 -38px',
          border: '1px solid #333',
          padding: '0',
          backgroundColor: '#fff',
          width: '76px',
          height: '76px',
          fontSize: '1.4em',
          fontWeight: 'bold',
          lineHeight: '1.1em',
          textAlign: 'center'
        });

        wrapper.appendChild(btn);
        window.thumbsCarousel.append(wrapper);
      }
      return ctaClassName;
    };

    // 2. CTA Removal Logic
    var hideCTA = function (activeSKU) {
      var cta = document.getElementsByClassName('tangiblee-cta')[0];
      if (cta && cta.parentNode) {
        cta.parentNode.removeChild(cta);
      }
    };

    // 3. SKU Change Listener
    var skuSelector = document.getElementsByClassName('single-option-selector')[0];
    if (skuSelector) {
      skuSelector.addEventListener('change', function () {
        var activeSku;
        var selectedValue = this.value;

        if (window.meta && meta.product && meta.product.variants) {
          for (var i = 0; i < meta.product.variants.length; i++) {
            if (meta.product.variants[i].public_title === selectedValue) {
              activeSku = meta.product.variants[i].sku;
              break;
            }
          }
        }
        if (activeSku) tangiblee('activeSKU', activeSku);
      });
    }

    // 4. Tangiblee Configuration
    window.tangiblee = window.tangiblee || function () {
      (tangiblee.q = tangiblee.q || []).push(arguments);
    };

    tangiblee('domain', 'www.tangiblee-integration.com');
    tangiblee('activeLocale', 'en-US');
    tangiblee('useCookies', true);
    tangiblee('useEnhancedEcommerce', true);
    tangiblee('showCTA', showCta);
    tangiblee('hideCTA', hideCTA);
    tangiblee('activeCurrency', '$');
    tangiblee('activeATC', '.btn-cart');

    // 5. Event Callbacks for Analytics
    tangiblee('onSKUsValidated', function (isValid) { console.log('SKUs Valid:', isValid); });
    tangiblee('onCTAFirstShown', function () { console.log('CTA shown'); });
    tangiblee('onCtaClicked', function () { console.log('CTA clicked'); });
    tangiblee('onModalOpened', function () { console.log('Modal opened'); });
    tangiblee('onIframeLoaded', function () { console.log('Iframe loaded'); });
    tangiblee('onModalClosed', function () { console.log('Modal closed'); });

    // 6. Initial State
    tangiblee('activeSKU', 'F123356');
    tangiblee('startOnSKUs', ['F123356', 'F125170']);
    tangiblee('activePrice', '350');
  })();
</script>

<script async src="https://cdn.tangiblee.com/integration/3.1/tangiblee.min.js"></script>

Related Resources