Webchatix documentation

Telegram-first live chat: the visitor writes into the website widget, your team answers from Telegram and the web dashboard. Sections on the left, details on the right.

In 5 minutes

  1. Open the bot → /start — an account on the Free plan and the first site are created.
  2. Copy the HTML snippet and paste it into your site before </body>.
  3. /panel — a one-time link into the web dashboard (or the “Web dashboard” menu item).
  4. Invite an operator: /invite or menu → “Team” → ➕.
  5. Connect a Telegram group: add the bot to the group (or run /addgroup there) and assign it to a site under Routes.
  6. Fallback for a whole site in one group: /bindsite site_key inside the group.

Plans and billing

Registration is open: /start in the bot creates an account on the Free plan. Paid plans are bought by card in the dashboard, section Billing — payment goes through Stripe.

PlanWebsitesClients / monthOperatorsPer month
free1301$0
basic2010005$10 ($8 paid yearly)
unlimited∞∞∞$20 ($16 paid yearly)

Prices are shown per month. Paying for a year is 20% cheaper and is charged as a single payment ($96 and $192 a year); yearly is preselected in the dashboard.

Premium (Basic and above): templates, active invite, visibility rules, notes, ratings.

A client is a unique visitor who started a chat in the current calendar month — the counter resets on the 1st.

How payment works

  • Dashboard → Billing: current plan, usage, plan switch, list of invoices with PDF links.
  • Card details never reach our servers — the payment page and the customer portal belong to Stripe.
  • Changing the plan mid-period is prorated by Stripe; cancelling keeps the paid plan until the end of the paid period, then the account returns to Free.
  • The email address in the same section receives the receipt, the failed-payment notice and a renewal reminder several days in advance.

Bot menu

The main menu after /start / /menu. Buttons usually come two per row.

ItemWhat it does
🌐 SitesThe account's site list: settings, Online/Offline, snippet, deletion.
👥 TeamOperators / members of the account.
➕ InviteCode and deep link for a new operator.
💬 GroupsTelegram groups that take requests: connect, assign to a site, disconnect.
🔗 Web dashboardMagic login link (single use, ~10 min).
🗺 RoutesWho receives dialogs from which site/page.
🔑 API keyThe account analytics API key, today's summary of all sites, key replacement (owner/admin).
⚙️ PanelQuick access: ops / sites / routes.
📝 TemplatesCanned replies (Basic and above).
💳 Plans and billingPrices, card payment, invoices (owner).
👑 OwnerHand ownership over to another member.
🗑 Delete accountCascade deletion after confirming by name.

Site card

  • Online / Offline — pause the widget (chat offline).
  • Settings — branding fields, invite, GDPR and so on (two buttons per row).
  • Operator — route this site to a person or a group.
  • Delete — confirmed by the site name.

Bot commands

CommandWhoMeaning
/start [CODE]everyoneOnboarding / redeem an invite.
/menumemberThe account main menu.
/helpeveryoneCommand reference for your role.
/panelmemberMagic link to the web dashboard.
/newsite [name | origin]admin+Create a site (+ CORS origins).
/addgroupadmin+ in a groupConnect the group as a group operator (no chat_id needed).
/bindsite KEYadmin+ in a groupBind the group as the fallback chat.
/inviteadmin+Operator invite.
/op_me CODEanyoneAccept an invite.
/tplmemberList / add / del / send with reply + /tpl id.
/notememberNote on a dialog (Basic and above).
/releasememberRelease a dialog (+ ask for a rating).
/langeveryoneBot interface language: en / pl / de / ru / uk / be / ar.
/setrole id roleownerowner|admin|operator.
/crm on|offownerTurn the account CRM bridge on/off.
/deleteaccountownerDelete the account.
/idin a chatShow chat_id.

Web dashboard

Tenant login: the link from /panel or a token on /account/login/.

SectionWhat for
OverviewCounters and recent dialogs; the company name; the CRM bridge for the owner — switch and webhook link (empty falls back to the one in config).
SitesCreation, snippet, full widget settings.
OperatorsMembers, invites, roles, groups.
RoutesAssignments: site → operator/group.
DialogsHistory, release, notes, rating.
AnalyticsVisits, bots, forms and chat for all sites or one; pages; analytics-only code; the account API key.
TemplatesTemplate CRUD + rating summary (Basic and above).

Site settings

Available in the bot (“Settings”) and in the web dashboard under Sites → gear icon.

