Redirecting the Enroll Button to an External Cart
Replace the default checkout with your own ecommerce system
This guide documents how to redirect learners from the Thought Industries Enroll button to an external cart (e.g., your own ecommerce/cart system) on course and product detail pages.
Product View Scripts (Global Redirect)
Best for: Redirecting all Enroll buttons across the site to one external cart, with product data (ID, SKU, etc.) passed in the URL.
How It Works
Product View Scripts run when a learner views a product (course, collection, learning path, etc.). You can inject JavaScript that replaces or intercepts the Enroll button and redirects to your cart instead of opening the Thought Industries checkout modal.
DOM Timing
The platform uses Ember (SPA). The enroll section may render asynchronously after the Product View Script runs. Use polling to wait for the button to appear, or event delegation to catch clicks once the DOM is ready.
Configuration
- Go to Settings → Connections → Layout Settings (or Tracking Scripts)
- Find Product View Scripts
- Paste one of the scripts below (customize the redirect URL)
Sample Script A: Polling + Button ReplacementRecommended
More robust for Ember/SPA pages. Polls until the Enroll button exists, then replaces it with a new button that redirects to your cart. Includes empty-SKU handling for debugging.
<script nonce="{{cspNonce}}">
(function() {
var sku = '{{purchasableSku}}';
var redirectUrl = 'https://store.abc.com/cart/add?productId=' + encodeURIComponent(sku);
function poll(delay) {
delay = delay || 100;
var btn = document.querySelector('.enroll__buy button.btn--primary')
|| document.querySelector('.enroll__buy button');
if (!btn) {
setTimeout(function() { poll(delay); }, delay);
return;
}
var replacement = document.createElement('button');
replacement.type = btn.type || 'button';
replacement.className = btn.className;
if (!sku) {
replacement.style.backgroundColor = 'red';
replacement.style.color = 'white';
replacement.innerHTML = 'NO PRODUCT SKU!';
} else {
replacement.innerHTML = btn.innerHTML;
replacement.addEventListener('click', function() {
window.location.href = redirectUrl;
});
}
btn.replaceWith(replacement);
}
poll();
})();
</script>Sample Script B: Event Delegation
Alternative approach. Intercepts clicks in the capture phase. Works if the enroll section is already rendered when the script runs.
<script nonce="{{cspNonce}}">
(function() {
var cartBaseUrl = 'https://store.abc.com/cart/add';
var params = [
'sku=' + encodeURIComponent('{{purchasableSku}}'),
'id=' + encodeURIComponent('{{purchasableId}}'),
'title=' + encodeURIComponent('{{purchasableTitle}}'),
'price=' + encodeURIComponent('{{priceInCents}}')
].join('&');
var redirectUrl = cartBaseUrl + (cartBaseUrl.indexOf('?') >= 0 ? '&' : '?') + params;
function handleEnrollClick(e) {
var btn = e.target.closest('button.btn--primary');
if (!btn) return;
var enrollSection = e.target.closest('.enroll, .enroll__buy, .course__detail__sidebar');
if (!enrollSection) return;
if (btn.closest('.enroll')
&& btn.textContent.toLowerCase().indexOf('waitlist') !== -1) return;
e.preventDefault();
e.stopPropagation();
window.location.href = redirectUrl;
return false;
}
document.addEventListener('click', handleEnrollClick, true);
})();
</script>Available Substitutions
These placeholders are automatically replaced with product data when the script runs.
| Placeholder | Description | Example |
|---|---|---|
| {{purchasableId}} | Product/course ID | abc123 |
| {{purchasableSku}} | Product SKU | LINUX-101 |
| {{purchasableTitle}} | Product title | Linux Fundamentals |
| {{purchasableSlug}} | URL slug | linux-fundamentals |
| {{purchasableType}} | Type (courseGroup, learningPath, etc.) | courseGroup |
| {{priceInCents}} | Price in cents | 9900 |
| {{priceInDollars}} | Price in dollars | 99.00 |
| {{email}} | Current user email | [email protected] |
| {{userId}} | Current user ID | usr_xyz |
| {{cspNonce}} | CSP nonce for inline scripts | (required for script tag) |
Important Notes
Single product per page
Product View fires once per page load. The substitutions reflect the product being viewed. For course groups with multiple sessions, {{purchasableId}} and {{purchasableSku}} are typically the displayed/default session.
CSP compliance
Always include nonce="{{cspNonce}}" in the <script> tag if your site uses Content Security Policy.
Empty SKU
If {{purchasableSku}} is empty, Script A shows a red "NO PRODUCT SKU!" button for debugging. Ensure courses have SKUs set in Manager → Catalog → Ecommerce.
Waitlist handling
Script B excludes buttons containing "waitlist." Remove that check if you want to redirect waitlist signups as well.
Other product types
This approach works for courses, learning paths, bundles, discount groups, and pickable groups. The Enroll button appears in .enroll or .enroll__buy containers.
Add Cart Item Scripts (Alternative)
Best for: Running logic when an item is actually added to the Thought Industries cart (e.g., syncing to external system). This does not prevent the Thought Industries cart modal from opening — it runs after the user adds to cart. For redirecting instead of using the Thought Industries cart, use Product View Scripts above.
Comparison
| Approach | Per-product config | Dynamic product data | Blocks Thought Industries cart |
|---|---|---|---|
| External Purchase Link | Yes | No (static URL) | Yes |
| Product View Scripts | No (global) | Yes (substitutions) | Yes |
| Add Cart Item Scripts | No | Yes | No |
Recommendation: If you need one global redirect with product data in the URL, use Product View Scripts with Sample Script A (polling + button replacement) for best compatibility with the platform's async rendering.
Troubleshooting
| Issue | Possible Cause / Fix |
|---|---|
| Script not firing | Ensure Product View Scripts are saved and the page is a product detail page (course, learning path, bundle, etc.). |
| Button not found / runs too early | Use Script A (polling + replacement). The platform renders the enroll section asynchronously; polling waits for it. |
| Redirect not working | For Script B, ensure e.preventDefault() and e.stopPropagation() run before window.location.href, and use the capture phase (true as third argument). |
| "NO PRODUCT SKU!" appears | The product has no SKU. Set a SKU in Manager → Catalog → [Course] → Ecommerce. |
| Wrong product data | On multi-session courses, Product View data may reflect the default session. Use External Purchase Link per session or custom DOM logic. |