Smarter Prompts: Builder Icebreakers vs. Custom-JS Icebreakers (and when to use each)
Hi all!!
This post should tie together/wrap up a few different posts mentioning or asking questions on how to either beef up, or gain some clarity on using custom JS and embed types.
Pickaxe already includes built-in icebreakers in the chat UI that are great defaults and zero code. Occasionally users will want page-aware prompts, A/B tests, or chips that live outside the chat panel (hero, header, sticky footer). That’s where a tiny bit of custom JavaScript on top of a script embed shines.
TL;DR
- Simplest and works with an iframe? → Use Builder icebreakers.
- Personalized chips (URL/cookie/plan-aware), extra analytics, or custom placement? → Add custom JS with a script embed. When you programmatically prefill, fire
input/changeso the embed registers the text. - Combine both: keep Builder chips as defaults; layer page-aware chips with JS (see FAB/UI augmentation examples).
What’s different (quick table)
| Dimension | Builder Icebreakers (inside chat) | Custom-JS Icebreakers (page-side) |
|---|---|---|
| Where they render | Inside the Pickaxe embed | Anywhere on your page |
| Works with iframe? | Yes | No — needs script embed so parent JS can reach the DOM. |
| Events | Wired internally | You must fire input/change when prefilling; otherwise messages can register blank. |
| Personalization | Limited to bot context | Full page/URL/cookie context (e.g., window.PickaxeConfig, UTM params) |
| Analytics | Pickaxe metrics | Your GA/Segment + Pickaxe (if you auto-send) |
| A/B testing | Harder | Easy in your site code |
| Maintenance | Lowest | You own a tiny snippet |
| Host quirks | Fewer (self-contained) | Must handle site keybindings (e.g., Genially spacebar capture) |
Adapter A — Add page-aware chips that prefill the chat (script embed)
Use this when: you want chips anywhere on the page that insert a prompt (and optionally auto-send).
Requires: script embed (Inline / Flex), not iframe.
<!-- Your Pickaxe script embed --> <script src="https://studio.pickaxe.co/api/embed/bundle.js" defer></script><!-- Your chips anywhere on the page –>
<ul class=“icebreakers”>
<li><button data-icebreaker=“tour”>Give me a 2-minute tour of features</button></li>
<li><button data-icebreaker=“pricing”>Which plan should I choose?</button></li>
<li><button data-icebreaker=“integrations”>Show me Zapier/Make options</button></li>
</ul><!-- Prefill logic (namespaced + proper events) –>
<script>
(() => {
if (window.PICKAXE_ICEBREAKER) return;
window.PICKAXE_ICEBREAKER = true;const MESSAGES = {
tour: ‘Give me a 2-minute tour of features.’,
pricing: ‘Based on my usage, which plan should I choose and why?’,
integrations: ‘Show me how to connect this to Zapier or Make.’
};function findTextarea() {
const root = document.querySelector(‘[data-pickaxe-embed]’);
return root && root.querySelector(‘textarea’);
}function setPrompt(text) {
const area = findTextarea();
if (!area) return false;
area.focus();
area.value = text;
// Fire the events the embed listens for (critical)
area.dispatchEvent(new Event(‘input’, { bubbles: true }));
area.dispatchEvent(new Event(‘change’, { bubbles: true }));
try { area.setSelectionRange(area.value.length, area.value.length); } catch {}
return true;
}function clickSend() {
const root = document.querySelector(‘[data-pickaxe-embed]’);
root?.querySelector(‘button[type=“submit”], button[aria-label=“Send”], [data-role=“send”]’)?.click();
}function bind() {
document.querySelectorAll(‘[data-icebreaker]’).forEach(el => {
if (el.dataset.bound === ‘1’) return;
el.dataset.bound = ‘1’;
el.addEventListener(‘click’, (e) => {
e.preventDefault();
const key = el.getAttribute(‘data-icebreaker’);
const text = MESSAGES[key] || key;
if (setPrompt(text)) {
// Optional: auto-send the message
// clickSend();
}
}, { passive: false });
});
}
bind();
new MutationObserver(bind).observe(document.body, { childList: true, subtree: true });
})();
</script>
Why the events? Community reports show that setting textarea.value alone can produce a blank message; dispatch
input/change so the app recognizes the text.
Customize: change the MESSAGES; uncomment clickSend(); to auto-send; style your chips as cards/links/etc.
For positioning ideas (e.g., text above a FAB), see the community walkthrough.
Adapter B — Track Builder icebreaker clicks with your analytics (no DOM writes)
Use this when: you keep Builder chips but want GA/Segment events on your site.
Requires: script embed (the parent page needs to observe the embed’s DOM). Iframe isolates inner DOM.
<script>
(() => {
const ROOT = '[data-pickaxe-embed]';
const mo = new MutationObserver(() => {
document.querySelectorAll(`${ROOT} [role="button"], ${ROOT} button`).forEach(btn => {
if (btn.dataset._tracked) return;
btn.dataset._tracked = '1';
btn.addEventListener('click', () => {
const text = btn.textContent?.trim() || 'icebreaker';
// GA4 example
window.gtag?.('event', 'pickaxe_icebreaker_click', { text });
// Segment example
window.analytics?.track?.('Pickaxe Icebreaker Click', { text });
});
});
});
mo.observe(document.documentElement, { subtree: true, childList: true });
})();
</script>