Before you start
Every integration talks to a Chatting App - one per website or mobile app. Ask your Connectly workspace admin to create one (Desk → Chatting App) and send you:
كل تكامل يتصل بـ تطبيق محادثة (Chatting App) - واحد لكل موقع أو تطبيق جوال. اطلب من مسؤول مساحة عمل Connectly إنشاء واحد (Desk ← Chatting App) وإرسال ما يلي إليك:
- Public key (
pk_…) - identifies your app. Safe to ship in a web page or app binary. - Secret key - only if you sign in your own users (see Identified visitors). Keep it on your server, never in the client.
- Server URL -
https://connectly.wowdigital.sa(used for both the API and the realtime connection).
- المفتاح العام (
pk_…) - يعرّف تطبيقك. آمن لتضمينه في صفحة ويب أو تطبيق. - المفتاح السري - فقط إذا كنت تربط المحادثة بمستخدميك المسجّلين (انظر الزوار المعرّفون). احتفظ به على خادمك فقط، وليس في التطبيق أبداً.
- عنوان الخادم -
https://connectly.wowdigital.sa(يُستخدم للواجهة البرمجية والاتصال اللحظي معاً).
https://www.your-site.com). Ask for your production and staging addresses to be added.https://www.your-site.com). اطلب إضافة عناوين موقعك الفعلي وموقع الاختبار.Installation
Add one script tag to your page. No build step or package manager needed.
أضف وسم script واحداً إلى صفحتك. لا حاجة لأدوات بناء أو مدير حزم.
<script src="https://connectly.wowdigital.sa/assets/connectly/chatting-sdk/connectly-chat.js"></script>socket.io-client by itself. If your page already includes socket.io-client v4, that copy is used.socket.io-client تلقائياً. وإذا كانت صفحتك تتضمن socket.io-client الإصدار 4 فستُستخدم تلك النسخة.Show the chat
ConnectlyChatWidget is a complete chat: messages, images, files, voice notes, typing indicator and the "talk to a human" flow. Add a wrapper element to your page and mount the chat into it - it fills the element.
ConnectlyChatWidget محادثة كاملة: الرسائل والصور والملفات والرسائل الصوتية ومؤشر الكتابة وخيار "التحدث مع موظف". أضف عنصراً حاوياً إلى صفحتك وضع المحادثة بداخله - وستملأ العنصر بالكامل.
<div id="support-chat" style="height: 600px"></div>
<script src="https://connectly.wowdigital.sa/assets/connectly/chatting-sdk/connectly-chat.js"></script>
<script>
const widget = ConnectlyChatWidget.mount({
publicKey: "pk_xxx",
container: "support-chat", // the wrapper element's id
title: "Support",
});
</script>container can also be a CSS selector or the element itself.container محدِّد CSS أو العنصر نفسه أيضاً.Floating chat button
Leave out container to get a round chat button in the corner of the page instead. It opens the chat above it (full screen on phones) and shows a badge for unread replies. It connects only when the visitor first opens it.
احذف container لتحصل بدلاً من ذلك على زر محادثة دائري في زاوية الصفحة. يفتح المحادثة فوقه (بملء الشاشة على الجوال) ويعرض عدد الردود غير المقروءة. ولا يتصل إلا عندما يفتحه الزائر أول مرة.
const widget = ConnectlyChatWidget.mount({
publicKey: "pk_xxx",
position: "right", // or "left"
startOpen: false,
});
widget.open(); // open the chat from your own "Contact us" button
widget.close(); // minimise it - the conversation continues
widget.destroy(); // remove it and end the conversationapiBaseUrl and wsUrl default to the server the script is loaded from (https://connectly.wowdigital.sa). Set them only if you host connectly-chat.js yourself.apiBaseUrl وwsUrl تساويان افتراضياً الخادم الذي حُمّل منه السكربت (https://connectly.wowdigital.sa). حدّدهما فقط إذا كنت تستضيف connectly-chat.js بنفسك.Customize
Match your brand with theme, and switch features or change any text with options. Pass only what you want to change. The names are the same as the Flutter SDK's ConnectlyChatTheme and ConnectlyChatOptions; times are in milliseconds.
طابق هوية علامتك عبر theme، وفعّل الميزات أو غيّر أي نص عبر options. مرّر فقط ما تريد تغييره. الأسماء نفسها المستخدمة في ConnectlyChatTheme وConnectlyChatOptions في حزمة Flutter؛ والأوقات بالملي ثانية.
ConnectlyChatWidget.mount({
publicKey: "pk_xxx",
container: "support-chat",
theme: {
primaryColor: "#16A34A",
headerBackgroundColor: "#16A34A",
visitorBubbleColor: "#16A34A",
backgroundImage: "https://www.your-site.com/chat-bg.png",
bubbleBorderRadius: 16,
},
options: {
enableAttachments: true,
enableVoiceRecording: false,
enableTalkToHuman: true,
welcomeMessage: "Hi! How can we help you today?",
inputPlaceholder: "Type a message...",
},
});Options
| Optionالخيار | Defaultالافتراضي | Descriptionالوصف |
|---|---|---|
enableAttachments | true | Attach files and imagesإرفاق الملفات والصور |
enableVoiceRecording | true | Record voice messages (shown on HTTPS pages, in browsers that can record)تسجيل رسائل صوتية (يظهر في صفحات HTTPS وفي المتصفحات التي تدعم التسجيل) |
enableTalkToHuman | true | Show "Talk to a human" in the chatإظهار "التحدث مع موظف" داخل المحادثة |
enableTypingIndicator | true | Animated dots while the other side typesنقاط متحركة أثناء كتابة الطرف الآخر |
enableSounds | true | A soft chime when a message arrivesتنبيه صوتي خفيف عند وصول رسالة |
allowedFileExtensions | png, jpg, jpeg, gif, webp, pdf, doc, docx, txt | Pickable file typesأنواع الملفات المسموحة |
maxFileSizeBytes | 10485760 (10 MB) | Largest attachmentأكبر حجم للمرفق |
maxRecordingDuration | 120000 (2 min) | Longest voice note, in millisecondsأطول رسالة صوتية، بالملي ثانية |
messageCharacterLimit | 2000 | Longest text message (0 = no limit)أطول رسالة نصية (0 = بلا حد) |
typingThrottle | 2000 | How often "typing" is sent while the visitor types, in millisecondsمعدل إرسال إشارة "يكتب" أثناء كتابة الزائر، بالملي ثانية |
resumeInterruptedChatWithin | 1800000 (30 min) | If the page is reloaded or closed while the chat is open, coming back within this time continues the same chat (0 = off)إذا أُعيد تحميل الصفحة أو أُغلقت أثناء فتح المحادثة، تُستكمل نفس المحادثة عند العودة خلال هذه المدة (0 = إيقاف) |
direction | "auto" | "ltr", "rtl", or "auto" to follow the page's <html dir>"ltr" أو "rtl" أو "auto" لاتباع <html dir> في الصفحة |
welcomeMessage, inputPlaceholder, …Label | English textنصوص إنجليزية | Every visible text can be replaced - e.g. with your translations (see below)يمكن استبدال كل نص ظاهر - بترجماتك مثلاً (انظر أدناه) |
Theme
| Propertyالخاصية | Defaultالافتراضي | Descriptionالوصف |
|---|---|---|
primaryColor | #4F46E5 | Send button, chat button, highlightsزر الإرسال وزر المحادثة والعناصر المميزة |
backgroundColor | #F3F4F6 | Behind the messagesخلفية منطقة الرسائل |
backgroundImage | null | Image behind the messages: a URL, or { url, fit, opacity } with fit "cover", "contain" or "repeat"صورة خلف الرسائل: رابط، أو { url, fit, opacity } حيث fit هي "cover" أو "contain" أو "repeat" |
visitorBubbleColor / visitorTextColor | #4F46E5 / #FFFFFF | The visitor's own messagesرسائل الزائر نفسه |
otherBubbleColor / otherTextColor | #F1F1F4 / rgba(0,0,0,.87) | Messages from the AI and agentsرسائل المساعد الذكي والموظفين |
bubbleBorderRadius | 16 | Bubble corners: pixels, or any CSS value like "16px 16px 4px 16px"زوايا الفقاعات: بالبكسل، أو أي قيمة CSS مثل "16px 16px 4px 16px" |
headerBackgroundColor / headerTextColor | #4F46E5 / #FFFFFF | The title barشريط العنوان |
messageTextStyle / timestampTextStyle | null | CSS properties, e.g. { fontSize: "15px" }خصائص CSS، مثل { fontSize: "15px" } |
fontFamily | System fontsخطوط النظام | Font of the whole chatخط المحادثة بالكامل |
composerBackgroundColor / inputTextColor | #FFFFFF / #111827 | The message box areaمنطقة مربع الكتابة |
Texts and Arabic
Every text the chat shows is an option: title, welcomeMessage, inputPlaceholder, talkToHumanLabel, talkToHumanHint, connectingLabel, onlineLabel, waitingForAgentLabel, agentConnectedLabel, agentLeftLabel, connectionLostLabel, connectErrorLabel, retryLabel, rateLimitedLabel, notSentLabel, fileTooLargeLabel, fileTypeNotAllowedLabel, microphonePermissionLabel, recordingLabel, recordingTooShortLabel, loadMessagesFailedLabel, attachmentLabel. {seconds}, {size} and {max} in a text are replaced with the actual value.
كل نص تعرضه المحادثة هو خيار: title, welcomeMessage, inputPlaceholder, talkToHumanLabel, talkToHumanHint, connectingLabel, onlineLabel, waitingForAgentLabel, agentConnectedLabel, agentLeftLabel, connectionLostLabel, connectErrorLabel, retryLabel, rateLimitedLabel, notSentLabel, fileTooLargeLabel, fileTypeNotAllowedLabel, microphonePermissionLabel, recordingLabel, recordingTooShortLabel, loadMessagesFailedLabel, attachmentLabel. وتُستبدل {seconds} و{size} و{max} داخل النص بالقيمة الفعلية.
ConnectlyChatWidget.mount({
publicKey: "pk_xxx",
container: "support-chat",
title: "تواصل معنا",
options: {
direction: "rtl",
welcomeMessage: "أهلاً بك! كيف نقدر نساعدك؟",
inputPlaceholder: "اكتب رسالتك...",
onlineLabel: "متصل",
connectingLabel: "جارٍ الاتصال...",
talkToHumanHint: "تحتاج موظفاً؟",
talkToHumanLabel: "التحدث مع موظف",
waitingForAgentLabel: "جارٍ تحويلك إلى موظف...",
agentConnectedLabel: "أنت الآن تتحدث مع موظف",
agentLeftLabel: "غادر الموظف المحادثة. المساعد الذكي عاد لمساعدتك.",
notSentLabel: "لم تُرسل. اضغط لإعادة المحاولة",
rateLimitedLabel: "أنت ترسل بسرعة كبيرة. حاول بعد {seconds} ثانية.",
retryLabel: "إعادة المحاولة",
},
});Callbacks
Hook into the chat without building your own UI:
تابع أحداث المحادثة دون بناء واجهتك الخاصة:
ConnectlyChatWidget.mount({
publicKey: "pk_xxx",
container: "support-chat",
onChatStarted: (chatId) => localStorage.setItem("my_chat_id", chatId), // keep it to resume later
onMessageReceived: (m) => console.log(m.role, m.content),
onMessageSend: (m) => analytics.track("chat_send", { type: m.type }),
onMessageStatusChanged: (m) => console.log(m.id, m.status), // "sent" or "failed"
onClose: () => console.log("chat closed"),
});Messages have the same fields as in Custom UI: id, role, type, content, file, timestamp and status.
للرسائل نفس الحقول الموضحة في واجهة مخصصة: id وrole وtype وcontent وfile وtimestamp وstatus.
Conversations
Each time the widget is mounted a new conversation starts. If the visitor reloads the page (or leaves and comes back) while a chat is open, it continues within resumeInterruptedChatWithin. Minimising the floating chat never ends it; destroy() does. To continue a specific conversation, save the id from onChatStarted and pass it back as chatId - its earlier messages load automatically.
في كل مرة تُضاف فيها الواجهة تبدأ محادثة جديدة. وإذا أعاد الزائر تحميل الصفحة (أو غادرها ثم عاد) أثناء فتح المحادثة فإنها تُستكمل خلال مدة resumeInterruptedChatWithin. تصغير المحادثة العائمة لا ينهيها؛ أما destroy() فينهيها. لاستكمال محادثة بعينها، احفظ المعرّف من onChatStarted ومرّره مجدداً في chatId - وتُحمّل رسائلها السابقة تلقائياً.
// Open the conversation the visitor had before (null = start a new one):
ConnectlyChatWidget.mount({
publicKey: "pk_xxx",
container: "support-chat",
chatId: localStorage.getItem("my_chat_id"),
onChatStarted: (chatId) => localStorage.setItem("my_chat_id", chatId),
});Identified visitors
Signed-in users can be linked to their account, so agents see who they're talking to and the user's chats follow them across devices. Your backend signs a short-lived token with the app's secret key - never the browser.
يمكن ربط المستخدمين المسجّلين بحساباتهم، فيرى الموظفون من يحادثون وتتبع محادثات المستخدم بين أجهزته. خادمك هو من يوقّع رمزاً قصير الأجل بالمفتاح السري للتطبيق - وليس المتصفح أبداً.
// In the browser - get a short-lived token from YOUR backend, then pass it in:
const { identify_token } = await fetch("/api/chat-token").then((r) => r.json());
ConnectlyChatWidget.mount({
publicKey: "pk_xxx",
container: "support-chat",
identifyToken: identify_token,
});| Claimالحقل | Requiredإلزامي | Purposeالغرض |
|---|---|---|
user_id | Yesنعم | Your user's idمعرّف المستخدم لديك |
exp | Yesنعم | Expiry (Unix time) - keep it short, e.g. 5 minutesوقت الانتهاء (Unix) - اجعله قصيراً، مثل 5 دقائق |
name, email, phone | Noلا | Shown to agentsتظهر للموظفين |
Signed with HS256 using the Chatting App's secret key:
يُوقّع بخوارزمية HS256 باستخدام المفتاح السري لتطبيق المحادثة:
const jwt = require("jsonwebtoken");
app.get("/api/chat-token", requireLogin, (req, res) => {
const token = jwt.sign(
{ user_id: req.user.id, name: req.user.name, email: req.user.email },
process.env.CONNECTLY_SECRET_KEY,
{ algorithm: "HS256", expiresIn: "5m" }
);
res.json({ identify_token: token });
});import time, jwt # PyJWT
@app.get("/api/chat-token")
def chat_token(user=Depends(require_login)):
token = jwt.encode(
{"user_id": user.id, "name": user.name, "email": user.email,
"exp": int(time.time()) + 300},
CONNECTLY_SECRET_KEY,
algorithm="HS256",
)
return {"identify_token": token}Built-in behavior
- Instant messages: messages appear right away with 🕓, then ✓ - or "Not sent, tap to retry". Retries are never delivered twice.
- Files and voice notes: images show in the chat, documents open in a new tab, and voice notes - recorded right in the browser - play inline. While the AI reads an upload, the typing dots show.
- Silent reconnecting: if the connection drops (laptop sleep, tab in the background, network change), the chat returns to the same conversation and loads anything missed. A Retry bar appears only if that fails.
- Human handoff: "Talk to a human" sits above the message box, shows a waiting line once asked, and hides while an agent is in the chat.
- Limits: up to 15 messages per minute per visitor; past that the message shows "Not sent" with how long to wait.
- Your styles stay yours: the chat is isolated (Shadow DOM) - your page's CSS doesn't change it, and it doesn't change your page.
- Footer: the chat shows a small "Powered by Connectly" line under the message box.
- رسائل فورية: تظهر الرسالة فوراً مع 🕓 ثم ✓ - أو "لم تُرسل، اضغط لإعادة المحاولة". لا تُسلّم إعادة المحاولة مرتين أبداً.
- الملفات والرسائل الصوتية: تظهر الصور داخل المحادثة، وتُفتح المستندات في تبويب جديد، وتُشغَّل الرسائل الصوتية - المسجّلة من المتصفح مباشرة - داخل المحادثة. وأثناء قراءة المساعد للمرفق تظهر نقاط الكتابة.
- إعادة اتصال صامتة: إذا انقطع الاتصال (سكون الجهاز، تبويب في الخلفية، تغيّر الشبكة) تعود المحادثة لنفس الجلسة وتُحمّل ما فات. ولا يظهر شريط إعادة المحاولة إلا إذا فشل ذلك.
- التحويل إلى موظف: يظهر "التحدث مع موظف" فوق مربع الكتابة، ثم سطر انتظار بعد الطلب، ويختفي أثناء وجود موظف في المحادثة.
- الحدود: حتى 15 رسالة في الدقيقة لكل زائر؛ بعدها تظهر "لم تُرسل" مع مدة الانتظار.
- تنسيقاتك تبقى كما هي: المحادثة معزولة (Shadow DOM) - لا تؤثر تنسيقات CSS في صفحتك عليها، ولا تؤثر هي على صفحتك.
- التذييل: تعرض المحادثة سطراً صغيراً "Powered by Connectly" أسفل مربع الكتابة.
API reference
ConnectlyChatWidget.mount(config)
| Optionالخيار | Descriptionالوصف |
|---|---|
publicKey | Required. The Chatting App's public keyإلزامي. المفتاح العام لتطبيق المحادثة |
container | Wrapper element id, CSS selector or element to fill. Omit for a floating chat buttonمعرّف العنصر الحاوي أو محدِّد CSS أو العنصر نفسه. احذفه لزر محادثة عائم |
title | Header title (default "Chat with us")عنوان الشريط العلوي (الافتراضي "Chat with us") |
theme | Colors and look - see Customizeالألوان والمظهر - انظر التخصيص |
options | Features, limits and texts - see Customizeالميزات والحدود والنصوص - انظر التخصيص |
identifyToken | Token from your backend for a signed-in userرمز من خادمك لمستخدم مسجّل |
chatId | Resume this conversationاستكمال هذه المحادثة |
position, startOpen | Floating button only: "right" or "left" corner; open right awayللزر العائم فقط: الزاوية "right" أو "left"؛ والفتح مباشرة |
onChatStarted, onMessageReceived, onMessageSend, onMessageStatusChanged, onClose | See Callbacksانظر الاستدعاءات |
apiBaseUrl, wsUrl | Only if you host the script yourself - default to the server it's loaded fromفقط إذا كنت تستضيف السكربت بنفسك - افتراضياً الخادم الذي حُمّل منه |
| Methodالدالة | Descriptionالوصف |
|---|---|
open() | Opens the floating chatيفتح المحادثة العائمة |
close() | Minimises the floating chat (the conversation continues)يصغّر المحادثة العائمة (تستمر المحادثة) |
toggle() | Opens or closes itيفتحها أو يغلقها |
destroy() | Removes the chat and ends the conversationيزيل المحادثة وينهيها |
client | The ConnectlyChat it runs on - for listening to its eventsكائن ConnectlyChat الذي تعمل عليه - للاستماع إلى أحداثه |