<script async src="https://signalbird.io/sdk/v1/signalbird.js" data-key="sb_public_live_…" data-channel="destek"></script>Web Widget - Canlı sohbet (signalbird.js)
Sitenize tek satırla eklenen canlı sohbet balonu. Ziyaretçi yazar, ekibiniz
panelde Inbox'tan yanıtlar. Widget ayrıca ziyaretçiyi bir kişiye
bağlar (identify) ve web push cihazını kaydeder (push.register), böylece
aynı kişi kampanyalarda da hedeflenebilir.
Bağımlılığı yoktur, 40 KB gzip altındadır, Shadow DOM içinde çalışır - sitenizin CSS'i widget'a, widget'ın CSS'i sitenize karışmaz.
Kurulum
<script async
src="https://signalbird.io/sdk/v1/signalbird.js"
data-app-key="sb_public_live_xxxxxxxxxxxxxxxx"></script>Bu kadar. Betik yüklenince POST /v1/sdk/bootstrap ile uygulama ayarlarını
çeker ve balonu çizer. </body> kapanışından hemen önce ya da <head> içinde
async ile eklenebilir; sayfanın yüklenmesini bloklamaz.
Anahtar
Panelde Inbox → Ayarlar → Uygulamalar → Yeni uygulama ile bir uygulama
açın; size bir uygulama anahtarı (sb_public_live_…) verilir.
Bu anahtar açıktır - HTML'de durur, herkes görebilir. Güvenliği kısıttan
gelir: uygulama ayarlarındaki izinli kökenler (alan adları) dışından
gelen istekler 403 ile reddedilir. Yeni bir alan adına (staging, yeni domain)
kurarken önce izinli kökenlere ekleyin.
Gizli anahtar (
sb_secret_live_…) burada çalışmaz;sb_…gizlidir ve HTML'e asla gömülmez.
Seçenekler
Betik etiketi üzerinden (data-*) ya da Signalbird.init() ile verilir; ikisi
aynı alanlardır.
data-* |
init() alanı |
Varsayılan | Açıklama |
|---|---|---|---|
data-app-key |
publicKey |
- | Zorunlu. sb_public_live_ ile başlamalı |
data-base-url |
baseUrl |
https://signalbird.io/api |
Kendi kurulumunuz varsa |
data-locale |
locale |
tarayıcı dili | tr ya da en |
| - | user |
- | Sayfa açılışında bilinen kullanıcı (identify ile aynı biçim) |
data-external-id |
user.external_id |
- | Oturumdaki kullanıcının sizin sisteminizdeki kimliği |
data-identity-hash |
identityHash |
- | external_id'nin hash'i - sunucunuzda üretilir (Kimlik doğrulaması) |
| - | debug |
false |
Konsola ayrıntı yazar |
data-app-key verildiğinde widget kendini kurar; init() çağırmanız gerekmez.
Anahtarı çalışma zamanında belirlemek isterseniz data-app-key'i atlayıp
Signalbird.init({...}) çağırın.
API
window.Signalbird betik yüklendiğinde hazırdır. Hiçbir metot sayfaya hata
fırlatmaz: widget'ın bir sorunu sitenizi bozmaz.
| Metot | Açıklama |
|---|---|
Signalbird.init({ publicKey, baseUrl?, locale?, user?, identityHash?, debug? }) |
Elle kurulum |
Signalbird.identify({ external_id, identityHash?, email?, name?, phone?, attributes? }) |
Ziyaretçiyi bir kişiye bağlar - girişten sonra çağırın. identityHash olmadan kimlik doğrulanmamış sayılır |
Signalbird.chat.open() · close() · toggle() |
Paneli açar / kapatır |
Signalbird.chat.isOpen() |
boolean |
Signalbird.chat.on('unread' | 'open' | 'close', fn) · off(event, fn) |
Olay dinleyici. unread sayıyla çağrılır |
Signalbird.push.register({ token, platform, provider?, external_id? }) |
Cihazı push kaydına ekler. platform: web · ios · android; provider: fcm · apns · webpush |
Signalbird.destroy() |
Widget'ı DOM'dan söker, zamanlayıcıları durdurur |
Kullanıcıyı tanıtmak
Ziyaretçi anonim başlar (localStorage['sb_visitor']). Giriş yaptığında
identify çağırın; sohbet geçmişi ve kişi kaydı o kullanıcıya bağlanır,
ekibiniz Inbox'ta ismini görür.
<script>
Signalbird.identify({
external_id: 'user-1042', // sizin sistemdeki kimlik
identityHash: '{{ hash }}', // SUNUCUNUZDA üretilir - aşağıya bakın
email: 'ahmet@example.com',
name: 'Ahmet Çil',
attributes: { plan: 'pro', company: 'Penyu' },
})
</script>external_id sizin sisteminizdeki kalıcı kimliktir; e-posta değişse de aynı
kişi kalır. Aynı external_id ile Gönderim SDK'sından sendPush({ to: 'external:user-1042' }) çağırabilirsiniz.
Programatik açma
Kendi "Yardım" bağlantınızdan paneli açın:
<button onclick="Signalbird.chat.open()">Bize yazın</button>Signalbird.chat.on('unread', (count) => {
document.querySelector('#help-badge').textContent = count > 0 ? String(count) : ''
})Web push kaydı
Kendi servis çalışanınızla token aldıktan sonra cihazı kaydedin; kişi panelden push kampanyalarında hedeflenebilir olur.
const token = await getFcmToken() // sizin FCM / Web Push akışınız
Signalbird.push.register({ token, platform: 'web', provider: 'fcm', external_id: 'user-1042' })React / Next.js
'use client'
import Script from 'next/script'
export function SignalbirdWidget({ user }: { user?: { id: string; email: string; name: string } }) {
return (
<Script
src="https://signalbird.io/sdk/v1/signalbird.js"
data-app-key={process.env.NEXT_PUBLIC_SIGNALBIRD_APP_KEY}
strategy="afterInteractive"
onLoad={() => {
if (user) window.Signalbird?.identify({ external_id: user.id, email: user.email, name: user.name })
}}
/>
)
}useEffect ile de eklenebilir: bir <script> oluşturup document.body'ye
takın, load olayında window.Signalbird?.identify(...) çağırın. Bileşen
kaldırılırken Signalbird.destroy() çağırmak isteğe bağlıdır; widget tek
örnektir ve tekrar init çağrısını yok sayar.
Özellikler
- Başlatıcı balon + panel; ≤ 640 px genişlikte tam ekran
- Boş ekran bir form değil, davet: marka avatarı, karşılama cümlesi, yanıt süresi ve destek konularından türeyen hazır başlangıç çipleri. Çipe dokunmak o metni mesaj olarak gönderir - "ne yazacağımı bilmiyorum" en sık terk sebebidir
- Kendini fark ettiren üç sinyal: ziyaretçi paneli hiç açmadıysa 11 sn sonra bir kez çıkan karşılama kartı; panel kapalıyken gelen yanıtın balonun üstünde beliren önizlemesi; okunmamış varken balonun sessiz nabzı. Üçü de kapatılabilir, kapatma kararı tarayıcıda saklanır
- Sohbet öncesi form (isim / e-posta - uygulama ayarına göre), karşılama mesajı, çalışma saatleri dışında çevrimdışı şeridi
- Gün ayraçları, ✓ / ✓✓ okundu bilgisi, iki yönlü yazıyor göstergesi
- Mesaj gruplama: aynı kişinin 5 dk içindeki ardışık mesajları tek öbek; avatar ve saat yalnız öbeğin sonunda
- Emoji seçici, uzun mesaj geçmişinde "en alta in" düğmesi, gövdedeki bağlantılar tıklanır
- Tek mesajda 420 karakter (sunucudan gelir, panelden değişebilir). Son 60 karakterde sayaç belirir, sınır aşılınca gönderilmez. Sınır iki taraf için de geçerlidir: jetonu yakan şey mesajı kimin yazdığı değil, uzunluğu
- Dosya yükleme: sürükle-bırak, yapıştır; jpeg / png / gif / webp / avif,
PDF ve düz metin - üst sınır
max_attachment_mb.image/*joker'i bilerek yok:image/svg+xmlbetik çalıştırabilen bir belgedir, görsel değil. Tür sunucuda dosyanın İÇERİĞİNDEN okunur; uzantıyı değiştirmek işe yaramaz - Alıntıyla yanıt, emoji tepkileri, kendi mesajını 15 dk içinde düzenle / sil
- Okunmamış rozeti +
document.titleyanıp sönmesi, ses Entergönderir,Shift+Entersatır atlar- tr / en otomatik; kapanışta 1–5 puan
- Canlı bağlantı (socket.io); bağlantı kurulamazsa yoklamaya düşer (kapalıyken 20 s → 180 s, açıkken 3 s)
- Ziyaretçi paneli taşır ve boyutlandırır: başlığı sürükle, dış üst
köşedeki tutamaktan çek. Seçim tarayıcıda saklanır
(
localStorage['sb_geometry']); mobilde kapalıdır - Mobil: tam ekran (
100dvh), çentik ve ev çubuğu boşlukları, klavye açılınca kompozitör klavyenin üstünde kalır, arkadaki sayfa kaymaz, tepedeki tutamağı aşağı sürükleyerek kapanır - Açık / koyu tema; koyu için
themeayarı ya da ziyaretçinin tercihi (auto) - Sohbet bitince panel sıfırdan başlar - kapanmış yazışma geri açılmaz. Ziyaretçi sohbeti bitirdiyse temsilci o konuşmaya yazamaz: kapanan kapı iki taraf için de kapalıdır
- Shadow DOM izolasyonu, marka rengi / logo / konum panelden
Panel ayarları
Kodda hiçbir görünüm ayarı yoktur; hepsi Inbox → Ayarlar → Uygulamalar altında durur ve bootstrap ile widget'a iner.
| Panel ayarı | Widget'ta karşılığı |
|---|---|
Sohbet açık / kapalı (chat_enabled) |
Kapalıysa widget hiçbir şey çizmez |
| İzinli kökenler | Liste dışı alan adından 403 |
| Tema rengi, konum (sağ / sol) | Marka rengi ve panelin başlangıç yeri |
Logo adresi (logo_url) |
Başlık avatarı; launcher_icon: logo ise balon |
Tema (theme: açık / koyu / ziyaretçinin tercihi) |
Widget'ın kendi yüzeyi - sayfaya dokunmaz |
Balon ikonu (launcher_icon: kuş / baloncuk / logo) |
Balondaki işaret |
Balon davranışı (launcher_mode: her zaman / yalnız çağrıldığında) |
manual seçilirse balon hiç çizilmez; sohbeti sitenizin kendi düğmesi açar |
Panel biçimi (layout: köşe penceresi / kenar çekmecesi / sayfa içi) |
sidebar ekran boyu kenar panelidir; inline sohbeti sayfanın içine çizer |
Sayfa içi kap (inline_selector) |
inline biçiminde sohbetin çizileceği kabın CSS seçicisi (varsayılan #signalbird-chat) |
Görünen ajan adı (agent_display_name) |
Ziyaretçi ajanın gerçek adı yerine bunu görür |
Dile göre metinler (texts) |
Karşılama, çevrimdışı notu ve balon etiketi ziyaretçinin diline göre |
| Başlatıcı metni, karşılama mesajı | Balon üstündeki etiket, ilk mesaj |
| Sohbet öncesi form alanları | İsim / e-posta zorunluluğu |
| Çalışma saatleri | Çevrimdışı şeridi ve "en kısa sürede döneriz" notu |
max_attachment_mb |
Yükleme üst sınırı |
Ayar değişikliği yeni yayın gerektirmez; bir sonraki sayfa yüklemesinde geçerlidir.
Sayfa içi (inline) sohbet
Sohbeti köşedeki balon yerine sayfanın İÇİNE koyabilirsiniz - destek sayfasının gövdesi sohbet olur. Balon, kapatma düğmesi ve sürükleme yoktur; sohbet kendiliğinden açıktır.
<div id="destek" style="height:640px"></div>
<script async src="https://signalbird.io/sdk/v1/signalbird.js"
data-key="sb_public_live_…" data-channel="destek"
data-layout="inline" data-container="#destek"></script>Aynı sitede ikisi birden. Panel ayarı sitenin varsayılanıdır; tek bir sayfa ondan ayrılabilir. Her sayfada balon dururken destek sayfasına sayfa içi bir sohbet daha koymak için:
<script async src="https://signalbird.io/sdk/v1/signalbird.js"
data-key="sb_public_live_…" data-channel="destek"></script>
<div id="destek" style="height:640px"></div>
<script>Signalbird.inline('#destek')</script>Signalbird.inline(kap, seçenekler?) anahtarları init()ten devralır ve aynı
kaba ikinci kez çizmez. Kap bulunamazsa sohbet balon olarak açılır - yanlış bir
seçici yüzünden sohbetin hiç görünmemesindense.
Balonu kendi düğmenizle açmak
Sitenizde zaten bir "Canlı destek" düğmesi varsa balonu hiç göstermeyebilirsiniz.
Panelden balon davranışı: yalnız çağrıldığında (launcher_mode: manual)
seçin ve düğmenize tek satır bağlayın:
<button onclick="Signalbird.chat.open()">Canlı destek</button>Sohbet başladıktan sonra balon görünür olur: ziyaretçi pencereyi kapatırsa temsilcinin yanıtı balonda ışık ve sesle bildirilir. Ziyaretçi sohbeti bitirdiğinde balon yeniden kaybolur.
Kimlik doğrulaması ve captcha
Kimlik doğrulaması (2.7.0). Açık anahtar sayfanın kaynağında durduğu için
herkes identify({ external_id: 'user-1042' }) yazabilir. Bu yüzden
Signalbird external_id'yi (ve e-postayı) ancak yanında geçerli bir
identityHash varsa güvenilir sayar. Hash olmadan:
- ziyaretçi kişi kaydınıza (contact) bağlanmaz,
- cihazı o kullanıcıya push hedefi olarak bağlanmaz (
external:user-1042), - kanal ajanının araçları kimliği güvenilir ziyaretçi olarak değil, yalnız
visitor.unverifiedaltında görür.
Hash SUNUCUNUZDA, gizli anahtarla üretilir ve sayfaya kullanıcının kimliğiyle birlikte yazılır; gizli anahtar asla tarayıcıya inmez:
identity_hash = hex( HMAC-SHA256( hex(SHA-256(sb_secret_live_…)), external_id ) )Her sunucu dilinde hazır yardımcı var: PHP Signalbird::identityHash($id),
Node client.identityHash(id), Python client.identity_hash(id), Go
client.IdentityHash(id), .NET client.IdentityHash(id).
<!-- Laravel Blade -->
<script async src="https://signalbird.io/sdk/v1/signalbird.js"
data-key="sb_public_live_…" data-channel="destek"
data-external-id="{{ $user->id }}"
data-identity-hash="{{ Signalbird::identityHash((string) $user->id) }}"></script>Widget bildiği hash'i oturum, identify ve aynı external_id'li
push.register çağrılarına kendisi ekler.
Captcha. Kanalınızda açıksa widget iki noktada görünmez bir Cloudflare Turnstile jetonu alır: yeni ziyaretçinin oturumu açılırken ve doğrulanmamış ziyaretçi ilk konuşmayı başlatırken. Kurulumda yapmanız gereken bir şey yoktur:
- Turnstile betiği yalnız ziyaretçi sohbeti ilk açtığında yüklenir; sohbeti hiç açmayan ziyaretçiye indirilmez.
- Çoğu ziyaretçi hiçbir şey görmez; Cloudflare etkileşim isterse kutu panelin içinde çıkar.
- Kısa sürede çok fazla sohbet başlatılırsa ziyaretçiye nazik bir uyarı
gösterilir (429
CONVERSATION_RATE_LIMITED). - İçerik güvenlik politikası (CSP) kullanıyorsanız
script-srcveframe-src'ehttps://challenges.cloudflare.comekleyin.
Gizlilik ve güvenlik
- Ziyaretçi kimliği ve gizli anahtarı yalnız
localStorage['sb_visitor']içinde durur; çerez yazılmaz, üçüncü tarafa gitmez. - Ekibin Inbox'ta yazdığı iç notlar ziyaretçiye hiçbir zaman gönderilmez.
- Anlık çeviri yalnız iki taraf farklı dil kullanıyorsa çalışır ve her taraf yalnız KARŞI tarafın mesajını çevrilmiş görür; kendi yazdığı hep orijinaliyle durur.
- Uygulama anahtarı açıktır; koruma izinli kökenlerdedir. Bu listeyi geniş
tutmayın (
*yok). - Widget sitenizin DOM'unu okumaz, form alanlarına dokunmaz; yalnız kendi Shadow DOM kökünde çalışır.
- Yüklenen dosyalar takımınızın depolamasına gider ve yalnız o sohbetin taraflarına açılır.
Sorun giderme
| Belirti | Sebep / çözüm |
|---|---|
| Widget hiç görünmüyor, konsol sessiz | Uygulamada sohbet kapalı (chat_enabled: false). Panelden açın |
Konsolda bootstrap 403 |
Alan adı izinli kökenlerde yok - https:// şemasıyla birlikte ekleyin; localhost:3000 da ayrıca eklenmeli |
bootstrap 401 |
Anahtar yanlış türde (gizli/açık karışmış) ya da iptal edilmiş |
| Balon var, mesaj gitmiyor | Ağ sekmesinde /v1/sdk/* isteklerine bakın; debug: true ile konsola ayrıntı yazılır |
| Giriş sonrası geçmiş görünmüyor | identify çağrılmamış ya da farklı external_id |
| Ziyaretçi kişi kaydına bağlanmıyor, push kullanıcıya gitmiyor | identityHash verilmemiş ya da yanlış anahtarla üretilmiş - kimlik doğrulanmamış sayılır |
| "Güvenlik doğrulaması tamamlanamadı" bandı | Turnstile yüklenemedi ya da reddedildi; CSP'de challenges.cloudflare.com izinli mi bakın |
| Sitenin CSS'i widget'ı bozdu | Olmamalı (Shadow DOM). Sayfada all: unset gibi agresif global kurallar varsa debug ile bildirin |