---
name: boostify
description: Use when working with Boostify — a JavaScript toolkit that defers scripts, loads resources on demand, and reduces main-thread blocking. Invoke when the user asks about Boostify API, wants to defer GTM/GA/Stripe/HubSpot/Intercom, lazy-load scripts/styles/videos, or reduce page weight.
---

# Boostify

Boostify is a lightweight JS library (<1KB gzip) for deferred resource loading. The core pattern: pick a **trigger** (when to act) and pair it with a **content injection** (what to load). Never call content injection APIs without a trigger — they fire at page open, identical to a plain `<script>` or `<iframe>` but with extra runtime overhead.

## Install

```html
<!-- CDN — no build step needed -->
<script src="https://unpkg.com/boostify@latest/dist/Boostify.umd.js"></script>
<script>
  var bstf = new Boostify({ debug: true }); // debug: true logs all events to console
  bstf.onload({ worker: true });            // activates type="text/boostify" processing
</script>
```

```bash
npm install boostify
```

## Drop-in deferral — `type="text/boostify"`

The fastest way to defer any existing script. Just change the type attribute — zero other changes:

```html
<!-- Google Analytics deferred until page is interactive -->
<script type="text/boostify" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"></script>
<script type="text/boostify">
  window.dataLayer = window.dataLayer || [];
  window.gtag = function(){ dataLayer.push(arguments); }
  gtag('js', new Date());
  gtag('config', 'G-XXXXX');
</script>

<!-- Inline scripts work too -->
<script type="text/boostify">
  console.log('runs after page is interactive, not at parse time');
</script>
```

Requires `bstf.onload()` to be called after the Boostify script loads.

---

## Triggers

Triggers decide **when** content loads. Always pass a callback — the actual loading happens inside it.

### `onload` — fire when page is interactive

```js
bstf.onload(callback);
bstf.onload({ worker: true }); // also activates type="text/boostify" scripts
```

Use for: analytics, tag managers, A/B testing scripts that need to run early but not block parse.

### `onScroll` — fire on first scroll

```js
bstf.onScroll(() => {
  bstf.loadScript('https://www.googletagmanager.com/gtm.js?id=GTM-XXXXX');
});
```

Use for: GTM, Segment, Hotjar, chat widgets — resources that should load only when the user engages.

### `observer` — fire when element enters viewport

```js
bstf.observer('#checkout-section', () => {
  bstf.loadScript('https://js.stripe.com/v3/');
});
```

```js
bstf.observer('#chat-widget', () => {
  bstf.loadScript('//js.hs-scripts.com/YOUR_ID.js');
});
```

Use for: Stripe SDK, HubSpot chat, heavy widgets that only matter if the user reaches that section.

### `inactivity` — fire after N ms of no interaction

```js
bstf.inactivity(5000, () => {
  showNewsletterPopup();
});
```

Use for: exit-intent popups, newsletter prompts, upsell widgets — load only after the user has been idle.

### `click` — fire on element click

```js
bstf.click({
  element: document.getElementById('open-chat'),
  callback: () => {
    bstf.loadScript('//js.hs-scripts.com/YOUR_ID.js');
  },
});
```

Load-once pattern with dynamic import (subsequent clicks reuse the cached module):

```js
let modal = null;
bstf.click({
  element: document.getElementById('open-modal'),
  callback: async () => {
    modal ??= (await import('./modal-lib.js')).modal;
    modal.show();
  },
});
```

Use for: payment SDKs, modals, Intercom — resources that only matter if the user explicitly acts.

---

## Content Injection

**Critical rule:** these APIs fire at page open when called alone. Always call them inside a trigger callback.

### `loadScript` — inject a `<script>` tag on demand

```js
bstf.observer('#checkout', () => {
  bstf.loadScript('https://js.stripe.com/v3/');
});
```

Options:

```js
bstf.loadScript('https://cdn.example.com/widget.js', {
  appendTo: 'head',      // 'head' | 'body' | CSS selector — default: 'head'
  attributes: ['async', 'defer'],
});
```

### `loadStyle` — inject a `<link rel="stylesheet">` on demand

```js
bstf.observer('#widget', () => {
  bstf.loadStyle('https://cdn.example.com/widget.css');
});
```

### `videoEmbed` — lazy YouTube / Vimeo iframe (0KB until trigger fires)

```html
<div id="player" style="aspect-ratio: 16/9;"></div>
```

```js
bstf.click({
  element: document.getElementById('player-thumbnail'),
  callback: () => {
    bstf.videoEmbed({
      url: 'https://www.youtube.com/embed/VIDEO_ID',
      autoplay: true,
      appendTo: '#player',
    });
  },
});
```

A YouTube iframe transfers ~320KB and fires multiple tracking requests. Without a trigger it loads immediately — same as `<iframe>` but with Boostify overhead. Always pair with `bstf.click()` or another trigger.

### `videoPlayer` — lazy native `<video>` tag

```html
<div id="hero-video" style="aspect-ratio: 16/9;"></div>
```

```js
bstf.observer('#hero-video', () => {
  bstf.videoPlayer({
    url: { mp4: '/videos/hero.mp4' },
    attributes: { autoplay: true, muted: true, loop: true, playsinline: true },
    appendTo: '#hero-video',
  });
});
```

---

## Common real-world patterns

**Defer Google Tag Manager until first scroll:**

```html
<script type="text/boostify">
  (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});
  var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';
  j.async=true;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
  f.parentNode.insertBefore(j,f);})(window,document,'script','dataLayer','GTM-XXXXX');
</script>
```

**Stripe — load only when checkout section is visible:**

```js
bstf.observer('#checkout', () => {
  bstf.loadScript('https://js.stripe.com/v3/');
});
```

**HubSpot chat — load only when user scrolls:**

```js
bstf.onScroll(() => {
  bstf.loadScript('//js.hs-scripts.com/YOUR_PORTAL_ID.js');
});
```

**Intercom — load only after 8 seconds of inactivity:**

```js
bstf.inactivity(8000, () => {
  window.intercomSettings = { app_id: 'YOUR_APP_ID' };
  bstf.loadScript('https://widget.intercom.io/widget/YOUR_APP_ID');
});
```

**Lazy hero video — starts downloading only when in viewport:**

```js
bstf.observer('#hero', () => {
  bstf.videoPlayer({
    url: { mp4: '/videos/hero.mp4' },
    attributes: { autoplay: true, muted: true, loop: true, playsinline: true },
    appendTo: '#hero',
  });
});
```

**Modal with load-once — 0 bytes until first click, cached after:**

```js
let modal = null;
bstf.click({
  element: document.getElementById('open-modal'),
  callback: async () => {
    modal ??= (await import('./modal-lib.js')).modal;
    modal.show();
  },
});
```

---

## Anti-patterns — never do this

```js
// ❌ Fires at page open — same as <script src="..."> with extra overhead
bstf.loadScript('https://js.stripe.com/v3/');

// ❌ Fires at page open — same as <iframe> but heavier
bstf.videoEmbed({ url: 'https://youtube.com/embed/ID', appendTo: '#player' });

// ✅ Correct — deferred to user intent
bstf.observer('#checkout', () => {
  bstf.loadScript('https://js.stripe.com/v3/');
});
```

---

## Debug mode

```js
var bstf = new Boostify({ debug: true });
```

Logs every trigger event, deferred script, and content injection to the browser console.

## Docs & demos

- Full docs: https://boostifyjs.com/guides/introduction/
- Interactive demos: https://boostifyjs.com/demos