FieldMeaning
Name / title / subtitleThe chat header.
Greeting / logoThe first message and the brand.
Online from–to, TZ, pauseThe Online/Offline status.
Escalation (min)Alert when there is no answer.
Colour / position / offsetsThe widget button.
Language / sounden|pl|de|ru|uk|be|ar and an mp3 URL.
Allowed originsCORS: comma-separated domains or *.
Invite *Bubble invitation (Basic and above).
Visibility JSONWhere to show the button/invite (Basic and above).
GDPRConsent checkbox before the first send.
AI responderAnswers the visitor when nobody replied for N minutes (3 by default).

AI responder (Gemini)

The visitor wrote, the operator is silent — after the configured number of minutes Google Gemini answers in the chat. The visitor sees the reply in the widget, and operators get an “AI replied” card in Telegram with the same text, so nobody repeats it.

  • Enabled per site: Sites → gear → AI responder. The same block holds the delay and the “what the AI should know” field — opening hours, delivery, what must not be promised.
  • A human reply resets the timer; a conversation an operator has claimed is left alone.
  • An AI answer does not cancel escalation: the admin is still alerted that no human replied.
  • The model keeps answers short, never invents prices or dates, and admits to being an automated assistant when asked directly.
  • The API key is set once per installation: gemini_api_key in config/config.php (take it in Google AI Studio, it has a free tier). Without the key the checkbox does nothing.

Visibility example

{"include":["/pricing","/contacts"],"exclude":["/admin"],"desktop":true,"mobile":true}

Website widget

<script async src="https://webchatix.online/widget/webchatix.js"
  data-site-key="SITE_KEY"></script>

Control from the page:

webchatix("show");   // show the button
webchatix("hide");   // hide it
webchatix("open");   // open the chat
webchatix("close");  // close the panel
webchatix("form", "report"); // count a form submission (analytics)

The widget language follows data-lang, then the page <html lang>, then the browser; en / pl / de / ru / uk / be / ar are supported, with English as the fallback. After changing the settings, reload the client page (the widget version sits in the ?v= query).

If your site sets a Content-Security-Policy, allow the widget domain in three directives: script-src, style-src and connect-src. The widget loads its styling from a separate webchatix.css file, so you do not need to keep 'unsafe-inline' in style-src for it.

Visit analytics and API

The widget counts visits to the site it is installed on. Analytics is kept with no time limit as daily counters (days in UTC); a report can cover any period. The numbers are available through an API with the secret account key — one key opens all sites of the account.

FieldWhat is counted
unique_visitorsUnique visitors — by the widget cookie (without a cookie — by IP + browser per day). Across a period there are no repeats: one person over a week counts once.
visitsEntries — the first page after 30 minutes of inactivity, plus a visitor's first page of the day.
page_viewsPage views by people, including SPA navigation (history.pushState).
bot_hitsPages crawled by bots: search engines (Googlebot, Bingbot, YandexBot…), AI crawlers (GPTBot, ClaudeBot, PerplexityBot…), social networks, SEO tools, headless browsers. They are not included in views or unique visitors.
form_submitsForm submissions on the site pages (the submit event, including forms the site sends via fetch). Field values are not sent — only the form name: #id, name or the action path. Submissions by bots are not counted.
chat_messagesVisitor messages in the Webchatix chat (text and photos).
chat_visitorsHow many visitors wrote in the chat — by conversation, without repeats across the period.
ads_googleClicks from Google Ads: the landing page URL has gclid, gbraid, wbraid or gad_source, or utm_source=google with a paid utm_medium (cpc, ppc, paid…). Counted once per entry: reloading the page does not double the click.
ads_yandexClicks from Yandex Direct: the URL has yclid, or utm_source=yandex with a paid utm_medium. Also once per entry.

The regular chat snippet already collects analytics — nothing to add.

Analytics-only install (no UI)

The data-mode="stats" attribute installs the widget without the button, chat window or styles: the script only sends one lightweight hit per page. The <noscript> pixel is optional — it catches bots that do not run JavaScript but do load images.

<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 is the public site key — the same one as in the chat snippet (bot: “📋 Install code”, dashboard: “Sites”). It is not the wxs_… API key: that one is secret and never goes into page code.

If the site has Allowed origins set, hits from pages on other domains are not counted.

Forms without a <form> tag

The widget catches a regular <form> by itself — via the submit event, including forms the site sends via fetch. But a form is often just fields plus a <button type="button">, with the site's JavaScript sending the data; there is no submit event then, and the submission is not counted. There are two ways to handle such forms.

1. The data-wx-form attribute on the submit button: a click on it counts as a submission of the form with that name. A disabled button is not counted, and a double click gives one submission.

