Guía de instalación e integración
The Blind Agents widget adds an AI-powered bug reporter, live webchat, and product guides to any website or app — with a single script tag or npm package.
Two widgets, one platform. Paste before </body>:
Bug reporter (report.js)
<script src="https://cdn.blindagents.com/report.js" data-api-key="YOUR_API_KEY" data-primary-color="#e11d48" data-title="Help Center" data-report-btn-text="Report an issue" data-btn-emoji="🔴" data-icon-url="" data-btn-tooltip="Report an issue" data-empty-text="No issues reported yet." data-user-whatsapp="" data-external-id="" data-position="bottom-right" data-anchor="" data-bubble-size="56" data-panel-width="" data-panel-height=""> </script>
AI chat widget (chat.js)
<script src="https://cdn.blindagents.com/chat.js" data-api-key="YOUR_API_KEY" data-agent-id="YOUR_AGENT_UUID" data-primary-color="#4f46e5" data-btn-emoji="💬" data-icon-url="" data-btn-tooltip="Chat with us" data-user-whatsapp="" data-external-id="" data-position="bottom-right" data-anchor="" data-bubble-size="56" data-panel-width="" data-panel-height="" data-font-size="14px" data-font-family="System" data-notification-sound="true"> </script>
YOUR_AGENT_UUID with your agent's ID from Agents.¿Usas otro stack? Tenemos instrucciones para cada plataforma.
Copy your API key from Settings → API Keys
Generate a key if you haven't already. It starts with ba_.
Paste the script tag before </body> in your HTML
<script src="https://cdn.blindagents.com/report.js" data-api-key="YOUR_API_KEY" data-primary-color="#e11d48" data-title="Help Center" data-report-btn-text="Report an issue" data-btn-emoji="🔴" data-icon-url="" data-btn-tooltip="Report an issue" data-empty-text="No issues reported yet." data-user-whatsapp="" data-external-id="" data-position="bottom-right" data-anchor="" data-bubble-size="56" data-panel-width="" data-panel-height=""> </script>
Done — the widget launcher appears on your site
Install the npm package
npm install @duvandroid/react-blind-agents
Add the widget to your App root
// src/App.tsx
import { BlindAgents } from '@duvandroid/react-blind-agents';
export default function App() {
return (
<BlindAgents apiKey="YOUR_API_KEY">
{/* Report widget — bug reporter */}
<BlindAgents.Report
primaryColor="#e11d48"
title="Help Center"
reportBtnText="Report an issue"
btnEmoji="🔴"
position="bottom-right"
bubbleSize={56}
/>
{/* Chat widget — AI agent */}
<BlindAgents.Chat
agentId="YOUR_AGENT_UUID"
primaryColor="#4f46e5"
position="bottom-left"
bubbleSize={56}
/>
</BlindAgents>
);
}That's it
<BlindAgentsWidget> once at the App root — it renders nothing in the DOM tree, only injects the script.Install the npm package
npm install @duvandroid/react-blind-agents
App Router — add to layout.tsx
// app/layout.tsx
import { BlindAgentsWidget } from '@duvandroid/react-blind-agents/next';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<BlindAgentsWidget
apiKey="YOUR_API_KEY"
primaryColor="#e11d48"
title="Help Center"
strategy="afterInteractive"
/>
</body>
</html>
);
}/next subpath — it uses next/script internally for correct hydration.Pages Router — add to _app.tsx
// pages/_app.tsx
import type { AppProps } from 'next/app';
import { BlindAgentsWidget } from '@duvandroid/react-blind-agents/next';
export default function App({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<BlindAgentsWidget apiKey="YOUR_API_KEY" primaryColor="#e11d48" />
</>
);
}Open your theme code editor
In your Shopify Admin → Online Store → Themes → Edit code.
Open theme.liquid
Find the file under Layout → theme.liquid.
Paste the snippet before </body>
{%- comment -%} Paste in theme.liquid before </body> {%- endcomment -%}
<script
src="https://cdn.blindagents.com/report.js"
data-api-key="YOUR_API_KEY"
data-primary-color="#e11d48"
data-title="Help Center"
data-report-btn-text="Report an issue"
data-btn-emoji="🔴"
data-btn-tooltip="Report an issue"
data-user-whatsapp="{{ customer.phone | default: '' }}">
</script>{{ customer.phone }} Liquid variable automatically passes the logged-in customer's phone number — skipping the identity verification step for authenticated shoppers.Save — the widget appears on your storefront immediately
No app install required. Works on any Shopify plan including Online Store 2.0 themes.
Open your Lovable project
Lovable generates a React/Vite app — use the npm package for the cleanest integration.
Ask Lovable to install the package
"Install @duvandroid/react-blind-agents and add a BlindAgentsWidget to App.tsx with apiKey="YOUR_API_KEY" and primaryColor="#e11d48""
Or add it manually via the code editor
<!-- Add inside index.html <body> or in a custom HTML component --> <script src="https://cdn.blindagents.com/report.js" data-api-key="YOUR_API_KEY" data-primary-color="#e11d48" data-title="Help Center" data-report-btn-text="Report an issue" data-btn-emoji="🔴"> </script>
Paste in index.html before </body>, or use the React snippet in App.tsx.
Option A — Custom Code (no-code, recommended)
Go to Settings → Custom Code
In the Wix dashboard: Settings → Custom Code → + Add Custom Code.
Paste the script tag
<script src="https://cdn.blindagents.com/report.js" data-api-key="YOUR_API_KEY" data-primary-color="#e11d48" data-title="Help Center" data-report-btn-text="Report an issue" data-btn-emoji="🔴" data-icon-url="" data-btn-tooltip="Report an issue" data-empty-text="No issues reported yet." data-user-whatsapp="" data-external-id="" data-position="bottom-right" data-anchor="" data-bubble-size="56" data-panel-width="" data-panel-height=""> </script>
Set placement to Body – end and apply to All Pages
Option B — Velo (code)
// Wix Velo — paste in Site > Add Code to Pages > Add Code to All Pages (body end)
// Or use Wix > Settings > Custom Code > Add custom code
// Option A: Custom Code panel (no-code)
// Paste the raw <script> tag in Settings → Custom Code → Body - end
// Option B: Velo (code)
import wixWindow from 'wix-window';
$w.onReady(() => {
const script = document.createElement('script');
script.src = 'https://cdn.blindagents.com/report.js';
script.setAttribute('data-api-key', 'YOUR_API_KEY');
script.setAttribute('data-primary-color', '#e11d48');
script.setAttribute('data-title', 'Help Center');
script.defer = true;
document.body.appendChild(script);
});Choose the method that fits your setup:
Open Site Settings → Custom Code
In the Webflow designer: Project Settings → Custom Code.
Paste in the Footer Code section
<!-- Webflow: Site Settings → Custom Code → Footer Code --> <script src="https://cdn.blindagents.com/report.js" data-api-key="YOUR_API_KEY" data-primary-color="#e11d48" data-title="Help Center" data-report-btn-text="Report an issue" data-btn-emoji="🔴" data-btn-tooltip="Report an issue" defer> </script>
Publish your site
Go to Settings → Advanced → Code Injection
In the Squarespace dashboard sidebar.
Paste in the Footer field
<!-- Squarespace: Settings → Advanced → Code Injection → Footer --> <script src="https://cdn.blindagents.com/report.js" data-api-key="YOUR_API_KEY" data-primary-color="#e11d48" data-title="Help Center" data-report-btn-text="Report an issue" data-btn-emoji="🔴" defer> </script>
Save — the widget loads on every page
For per-page injection, use Page Settings → Advanced → Page Header Code Injection.
Go to Ghost Admin → Settings → Code Injection
Available on all Ghost plans.
Paste in the Site Footer field
<!-- Ghost: Settings → Code Injection → Site Footer --> <script src="https://cdn.blindagents.com/report.js" data-api-key="YOUR_API_KEY" data-primary-color="#e11d48" data-title="Help Center" data-report-btn-text="Report an issue" data-btn-emoji="🔴" defer> </script>
Save — done
Open your Bubble app settings
Settings → SEO / metatags tab.
Paste in the Script/meta tags in header field
<!-- Bubble: Settings → SEO / metatags → Script/meta tags in header
Or use an HTML element on the page with the script tag -->
<script
src="https://cdn.blindagents.com/report.js"
data-api-key="YOUR_API_KEY"
data-primary-color="#e11d48"
data-title="Help Center"
data-report-btn-text="Report an issue"
data-btn-emoji="🔴"
defer>
</script>Alternatively, add an HTML element on any page and paste the script tag there.
Deploy to live — the widget appears on your app
Open Site Settings → General → Custom Code
Click the gear icon in the top-right of the Framer editor.
Paste in the End of body tag section
// Framer: Site Settings → General → Custom Code → End of <body> <script src="https://cdn.blindagents.com/report.js" data-api-key="YOUR_API_KEY" data-primary-color="#e11d48" data-title="Help Center" data-report-btn-text="Report an issue" data-btn-emoji="🔴" defer> </script>
Publish — the widget loads on your live Framer site
GTM lets you deploy the widget to any site without touching the source code — useful for marketing teams or sites managed by multiple people.
Create a new Custom HTML Tag
In GTM: Tags → New → Tag Configuration → Custom HTML.
Paste the custom HTML snippet
// Google Tag Manager → Tags → New → Custom HTML
<script>
(function() {
var el = document.createElement('script');
el.src = 'https://cdn.blindagents.com/report.js';
el.setAttribute('data-api-key', 'YOUR_API_KEY');
el.setAttribute('data-primary-color', '#e11d48');
el.setAttribute('data-title', 'Help Center');
el.setAttribute('data-report-btn-text', 'Report an issue');
el.setAttribute('data-btn-emoji', '🔴');
el.defer = true;
document.head.appendChild(el);
})();
</script>
// Trigger: All Pages — Page ViewSet trigger to All Pages
Under Triggering, select All Pages → Page View.
Submit and publish the container
Get real-time Slack notifications for every Blind Agents event — new tickets, status changes, resolved issues, and new contacts. There are two approaches: a simple Slack Incoming Webhook, or a full server middleware that verifies signatures.
Create a Slack Incoming Webhook
1. Go to api.slack.com/apps → Create New App → From scratch.
2. Under Features → Incoming Webhooks, enable it and click Add New Webhook to Workspace.
3. Select the channel (e.g. #bugs) and copy the webhook URL.
curl -X POST https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK \
-H "Content-Type: application/json" \
-d '{
"text": "New Blind Agents ticket: Button not working on checkout",
"blocks": [{
"type": "section",
"text": { "type": "mrkdwn", "text": "*New ticket:* Button not working on checkout" }
}]
}'Create a Blind Agents webhook pointing to your server
In Blind Agents → Webhooks → Add webhook, enter your server endpoint URL (e.g. https://yourserver.com/webhooks/blind-agents) and select the events to subscribe to.
// Example payload Blind Agents sends to your webhook URL
{
"id": "evt_01HXYZ...",
"event": "ticket.created",
"created_at": "2026-04-09T03:00:00Z",
"data": {
"id": "tkt_01HXYZ...",
"title": "Button not working on checkout",
"status": "open",
"priority": "high",
"type": "bug",
"contact": { "name": "Jane Doe", "email": "jane@example.com" },
"page_url": "https://yoursite.com/checkout"
}
}Build the middleware to forward events to Slack
This Node.js/Express handler verifies the signature then forwards a message to Slack:
// Express.js handler that forwards Blind Agents events to Slack
import express from 'express';
import crypto from 'crypto';
const app = express();
app.use(express.raw({ type: 'application/json' })); // raw body for signature verification
const BA_SECRET = process.env.BLIND_AGENTS_WEBHOOK_SECRET;
const SLACK_URL = process.env.SLACK_WEBHOOK_URL;
function verify(rawBody, signature) {
const parts = Object.fromEntries(signature.split(',').map(p => p.split('=')));
const expected = crypto.createHmac('sha256', BA_SECRET)
.update(`${parts.t}.${rawBody}`).digest('hex');
const valid = crypto.timingSafeEqual(Buffer.from(parts.v1, 'hex'), Buffer.from(expected, 'hex'));
const recent = Date.now() / 1000 - Number(parts.t) < 300;
return valid && recent;
}
app.post('/webhooks/blind-agents', async (req, res) => {
const sig = req.headers['x-blindagents-signature'];
if (!verify(req.body.toString(), sig)) return res.sendStatus(401);
const { event, data } = JSON.parse(req.body.toString());
// Map events to Slack messages
const messages = {
'ticket.created': `🎫 *New ticket:* <${data.page_url}|${data.title}> — ${data.priority} priority`,
'ticket.status_changed': `🔄 *Ticket updated:* ${data.title} → ${data.status}`,
'ticket.resolved': `✅ *Ticket resolved:* ${data.title}`,
'contact.created': `👤 *New contact:* ${data.name} (${data.email})`,
};
const text = messages[event] ?? `📡 Blind Agents event: ${event}`;
await fetch(SLACK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text }),
});
res.sendStatus(200);
});Use Block Kit for rich Slack messages (optional)
Replace the plain text message with a structured Block Kit layout including a direct link to the ticket:
// Rich Slack message with Block Kit for ticket.created
const block = {
blocks: [
{
type: "header",
text: { type: "plain_text", text: "🎫 New Bug Report" }
},
{
type: "section",
fields: [
{ type: "mrkdwn", text: `*Title:*\n${data.title}` },
{ type: "mrkdwn", text: `*Priority:*\n${data.priority}` },
{ type: "mrkdwn", text: `*Reporter:*\n${data.contact?.name ?? 'Anonymous'}` },
{ type: "mrkdwn", text: `*Page:*\n${data.page_url ?? '—'}` },
]
},
{
type: "actions",
elements: [{
type: "button",
text: { type: "plain_text", text: "View ticket" },
url: `https://www.blindagents.com/tickets/${data.id}`,
style: "primary"
}]
}
]
};n8n is an open-source workflow automation tool. Use it to connect Blind Agents events to Slack, email, Jira, Notion, Google Sheets, or any other service — without writing a server from scratch.
Add a Webhook trigger node in n8n
1. In n8n, create a new workflow.
2. Add a Webhook node as the trigger.
3. Set Method to POST and copy the generated URL.
// 1. In n8n, add a "Webhook" trigger node // 2. Copy the generated webhook URL // 3. In Blind Agents → Webhooks, create a new webhook with that URL // 4. Select the events you want (e.g. ticket.created, ticket.status_changed) // 5. Connect downstream n8n nodes to process the data
Register the n8n URL as a Blind Agents webhook
In Blind Agents → Webhooks → Add webhook:
• Paste the n8n webhook URL.
• Select the events you want (e.g. ticket.created, ticket.resolved).
• Copy the signing secret — you'll need it in the next step.
Add a Code node to verify the signature
This step is optional but strongly recommended. Add a Code node after the webhook trigger and paste this verification logic:
// n8n Code node — verify the Blind Agents signature
const crypto = require('crypto');
const secret = $env.BLIND_AGENTS_SECRET; // store in n8n Credentials
const signature = $input.first().headers['x-blindagents-signature'];
const rawBody = JSON.stringify($input.first().body);
const parts = Object.fromEntries(signature.split(',').map(p => p.split('=')));
const msg = `${parts.t}.${rawBody}`;
const hmac = crypto.createHmac('sha256', secret).update(msg).digest('hex');
const isValid = crypto.timingSafeEqual(Buffer.from(parts.v1, 'hex'), Buffer.from(hmac, 'hex'));
const isRecent = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
if (!isValid || !isRecent) throw new Error('Invalid signature — aborting workflow');
return $input.all(); // pass through to next nodeBLIND_AGENTS_SECRET in n8n → Credentials → Custom API — never hardcode secrets.Connect downstream nodes
Use expressions like {{ $json.body.data.title }} to access ticket fields. Example workflow sending to Slack:
// n8n workflow: Blind Agents → Slack (3 nodes)
// Node 1 — Webhook trigger (auto-generated URL, POST method)
// Node 2 — Code (signature verification, see above)
// Node 3 — Slack node (Send Message)
// Channel: #bugs
// Message text (expression):
"🎫 New ticket: {{ $json.body.data.title }}
Priority: {{ $json.body.data.priority }}
Reporter: {{ $json.body.data.contact.name }}
Page: {{ $json.body.data.page_url }}"Always end with a Respond to Webhook node
// Always add an "Respond to Webhook" node at the end
// Response Code: 200
// Response Body: { "ok": true }
// This tells Blind Agents the delivery succeeded.
// If your workflow errors before this node, Blind Agents will mark the delivery as failed.All data-* attributes below work on both report.js and chat.js unless noted. React / Next.js props use camelCase equivalents (e.g. primaryColor, panelWidth).
Mounting inside a DOM element — set data-anchor to a CSS selector (e.g. #my-panel). The widget mounts inside that element with position:absolute instead of the default position:fixed.
Custom position — pass a JSON object to data-position: '{"bottom":"20px","right":"80px"}'. Presets: bottom-right · bottom-left · top-right · top-left.
data-api-keyYour Blind Agents public API key (ba_...)
data-agent-idAgent UUID to connect the chat to (chat.js only)
data-user-whatsappPre-fill WhatsApp number (country code required, e.g. 573114088900) — skips OTP verification
data-external-idYour internal user / account ID — links sessions to your own CRM records
data-primary-colorAccent color for the widget UI (any CSS color)
data-btn-emojiEmoji shown on the floating launcher button
data-icon-urlURL of an image to use as the launcher icon (overrides data-btn-emoji)
data-btn-tooltipTooltip text on the launcher button
data-titlePanel header title (report.js)
data-report-btn-text"Report" button label inside the panel (report.js)
data-empty-textText shown when there are no reports (report.js)
data-font-sizeChat font size preset e.g. "14px" (chat.js)
data-font-familyChat font family: "System" | "Serif" | "Mono" | "Rounded" (chat.js)
data-notification-soundEnable/disable notification sound on incoming messages — "true" (default) or "false" (chat.js)
data-positionWidget position: "bottom-right" | "bottom-left" | "top-right" | "top-left" | JSON object e.g. '{"bottom":"20px","right":"80px"}'
data-anchorCSS selector of a DOM element to mount the widget inside (e.g. "#my-panel"). Element gets position:relative automatically.
data-bubble-sizeDiameter of the floating launcher button in px (default: 56)
data-panel-widthWidth of the open widget panel (any CSS length, e.g. "380px")
data-panel-heightHeight of the open widget panel (any CSS length, e.g. "600px")
The npm package uses camelCase props that map 1:1 to the data attributes:
data-api-key→apiKeydata-primary-color→primaryColordata-title→titledata-report-btn-text→reportBtnTextdata-btn-emoji→btnEmojidata-btn-tooltip→btnTooltipdata-empty-text→emptyTextdata-user-whatsapp→userWhatsappdata-external-id→externalId@duvandroid/react-blind-agents
React component wrapper for the Blind Agents widget
npm install @duvandroid/react-blind-agents