Support Beacon
The Beacon is Kitoro’s embeddable support widget. Add it to your website to let visitors chat with Atlas AI, submit support requests, and track conversions back to content.
What You Get
Section titled “What You Get”- Live Chat: Visitors chat with Atlas AI, powered by your knowledge base
- Contact Form: Collect support requests when you’re offline
- Conversion Tracking: Attribute signups and purchases to the content that generated them
- Branding: Match your brand colors, logo, and welcome message
Step 1: Configure the Widget
Section titled “Step 1: Configure the Widget”- Go to Settings → Support Beacon in Kitoro
- Toggle features on/off:
- Live Chat (Atlas AI)
- Contact Form
- Require Email
- AI Auto-Reply
- Customize branding:
- Upload your logo
- Set your brand color
- Write a welcome message
- Choose button icon and position
Step 2: Get the Embed Code
Section titled “Step 2: Get the Embed Code”- In Settings → Support Beacon, scroll to Installation
- Click Get Embed Code
- Copy the code snippet
Step 3: Add to Your Website or App
Section titled “Step 3: Add to Your Website or App”The Beacon works in two modes depending on where you embed it:
| Mode | Use Case | User Identity |
|---|---|---|
| Anonymous | Marketing website, landing pages | Visitor is unknown until they provide email |
| Identified | Inside your SaaS app | User is logged in, you know who they are |
Anonymous Mode (Marketing Website)
Section titled “Anonymous Mode (Marketing Website)”For public pages where visitors aren’t logged in. Paste just before </body>:
<script> (function(w,d,s,o,f,js,fjs){ w['KitoroBeacon']=o;w[o]=w[o]||function(){ (w[o].q=w[o].q||[]).push(arguments)}; js=d.createElement(s);fjs=d.getElementsByTagName(s)[0]; js.id='kitoro-beacon';js.src=f;js.async=1; fjs.parentNode.insertBefore(js,fjs); })(window,document,'script','kb','https://wgzyalishpyzbtgkxylm.supabase.co/storage/v1/object/public/beacon-widget/widget.js'); kb('init', 'kit_pub_YOUR_KEY_HERE');</script>Behavior:
- Visitor chats anonymously
- If Atlas escalates to human support, visitor is asked for their email
- Contact is created in your CRM (or matched to existing contact if email already exists)
Identified Mode (Inside Your App)
Section titled “Identified Mode (Inside Your App)”For logged-in users in your SaaS app. Pass the user’s info so Atlas knows who they are:
<script> (function(w,d,s,o,f,js,fjs){ w['KitoroBeacon']=o;w[o]=w[o]||function(){ (w[o].q=w[o].q||[]).push(arguments)}; js=d.createElement(s);fjs=d.getElementsByTagName(s)[0]; js.id='kitoro-beacon';js.src=f;js.async=1; fjs.parentNode.insertBefore(js,fjs); })(window,document,'script','kb','https://wgzyalishpyzbtgkxylm.supabase.co/storage/v1/object/public/beacon-widget/widget.js');
// Pass logged-in user info kb('init', 'kit_pub_YOUR_KEY_HERE', { user: { email: 'user@example.com', // Required name: 'Jane Smith', // Optional externalId: 'usr_12345' // Optional - your internal user ID } });</script>React / Next.js example:
useEffect(() => { if (window.kb && currentUser) { window.kb('init', process.env.NEXT_PUBLIC_KITORO_BEACON_KEY, { user: { email: currentUser.email, name: currentUser.name, externalId: currentUser.id } }); }}, [currentUser]);Behavior:
- User is identified immediately - no email prompt needed
- Contact is linked to your CRM (or created if new)
- Support tickets show the user’s name and email
externalIdlets you cross-reference tickets with your user database
Can I Use Both Modes?
Section titled “Can I Use Both Modes?”Yes. Most customers use:
- Anonymous mode on marketing site (leads, prospects)
- Identified mode inside their app (paying customers, trials)
Both use the same API key. The mode is determined by whether you pass the user object.
The widget appears as a floating button in the corner of your site.
CRM Integration
Section titled “CRM Integration”The Beacon automatically links conversations to your Kitoro CRM. No duplicate contacts.
How Matching Works
Section titled “How Matching Works”When a visitor provides their email (or you pass it via identified mode), Kitoro:
- Searches your CRM for an existing contact with that email
- If found: Links the conversation to that contact (even if they came from LinkedIn, Twitter, etc.)
- If not found: Creates a new contact with source
beacon_websiteorbeacon_app
This means a lead who first commented on your LinkedIn post, then later visits your website and chats - they’re linked as one contact, not two.
Source Tracking
Section titled “Source Tracking”| Where They Chat | Contact Source |
|---|---|
| Marketing website (anonymous) | beacon_website |
| Inside your app (identified) | beacon_app |
You can filter contacts by source in your CRM to see how many come from the widget vs social vs other channels.
Features
Section titled “Features”Live Chat with Atlas
Section titled “Live Chat with Atlas”When enabled, visitors can chat with Atlas AI in real-time:
- Atlas answers questions using your Library knowledge base
- High-confidence answers are delivered instantly
- Low-confidence questions get escalated to your Support queue
- When escalated, visitors receive: “A human will review this and email you within 24 hours”
- Conversations sync to Kitoro for follow-up and response via email
Contact Form
Section titled “Contact Form”When live chat is disabled or during offline hours:
- Visitors submit their email and message
- Creates a ticket in your Support queue
- Atlas drafts a response for your approval
Branding Options
Section titled “Branding Options”| Setting | Description |
|---|---|
| Logo | Your company logo (200x200px recommended) |
| Company Name | Shown in the widget header |
| Welcome Message | First thing visitors see |
| Brand Color | Button and accent color |
| Position | Bottom-right or bottom-left |
| Button Icon | Chat, AI, Help, Support, etc. |
Conversion Tracking
Section titled “Conversion Tracking”The Beacon also tracks when leads become customers, closing the loop on content ROI.
The Attribution Flow
Section titled “The Attribution Flow”- Content published → You post via Kitoro
- Engagement captured → Someone comments/DMs, Kitoro captures their email
- Lead created → They’re added to CRM with
source_post_id - Conversion tracked → They sign up, you call the Beacon API
- Revenue attributed → Kitoro traces back to the original post
Result: “This LinkedIn post generated $4,200 from 3 customers.”
Quick Start
Section titled “Quick Start”Add this to your signup handler:
// After successful signupfetch('https://wgzyalishpyzbtgkxylm.supabase.co/functions/v1/beacon-conversion', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Beacon-Key': 'kit_pub_YOUR_KEY_HERE' }, body: JSON.stringify({ email: user.email, event: 'signup', deal_value: 99 // optional })}).catch(console.error);API Reference
Section titled “API Reference”Endpoint: POST /functions/v1/beacon-conversion
Headers:
Content-Type: application/jsonX-Beacon-Key: kit_pub_xxx(from Settings)
Body:
{ "email": "user@example.com", "event": "signup", "deal_value": 99}| Field | Required | Description |
|---|---|---|
email | Yes | Customer’s email |
event | No | signup, purchase, or upgrade |
deal_value | No | Revenue amount |
Response:
// Contact found in CRM{ "success": true, "matched": true, "has_attribution": true }
// Email not in CRM (direct signup, not from content){ "success": true, "matched": false }Code Examples
Section titled “Code Examples”JavaScript / React / Next.js:
const BEACON_URL = 'https://wgzyalishpyzbtgkxylm.supabase.co/functions/v1/beacon-conversion';
async function trackConversion(email, event = 'signup', dealValue) { try { await fetch(BEACON_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Beacon-Key': process.env.KITORO_BEACON_KEY }, body: JSON.stringify({ email, event, deal_value: dealValue }) }); } catch (error) { console.error('Kitoro tracking failed:', error); }}Python / Django:
import requestsimport os
BEACON_URL = 'https://wgzyalishpyzbtgkxylm.supabase.co/functions/v1/beacon-conversion'
def track_conversion(email, event='signup', deal_value=None): try: requests.post( BEACON_URL, headers={ 'Content-Type': 'application/json', 'X-Beacon-Key': os.environ['KITORO_BEACON_KEY'] }, json={'email': email, 'event': event, 'deal_value': deal_value}, timeout=5 ) except Exception as e: print(f'Kitoro tracking failed: {e}')Ruby / Rails:
class KitoroTracker BEACON_URL = 'https://wgzyalishpyzbtgkxylm.supabase.co/functions/v1/beacon-conversion'
def self.track_conversion(email:, event: 'signup', deal_value: nil) HTTParty.post( BEACON_URL, headers: { 'Content-Type' => 'application/json', 'X-Beacon-Key' => ENV['KITORO_BEACON_KEY'] }, body: { email: email, event: event, deal_value: deal_value }.to_json ) rescue => e Rails.logger.warn "Kitoro tracking failed: #{e.message}" endendBest Practices
Section titled “Best Practices”For the Widget:
- Keep your Library well-stocked so Atlas can answer questions
- Set up offline hours if you want contact form instead of live chat at night
- Use your brand color for recognition
For Conversion Tracking:
- Call after successful signup (not before)
- Make it async - don’t block the signup flow
- Catch errors - tracking failure shouldn’t break signups
- Store API key in environment variables
Q: What’s the difference between anonymous and identified mode? A: Anonymous mode is for public websites where you don’t know who the visitor is. Identified mode is for logged-in users inside your app - you pass their email/name so Atlas knows who they are immediately.
Q: Can I use both modes with the same API key?
A: Yes. The mode is determined by whether you pass the user object in kb('init', ...). Same key works for both.
Q: What if a website visitor already exists in my CRM? A: They’re linked to their existing contact record. No duplicates are created. This works because Kitoro matches by email across all sources (social, website, app).
Q: What if Atlas can’t answer a question? A: Atlas flags it for human review and the ticket appears in your Support queue.
Q: Does the widget slow down my site? A: No, it loads asynchronously and is only ~6KB gzipped.
Q: What if someone signs up without engaging with content first?
A: The conversion is recorded with matched: false. You see it in metrics but it won’t attribute to any content.