<button type="button" class="get_report" data-wx-form="report">…</button>

2. A call from your site's code — when a submission should count, for example, only after the fields pass validation. It works with the regular widget and with data-mode="stats". If your code can run before the widget loads, add the stub above it — the calls are queued and not lost.

// after the fields pass validation
webchatix("form", "report");

// stub — above the calls, if your code may run before the widget
window.webchatix = window.webchatix || function () {
  (webchatix.q = webchatix.q || []).push(arguments);
};

The data-wx-form attribute on a <form> or on its submit button sets the form name in the report instead of #id / name / action.

API key

The wxs_… key is one per account. Where to get and replace it: in the Telegram bot — the 🔑 API key button in the main menu (with a summary of all sites); in the dashboard — Sites → gear icon. “Replace key” issues a new one and the old key stops working immediately. The account owner and admins can see and replace it.

The key is secret: the public site_key cannot be used for reading, and the key itself must not go into page code — request analytics from your server. One site's analytics is also in the bot: 🌐 Sites → site → 📊 Analytics.

Pass the key in one of three ways: the X-Stats-Key: wxs_… header, the Authorization: Bearer wxs_… header, or the ?key=wxs_… parameter.

Two keys

KeyWhere it is usedPublic?
SITE_KEY — site keychat snippet, data-mode="stats", the wx-api.php?action=track pixel — everything that sits in page code and only writes hitsyes
wxs_… — account API keystats-api.php: reading analytics (action=stats) and server-side hits (action=hit) — from your server only. One for all sites of the account.no, secret

An API key in the pixel or page code is visible to any visitor via “View source” — they could read and inflate your analytics. If the key has leaked, replace it.

GET /stats-api.php?action=stats

Parameters: site_key — only this site of the account (without it — all sites); the period — days (the last N days up to today, 1–366, default 7) or from and to (YYYY-MM-DD dates, inclusive, at most 366 days; if only one date is given, the other is counted days away); limit — how many pages in each site's top list (1–1000, default 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 and days are the sum over the sites in the response; visitors are counted per site. sites holds each site's report: days has one entry per date (days without visits come with zeros), pages is the top pages (path without the query string) by views plus crawls, bots is crawls per bot name, forms is submissions per form name.

POST /stats-api.php?action=hit — server-side hits

Most search bots do not run JavaScript, so the widget does not see them. To count them as well, your site backend can report the requests it receives: fields site_key (which site of the account; required), url (or a path), ua — the User-Agent, optional ip, referrer, visitor_id. Batch: {"site_key": "…", "hits": [ … ]}, up to 500 hits per request; a hit's own site_key overrides the shared one. Bot or human is decided by 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}

Errors

HTTPerrorReason
401key_requiredNo key was passed.
403invalid_keyThe key is wrong or has been replaced.
403plan_requiredThe API key works on the Basic and Unlimited plans.
403disabledThe account is suspended.
400too_many_hitsMore than 500 hits in one request.
400unknown_sitesite_key is missing or belongs to another account.
400bad_periodBad period: a date is not YYYY-MM-DD, from is after to, or the period is longer than 366 days.

Only counters and anonymised visitor hashes are stored — no IPs, addresses or User-Agents in plain form.

Operators and roles

  • owner — full control, plan requests, account deletion, CRM, ownership transfer.
  • admin — sites, invites, routes, settings.
  • operator — answers in dialogs, notes/templates depending on the plan.

One Telegram user = one owned account. In other people's accounts you can be an operator by invitation.

Groups

Besides people, a Telegram group can be an operator: requests arrive as a card in the chat and anyone in the group answers by replying to it. To connect one, add the bot to the group (menu → 💬 Groups → “Connect a group”) or run /addgroup inside it — no chat_id to type, the bot reads it itself. Groups do not count against the plan's operator limit.

Dialogs

  • The customer message goes to Telegram (group/operator according to the route).
  • Claim — takes the dialog; a system message lands in the history.
  • Transfer — only to an active member of the same account.
  • Release — you can ask the visitor for a rating.
  • Notes — visible to the team, not to the customer (Basic and above).
  • Templates — reply to the dialog plus /tpl id, or the template button → Reply.

Security and GDPR

  • Accounts are isolated by account_id.
  • The magic link is single use; link issuing is rate limited.
  • Suspend switches off the widget, the bot and the tenant dashboard.
  • CORS: set allowed_origins (do not leave * in production without a reason).
  • The GDPR checkbox comes before the customer's first message.
  • Upload quota depends on the plan (max_upload_mb).
  • No more than 10 new sites per hour per account.