Dokumentacja Webchatix
Czat na żywo w duchu Telegram-first: odwiedzający pisze w widżecie na stronie, zespół odpowiada z Telegrama i panelu webowego. Po lewej sekcje, po prawej szczegóły.
W 5 minut
- Otwórz bota →
/start— powstaje konto na planie Free i pierwsza strona. - Skopiuj snippet HTML i wklej go na stronie przed
</body>. /panel— jednorazowy link do panelu webowego (albo pozycja „Panel webowy” w menu).- Zaproś operatora:
/invitelub menu → „Zespół” → ➕. - Podłącz grupę Telegram: dodaj bota do grupy (albo wpisz w niej
/addgroup) i przypisz ją do strony w «Trasach». - Wariant zapasowy — cała strona do jednej grupy:
/bindsite site_keyw grupie.
Plany i płatności
Rejestracja jest otwarta: /start w bocie tworzy konto w planie Free. Plany płatne kupuje się kartą w panelu, sekcja Faktury — płatność obsługuje Stripe.
| Plan | Strony | Klienci / mies. | Operatorzy | Za miesiąc |
|---|---|---|---|---|
free | 1 | 30 | 1 | $0 |
basic | 20 | 1000 | 5 | $10 ($8 przy płatności rocznej) |
unlimited | ∞ | ∞ | ∞ | $20 ($16 przy płatności rocznej) |
Ceny podajemy za miesiąc. Płatność za rok jest tańsza o 20% i pobierana jednorazowo ($96 i $192 rocznie); w panelu rok jest wybrany domyślnie.
Premium (od Basic): szablony, active invite, visibility rules, notatki, oceny.
Klient to unikalny odwiedzający, który rozpoczął rozmowę w bieżącym miesiącu kalendarzowym; licznik zeruje się 1. dnia.
Jak działa płatność
- Panel → Faktury: bieżący plan, zużycie limitów, zmiana planu, lista płatności z linkami do PDF.
- Dane karty nie trafiają na nasze serwery — strona płatności i portal należą do Stripe.
- Zmianę planu w trakcie okresu Stripe rozlicza proporcjonalnie; anulowanie zostawia plan płatny do końca opłaconego okresu, potem konto wraca na Free.
- Na adres e-mail z tej samej sekcji przychodzą potwierdzenie płatności, informacja o nieudanym obciążeniu i przypomnienie o odnowieniu.
Komendy bota
| Komenda | Kto | Znaczenie |
|---|---|---|
/start [CODE] | wszyscy | Onboarding / realizacja zaproszenia. |
/menu | member | Główne menu konta. |
/help | wszyscy | Spis komend dla Twojej roli. |
/panel | member | Magic-link do panelu webowego. |
/newsite [nazwa | origin] | admin+ | Utwórz stronę (+ CORS origins). |
/addgroup | admin+ w grupie | Podłącz grupę jako operatora-grupę (bez chat_id). |
/bindsite KEY | admin+ w grupie | Podłącz grupę jako czat zapasowy. |
/invite | admin+ | Zaproszenie operatora. |
/op_me CODE | każdy | Przyjmij zaproszenie. |
/tpl | member | Lista / add / del / wysyłka reply + /tpl id. |
/note | member | Notatka do rozmowy (od Basic). |
/release | member | Zwolnij rozmowę (+ prośba o ocenę). |
/lang | wszyscy | Język interfejsu bota: en / pl / de / ru / uk / be / ar. |
/setrole id role | owner | owner|admin|operator. |
/crm on|off | owner | Włącz/wyłącz most CRM konta. |
/deleteaccount | owner | Usuń konto. |
/id | na czacie | Pokaż chat_id. |
Panel webowy
Logowanie tenanta: link z /panel albo token na /account/login/.
| Sekcja | Po co |
|---|---|
| Przegląd | Liczniki i ostatnie rozmowy; nazwa firmy; most CRM dla ownera — przełącznik i link webhooka (puste — wspólny z config). |
| Strony | Tworzenie, snippet, pełne ustawienia widżetu. |
| Operatorzy | Uczestnicy, zaproszenia, role, grupy. |
| Trasy | Assignments: strona → operator/grupa. |
| Rozmowy | Historia, release, notatki, ocena. |
| Statystyki | Odwiedziny, boty, formularze i czat dla wszystkich stron lub jednej; strony; kod tylko do statystyk; klucz API konta. |
| Szablony | CRUD szablonów + podsumowanie ocen (od Basic). |
Ustawienia strony
Dostępne w bocie („Ustawienia”) oraz w panelu: Strony → koło zębate.
| Pole | Znaczenie |
|---|---|
| Nazwa / tytuł / podtytuł | Nagłówek czatu. |
| Powitanie / logo | Pierwsza wiadomość i marka. |
| Online od–do, TZ, pauza | Status Online/Offline. |
| Eskalacja (min) | Alert przy braku odpowiedzi. |
| Kolor / pozycja / marginesy | Przycisk widżetu. |
| Język / dźwięk | en|pl|de|ru|uk|be|ar oraz URL mp3. |
| Allowed origins | CORS: domeny po przecinku albo *. |
| Invite * | Zaproszenie w dymku (od Basic). |
| Visibility JSON | Gdzie pokazywać przycisk/invite (od Basic). |
| GDPR | Checkbox zgody przed pierwszą wysyłką. |
| Asystent AI | Odpowiada klientowi, gdy nikt nie odpisał przez N minut (domyślnie 3). |
Asystent AI (Gemini)
Klient napisał, operator milczy — po ustawionej liczbie minut w rozmowie odpowiada Google Gemini. Klient widzi odpowiedź w widgecie, a operatorzy dostają w Telegramie kartę „AI odpowiedziało” z tym samym tekstem, żeby nikt nie powtarzał.
- Włącza się osobno dla każdej strony: Strony → koło zębate → Asystent AI. Tam też opóźnienie i pole „co AI ma wiedzieć o firmie” — godziny, dostawa, czego nie wolno obiecywać.
- Odpowiedź człowieka zeruje licznik; rozmowy przejętej przez operatora (claim) AI nie rusza.
- Odpowiedź AI nie kasuje eskalacji: administrator i tak dostanie alert, że człowiek nie odpisał.
- Model odpowiada krótko, nie wymyśla cen ani terminów, a zapytany wprost przyznaje, że jest automatycznym asystentem.
- Klucz API ustawia się raz dla całej instalacji:
gemini_api_keywconfig/config.php(klucz z Google AI Studio ma darmowy limit). Bez klucza checkbox nic nie daje.
Przykład visibility
{"include":["/pricing","/contacts"],"exclude":["/admin"],"desktop":true,"mobile":true} Widżet na stronie
<script async src="https://webchatix.online/widget/webchatix.js"
data-site-key="SITE_KEY"></script>
Sterowanie ze strony:
webchatix("show"); // pokaż przycisk
webchatix("hide"); // ukryj
webchatix("open"); // otwórz czat
webchatix("close"); // zamknij panel
webchatix("form", "report"); // zalicz wysłanie formularza (statystyki)
Język widżetu bierze się z data-lang, potem z <html lang> strony, a na końcu z przeglądarki; obsługiwane są en / pl / de / ru / uk / be / ar, zapasowy to angielski. Po zmianie ustawień odśwież stronę klienta (wersja widżetu w query ?v=).
Jeśli strona ma ustawioną Content-Security-Policy, dopuść domenę widżetu w trzech dyrektywach: script-src, style-src i connect-src. Wygląd widżet ładuje z osobnego pliku webchatix.css, więc nie trzeba dla niego trzymać 'unsafe-inline' w style-src.
Statystyki odwiedzin i API
Widżet liczy odwiedziny strony, na której jest zainstalowany. Statystyki są przechowywane bez limitu czasu jako liczniki dzienne (doby wg UTC); raport można pobrać za dowolny okres. Dane udostępnia API po tajnym kluczu konta — jeden klucz otwiera wszystkie strony konta.
| Pole | Co jest liczone |
|---|---|
unique_visitors | Unikalni odwiedzający — po cookie widżetu (bez cookie — po IP + przeglądarce w ciągu doby). W okresie bez powtórzeń: jedna osoba w tygodniu liczy się raz. |
visits | Wejścia — pierwsza strona po 30 minutach bezczynności oraz pierwsza strona odwiedzającego w danej dobie. |
page_views | Wyświetlenia stron przez ludzi, w tym przejścia w SPA (history.pushState). |
bot_hits | Odwiedziny stron przez boty: wyszukiwarki (Googlebot, Bingbot, YandexBot…), crawlery AI (GPTBot, ClaudeBot, PerplexityBot…), sieci społecznościowe, narzędzia SEO, przeglądarki headless. Nie wliczają się do wyświetleń ani unikalnych. |
form_submits | Wysłania formularzy na stronach witryny (zdarzenie submit, także formularze wysyłane przez fetch). Wartości pól nie są przesyłane — tylko nazwa formularza: #id, name lub ścieżka action. Wysłania przez boty nie są liczone. |
chat_messages | Wiadomości odwiedzających w czacie Webchatix (tekst i zdjęcia). |
chat_visitors | Ilu odwiedzających napisało w czacie — wg rozmów, w okresie bez powtórzeń. |
ads_google | Przejścia z Google Ads: w adresie strony wejścia jest gclid, gbraid, wbraid lub gad_source, albo utm_source=google z płatnym utm_medium (cpc, ppc, paid…). Liczone raz na wejście: odświeżenie strony nie podwaja kliknięcia. |
ads_yandex | Przejścia z Yandex Direct: w adresie jest yclid albo utm_source=yandex z płatnym utm_medium. Też raz na wejście. |
Zwykły snippet czatu już zbiera statystyki — nic nie trzeba dodawać.
Instalacja tylko do statystyk (bez interfejsu)
Atrybut data-mode="stats" instaluje widżet bez przycisku, okna czatu i stylów: skrypt wysyła tylko jeden lekki hit na stronę. Piksel w <noscript> jest opcjonalny — łapie boty, które nie wykonują JavaScriptu, ale pobierają obrazki.
<script async src="https://webchatix.online/widget/webchatix.js"
data-site-key="SITE_KEY" data-mode="stats"></script>
<noscript><img src="https://webchatix.online/wx-api.php?action=track&site_key=SITE_KEY"
width="1" height="1" alt="" style="position:absolute"></noscript>
SITE_KEY to publiczny klucz strony — ten sam co w snippecie czatu (bot: „📋 Kod instalacji”, panel: „Strony”). To nie jest klucz API wxs_…: ten jest tajny i nie trafia do kodu stron.
Jeśli strona ma ustawione Allowed origins, hity ze stron innych domen nie są liczone.
Formularze bez tagu <form>
Wysłanie zwykłego <form> widżet łapie sam — po zdarzeniu submit, także gdy strona wysyła go przez fetch. Często jednak formularz to pola i przycisk <button type="button">, a dane wysyła JavaScript strony; zdarzenia submit wtedy nie ma i wysłanie nie jest liczone. Dla takich formularzy są dwa sposoby.
1. Atrybut data-wx-form na przycisku wysyłania: kliknięcie liczy się jako wysłanie formularza o tej nazwie. Nieaktywny przycisk (disabled) nie jest liczony, podwójne kliknięcie daje jedno wysłanie.
<button type="button" class="get_report" data-wx-form="report">…</button>
2. Wywołanie z kodu strony — gdy wysłanie ma się liczyć np. dopiero po poprawnej walidacji pól. Działa ze zwykłym widżetem i z data-mode="stats". Jeśli Twój kod może wykonać się przed załadowaniem widżetu, dodaj wyżej zaślepkę — wywołania trafią do kolejki i nie zginą.
// po poprawnej walidacji pól
webchatix("form", "report");
// zaślepka — nad wywołaniami, jeśli kod może zadziałać przed widżetem
window.webchatix = window.webchatix || function () {
(webchatix.q = webchatix.q || []).push(arguments);
};
Atrybut data-wx-form na <form> lub na jej przycisku submit ustawia nazwę formularza w raporcie zamiast #id / name / action.
Klucz API
Klucz wxs_… jest jeden na całe konto. Gdzie go wziąć i wymienić: w bocie Telegram — przycisk 🔑 Klucz API w menu głównym (tam też podsumowanie wszystkich stron), w panelu — Strony → koło zębate. „Wymień klucz” wydaje nowy, stary przestaje działać od razu. Widzą i wymieniają go owner i admini konta.
Klucz jest tajny: publiczny site_key nie nadaje się do odczytu, a samego klucza nie wstawiaj do kodu stron — pobieraj statystyki ze swojego serwera. Statystyki jednej strony są też w bocie: 🌐 Strony → strona → 📊 Statystyki.
Klucz przekazuje się na jeden ze sposobów: nagłówek X-Stats-Key: wxs_…, nagłówek Authorization: Bearer wxs_… lub parametr ?key=wxs_….
Dwa klucze
| Klucz | Gdzie używany | Publiczny? |
|---|---|---|
SITE_KEY — klucz strony | snippet czatu, data-mode="stats", piksel wx-api.php?action=track — wszystko, co jest w kodzie stron i tylko zapisuje hity | tak |
wxs_… — klucz API konta | stats-api.php: odczyt statystyk (action=stats) i hity z serwera (action=hit) — tylko z Twojego serwera. Jeden dla wszystkich stron konta. | nie, tajny |
Klucz API w pikselu lub w kodzie strony zobaczy każdy odwiedzający przez „Pokaż źródło” — i będzie mógł czytać i zawyżać statystyki. Jeśli klucz wyciekł, wymień go.
GET /stats-api.php?action=stats
Parametry: site_key — tylko ta strona konta (bez niego — wszystkie strony); okres — days (ostatnie N dni do dziś, 1–366, domyślnie 7) albo from i to (daty RRRR-MM-DD włącznie, nie dłużej niż 366 dni; jeśli podano jedną datę, druga jest liczona o days dni); limit — ile stron w rankingu każdej witryny (1–1000, domyślnie 50).
curl -H "X-Stats-Key: wxs_…" "https://webchatix.online/stats-api.php?action=stats&days=7&limit=20"
curl -H "X-Stats-Key: wxs_…" "https://webchatix.online/stats-api.php?action=stats&site_key=SITE_KEY"
curl -H "X-Stats-Key: wxs_…" "https://webchatix.online/stats-api.php?action=stats&from=2026-01-01&to=2026-03-31"
{
"ok": true,
"account": {"id": 42, "name": "My company"},
"timezone": "UTC",
"from": "2026-10-12",
"to": "2026-10-18",
"totals": {"unique_visitors": 412, "visits": 530, "page_views": 1874, "bot_hits": 961,
"form_submits": 23, "chat_messages": 57, "chat_visitors": 14,
"ads_google": 48, "ads_yandex": 31},
"days": [
{"date": "2026-10-18", "unique_visitors": 61, "visits": 74, "page_views": 255, "bot_hits": 140,
"form_submits": 4, "chat_messages": 9, "chat_visitors": 3,
"ads_google": 6, "ads_yandex": 4}
],
"sites": [
{
"site_key": "SITE_KEY",
"name": "My site",
"totals": {"unique_visitors": 300, "visits": 391, "page_views": 1402, "bot_hits": 700,
"form_submits": 15, "chat_messages": 40, "chat_visitors": 9,
"ads_google": 35, "ads_yandex": 20},
"days": [ … ],
"pages": [{"path": "/pricing/", "page_views": 310, "bot_hits": 88, "form_submits": 6}],
"bots": [{"bot": "Googlebot", "hits": 402}, {"bot": "GPTBot", "hits": 97}],
"forms": [{"form": "#contact", "submits": 15}]
}
]
}
totals i days to suma po stronach w odpowiedzi; odwiedzający liczeni są osobno dla każdej strony. W sites jest raport każdej strony: days — wpis na każdą datę (dni bez odwiedzin mają zera), pages — ranking stron (ścieżka bez query) wg wyświetleń i odwiedzin botów, bots — odwiedziny wg nazw botów, forms — wysłania wg nazw formularzy.
POST /stats-api.php?action=hit — hity z serwera
Większość botów wyszukiwarek nie wykonuje JavaScriptu, więc widżet ich nie widzi. Aby je też liczyć, backend strony może sam zgłaszać przyjęte żądania: pola site_key (która strona konta; wymagane), url (lub ścieżka), ua — User-Agent, opcjonalne ip, referrer, visitor_id. Paczką — {"site_key": "…", "hits": [ … ]}, do 500 hitów na żądanie; site_key pojedynczego hitu zastępuje wspólny. Bot czy człowiek — rozstrzyga ua.
curl -X POST "https://webchatix.online/stats-api.php?action=hit" \
-H "X-Stats-Key: wxs_…" -H "Content-Type: application/json" \
-d '{"site_key": "SITE_KEY", "url": "https://example.com/pricing/", "ua": "Mozilla/5.0 (compatible; bingbot/2.0)", "ip": "203.0.113.7"}'
# → {"ok": true, "views": 0, "bots": 1, "skipped": 0}
Błędy
| HTTP | error | Przyczyna |
|---|---|---|
| 401 | key_required | Nie przekazano klucza. |
| 403 | invalid_key | Klucz jest błędny lub został wymieniony. |
| 403 | plan_required | Klucz API działa w planach Basic i Unlimited. |
| 403 | disabled | Konto jest zawieszone. |
| 400 | too_many_hits | Ponad 500 hitów w jednym żądaniu. |
| 400 | unknown_site | Brak site_key albo to strona innego konta. |
| 400 | bad_period | Zły okres: data nie w formacie RRRR-MM-DD, from później niż to lub okres dłuższy niż 366 dni. |
Przechowywane są tylko liczniki i zanonimizowane hashe odwiedzających — bez IP, adresów i User-Agentów w jawnej postaci.
Operatorzy i role
- owner — pełna kontrola, prośby o plan, usunięcie konta, CRM, przekazanie własności.
- admin — strony, zaproszenia, trasy, ustawienia.
- operator — odpowiedzi w rozmowach, notatki/szablony zależnie od planu.
Jeden użytkownik Telegrama = jedno własne konto. W cudzych kontach można być operatorem na zaproszenie.
Grupy
Operatorem może być nie tylko osoba, ale i grupa Telegram: zgłoszenie trafia kartą na czat, odpowiada dowolny uczestnik przez Reply. Podłączenie: dodaj bota do grupy (menu → 💬 Grupy → „Podłącz grupę”) albo wpisz w niej /addgroup — chat_id nie trzeba wpisywać, bot pobiera go sam. Grupy nie zajmują limitu operatorów w planie.
Rozmowy
- Wiadomość klienta idzie do Telegrama (grupa/operator według trasy).
- Przyjmij — claim; wiadomość systemowa w historii.
- Przekaż — tylko do aktywnego uczestnika tego samego konta.
- Zwolnij / release — można poprosić odwiedzającego o ocenę.
- Notatki — widoczne dla zespołu, nie dla klienta (od Basic).
- Szablony — reply na rozmowę +
/tpl idalbo przycisk szablonu → Reply.
Bezpieczeństwo i GDPR
- Konta są izolowane po
account_id. - Magic-link jest jednorazowy; liczba wydawanych linków jest limitowana.
- Suspend wyłącza widżet, bota i panel tenanta.
- CORS: ustaw allowed_origins (nie zostawiaj
*na produkcji bez potrzeby). - Checkbox GDPR — przed pierwszą wiadomością klienta.
- Limit uploadu zależny od planu (
max_upload_mb). - Nie więcej niż 10 nowych stron na godzinę na konto.