Skip to content

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.

  • 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
  1. Go to Settings → Support Beacon in Kitoro
  2. Toggle features on/off:
    • Live Chat (Atlas AI)
    • Contact Form
    • Require Email
    • AI Auto-Reply
  3. Customize branding:
    • Upload your logo
    • Set your brand color
    • Write a welcome message
    • Choose button icon and position
  1. In Settings → Support Beacon, scroll to Installation
  2. Click Get Embed Code
  3. Copy the code snippet

The Beacon works in two modes depending on where you embed it:

ModeUse CaseUser Identity
AnonymousMarketing website, landing pagesVisitor is unknown until they provide email
IdentifiedInside your SaaS appUser is logged in, you know who they are

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)

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
  • externalId lets you cross-reference tickets with your user database

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.

The Beacon automatically links conversations to your Kitoro CRM. No duplicate contacts.

When a visitor provides their email (or you pass it via identified mode), Kitoro:

  1. Searches your CRM for an existing contact with that email
  2. If found: Links the conversation to that contact (even if they came from LinkedIn, Twitter, etc.)
  3. If not found: Creates a new contact with source beacon_website or beacon_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.

Where They ChatContact 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.


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

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
SettingDescription
LogoYour company logo (200x200px recommended)
Company NameShown in the widget header
Welcome MessageFirst thing visitors see
Brand ColorButton and accent color
PositionBottom-right or bottom-left
Button IconChat, AI, Help, Support, etc.

The Beacon also tracks when leads become customers, closing the loop on content ROI.

  1. Content published → You post via Kitoro
  2. Engagement captured → Someone comments/DMs, Kitoro captures their email
  3. Lead created → They’re added to CRM with source_post_id
  4. Conversion tracked → They sign up, you call the Beacon API
  5. Revenue attributed → Kitoro traces back to the original post

Result: “This LinkedIn post generated $4,200 from 3 customers.”

Add this to your signup handler:

// After successful signup
fetch('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);

Endpoint: POST /functions/v1/beacon-conversion

Headers:

  • Content-Type: application/json
  • X-Beacon-Key: kit_pub_xxx (from Settings)

Body:

{
"email": "user@example.com",
"event": "signup",
"deal_value": 99
}
FieldRequiredDescription
emailYesCustomer’s email
eventNosignup, purchase, or upgrade
deal_valueNoRevenue 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 }

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 requests
import 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}"
end
end

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.