Skip to main content

HTML Templates as Calls To Action (Advanced)

HTML Template integrations render custom HTML inside the chat as a rich Call To Action (CTA). Use them for multi‑step wizards, quizzes, guided flows, or custom UI that moves the user to the next step. Templates can work with or without LLM parameters and do not require a data source.

Related: standard button CTAs are covered in CTA Buttons.


How it works

  • The assistant decides to call your integration based on its Description text.
  • The integration returns an HTML fragment that’s rendered in the conversation.
  • Your template can run inline JavaScript to handle events and can call ai12zBot.sendMessage() or ai12zBot.sendJSON() to continue the flow.

Quick start: Create an HTML Template CTA

  1. Go to Integrations → Custom Integrations and click Add Custom Integration.

Integrations list

  1. In the properties dialog, set when this integration should be used and how it responds:

Integration properties

  • Name and describe the scenario so the LLM knows when to call it (e.g., “help pick skis”).
  • Data Source: None (templates don’t need external data by default).
  • Handle Response: Template (HTML).
  • Optional: enable a Custom Function if you’ll post‑process JSON later.
  1. Add your HTML template and optional parameters, then Save/Publish.

Edit HTML template

  1. Test in chat by asking the triggering question. The CTA renders inline and can gather inputs or trigger follow‑ups.

Rendered CTA in chat


Example: Ski Match quiz

Minimal example showing a small quiz that displays a recommended ski and offers a follow‑up button.

<div style="font-family: Arial, sans-serif; margin: 10px;">
<h3>Find Your Perfect Skis</h3>
<form id="ski-form" autocomplete="off">
<div>
<p><strong>1. What is your skill level?</strong></p>
<label
><input type="radio" name="skill" value="Beginner" required />
Beginner</label
>
<label
><input type="radio" name="skill" value="Intermediate" />
Intermediate</label
>
<label><input type="radio" name="skill" value="Expert" /> Expert</label>
</div>

<div>
<p><strong>2. What terrain do you ski most?</strong></p>
<label
><input type="radio" name="terrain" value="Groomed" required />
Groomed</label
>
<label
><input type="radio" name="terrain" value="Powder" />
Powder/Off‑piste</label
>
<label
><input type="radio" name="terrain" value="Park" /> Terrain Park</label
>
<label
><input type="radio" name="terrain" value="Mixed" /> A bit of
everything</label
>
</div>

<button
type="button"
onclick="handleSkiFormSubmitFromButton(this)"
style="margin-top: 10px; background:#14a3b8; border:0; padding:10px 16px; color:#fff; border-radius:4px; cursor:pointer;"
>
Show My Match
</button>
</form>
<div id="ski-result" style="margin-top: 16px;"></div>
</div>
// Handle quiz submit
function handleSkiFormSubmitFromButton(button) {
const form = button.closest("form")
if (!form) return
const skill = form.querySelector('input[name="skill"]:checked')?.value
const terrain = form.querySelector('input[name="terrain"]:checked')?.value
const match = findSkiMatch(skill, terrain)

const resultDiv = form.parentNode.querySelector("#ski-result")
if (!resultDiv) return

resultDiv.innerHTML = `
<div style="display:flex;gap:12px;align-items:flex-start;border:1px solid #e5e7eb;border-radius:8px;padding:12px;max-width:620px;">
<img src="${match.image}" alt="${match.name}" style="width:160px;height:160px;object-fit:cover;border-radius:6px;" />
<div style="flex:1;">
<h4 style="margin:0 0 6px 0;">${match.name}</h4>
<p style="margin:0 0 12px 0;">${match.type}</p>
<button type="button" class="ai12zBtn" onclick="ai12zBot.sendMessage('Show me more about ${match.name}')">Show more</button>
</div>
</div>`
}

function findSkiMatch(skill, terrain) {
if (skill === "Expert" && terrain === "Powder") {
return {
name: "Faction La Machine 5",
type: "Powder skis",
image:
"https://cdn.shopify.com/s/files/1/0920/9112/1967/files/Faction-Skis-2526-La-Machine-5-Base-1x1.webp?v=1751438691",
}
}
if (terrain === "Park") {
return {
name: "Völkl Revolt 84",
type: "Freestyle skis",
image:
"https://cdn.shopify.com/s/files/1/0920/9112/1967/files/volkl_2425_revolt-84_V2410156_1.webp?v=1751439056",
}
}
return {
name: "Nordica Enforcer 94",
type: "All‑Mountain skis",
image:
"https://cdn.shopify.com/s/files/1/0920/9112/1967/files/700_253125_1081575.webp?v=1751427036",
}
}

Tips & best practices

  • Keep templates small and focused; link out for heavy content.
  • Prefer semantic HTML and accessible controls (labels, required, keyboard support).
  • Use the ai12zBtn class for consistent button styling.
  • Avoid long blocking scripts; update the DOM quickly and call ai12zBot.sendMessage() or ai12zBot.sendJSON() for follow‑ups.
  • If you do use LLM parameters, name them clearly (snake_case) and provide example values.

Troubleshooting

  • Nothing renders: ensure Handle Response is set to Template (HTML) and the integration is Published.
  • Clicks don’t work: confirm your inline handlers run in the rendered HTML context; avoid referencing elements outside the template.
  • External images/scripts blocked: use HTTPS URLs and ensure your CSP allows them.
  • Integration never triggers: adjust the Description so the LLM knows when to call it, and verify the Key Name isn’t conflicting with another tool.