ویجت سایت

ویجت یعنی گفت‌وگوی ربات شما مستقیماً روی سایتتان: دکمه‌ای گرد در گوشهٔ صفحه که با آن مکالمه باز می‌شود. برای بازدیدکننده یک راه ارتباطی دیگر است؛ برای ربات کانالی عادی — با همان واکنش‌ها و همان گفت‌وگوهای اپراتور که در پیام‌رسان‌ها هست. مرور چندکاناله بودن در صفحهٔ کانال‌ها.

نصب یعنی چسباندن یک تکه کد در قالب سایت. باقی همه چیز در پنل تنظیم می‌شود و بدون دست‌زدن دوباره به سایت اعمال می‌گردد.

کد نصب را از کجا بگیریم

در پنل ویجت ← بلوک نصب روی سایت ← فیلد کد برای درج را باز کنید. دکمهٔ کپی کل تکه را در کلیپ‌بورد می‌گذارد.

کد چنین است، با کلید خودتان به‌جای سه‌نقطه:

<script>
  window.mybot = { key: "eu-1a2b3c4d-..." };
</script>
<script async src="https://getmybot.dev/loader.js"></script>

اگر به‌جای کد نوشته شده باشد که هنوز برای این ربات کلید نصب صادر نشده است، یعنی کانال ویجت وصل نیست. با پشتیبانی تماس بگیرید: کلید هنگام وصل‌کردن کانال صادر می‌شود.

زیر کد راهنمایی هست که ویجت به کدام میزبان وصل می‌شود. اگر سایت شما CSP (سیاست امنیت محتوا) دارد، به آن میزبان اجازهٔ بارگذاری اسکریپت و درخواست شبکه بدهید، وگرنه مرورگر بی‌صدا ویجت را مسدود می‌کند.

کد را کجا بگذاریم

این تکه در HTML هر صفحه‌ای می‌رود که ویجت باید در آن دیده شود. در عمل یعنی یک بار در قالب مشترک سایت: فوتر، فیلد «کد پیش از </body>» در CMS، یا کانتینری در تگ‌منیجر.

قواعد کوتاه‌اند:

  • بهترین جا درست پیش از </body> پایانی است. در <head> هم کار می‌کند، اما آنگاه مرورگر پیش از محتوای شما وقت صرف ویجت می‌کند.
  • ترتیب دو تگ مهم است: اولی کلید را تعیین می‌کند، دومی ویجت را بار می‌کند. جابه‌جایشان نکنید و در صفحه پراکنده‌شان نکنید.
  • تگ دوم async دارد و رندر را متوقف نمی‌کند. این ویژگی را برندارید.
  • هر صفحه یک تکه. دو نسخه یعنی دو بار تلاش برای راه‌اندازی.

بعد از آن، بارگذار خودش تشخیص می‌دهد ربات شما از کدام مرکز داده سرویس می‌گیرد و بدنهٔ ویجت را از همان‌جا می‌آورد. برای این کار از شما چیزی لازم نیست.

کلید نصب عمومی است

کلید در تگ نخست شناسهٔ عمومی ربات است، نه گذرواژه. در سورس صفحه قرار دارد: هر بازدیدکننده‌ای می‌تواند «نمایش سورس صفحه» را باز کند و ببیندش. هر ویجت گفت‌وگویی همین‌طور کار می‌کند و طبیعی است.

آنچه باید بدانید:

  • با این کلید نمی‌توان وارد پنل شد، گفت‌وگوهای دیگران را خواند، پایگاه مشترکان را برون‌بری کرد یا چیزی در ربات تغییر داد. تنها یک امکان می‌گشاید: آغاز مکالمه‌ای تازه با همین ربات.
  • کلید را رازآلود نبینید: پنهان‌کردن یا مبهم‌سازی‌اش سودی ندارد.
  • اگر لازم شد کلید عوض شود (مثلاً پس از پایان همکاری با پیمانکار)، پشتیبانی این کار را می‌کند. پس از تعویض، کد قدیمی روی سایت از کار می‌افتد و باید به‌روزرسانی شود.

فهرست دامنه‌های مجاز

ویجت فهرست دامنه‌های مجاز (origin allowlist) دارد — نشانی سایت‌هایی که ویجت اجازه دارد از آن‌ها کار کند. این فهرست هنگام وصل‌کردن کانال تعیین می‌شود و بعداً بدون صدور دوبارهٔ کلید تغییر می‌کند: کد روی سایت شما همان می‌ماند.

هر مدخل یک origin است: طرح، میزبان و در صورت غیراستاندارد بودن، درگاه.

https://example.com
https://www.example.com
https://shop.example.com
http://localhost:3000

تطبیق دقیق و نویسه‌به‌نویسه است:

  • نشانهٔ عام وجود ندارد. https://*.example.com کار نمی‌کند — زیردامنه‌ها را جداگانه بنویسید.
  • example.com و www.example.com دو مدخل متفاوت‌اند. اگر سایت با هر دو باز می‌شود، هر دو را بیفزایید.
  • http:// و https:// هم دو مدخل جداگانه‌اند. معمولاً فقط https:// لازم است، اما محیط آزمایشی روی http:// را باید صریحاً افزود.
  • مسیر پذیرفته نیست: https://example.com/shop رد می‌شود؛ origin فقط نشانی سایت است.

اگر دامنهٔ واقعی شما در فهرست نباشد، ویجت راه نمی‌افتد. مرورگر بازدیدکننده پاسخ رد «origin not allowed» می‌گیرد و گفت‌وگو اصلاً باز نمی‌شود. این معمولاً پس از کوچ به دامنهٔ تازه، افزودن زیردامنه یا راه‌اندازی نسخهٔ زبانی دوم روی نشانی جداگانه پیش می‌آید — هرکدام مدخل خودش را می‌خواهد.

اگر فهرست خالی باشد هیچ محدودیتی نیست و ویجت از هر سایتی کار می‌کند. این را «هنوز پیکربندی نشده» بدانید، نه گشودگی عمدی: به‌محض آنکه دامنه‌هایتان را دانستید، واردشان کنید.

این محدودیت چه می‌کند و چه نمی‌کند

می‌کند: سایت دیگری نمی‌تواند ویجت شما را در خود جاسازی کند. وگرنه کسی می‌توانست کد را در صفحهٔ خود کپی کند و مرورگر بازدیدکنندگان واقعی محتوای مکالمه با ربات شما را به آن سایت تحویل دهد. فهرست دقیقاً همین را می‌بندد.

نمی‌کند: این محافظت در برابر کسی نیست که کلید را کپی کرده و مستقیماً به پلتفرم درخواست می‌فرستد — نه از مرورگر بلکه مثلاً با اسکریپت. سرایندی که نشانی سایت را حمل می‌کند مرورگر می‌گذارد؛ برنامه‌ای بیرون از مرورگر می‌تواند آن را نفرستد یا هرچه بخواهد بفرستد. پس فهرست را محدودیت جاسازی بدانید، نه مرز امنیتی. آنچه از سوءاستفاده جلوگیری می‌کند محدودیت نرخ درخواست و نظارت بر گفت‌وگوها در سمت پلتفرم است، نه این فهرست.

ظاهر

در ویجتظاهر این‌ها تنظیم می‌شوند:

  • موقعیت — دکمه در گوشهٔ پایین چپ یا راست.
  • رنگ تأکید — رنگ دکمه و عناصر گفت‌وگو. رنگ برند خود را بگذارید تا ویجت بیگانه ننماید.
  • نام گفت‌وگو — نوشتهٔ روی دکمهٔ راه‌انداز و عنوان پنل گفت‌وگو. معمولاً نام شرکت یا نامی که ربات خود را با آن معرفی می‌کند.

کنارش پیش‌نمایش هست — ویجتی زنده که نتیجه را پیش از ذخیره نشان می‌دهد.

ویجت هنوز پیام خوشامد ندارد: همین سه تنظیم است و بس. پیام نخست را ربات در پاسخ به بازدیدکننده و طبق قواعد معمول واکنش‌های شما می‌فرستد.

تغییرها خودبه‌خود به سایت می‌رسند: ویجت هنگام بارگذاری صفحه تنظیمات را می‌خواند و کد چسبانده‌شده هرگز نیاز به ویرایش ندارد.

بازدیدکنندگان ناشناس‌اند

بازدیدکننده برای نوشتن چیزی پر نمی‌کند. در نخستین اجرا ویجت از پلتفرم شناسهٔ ناشناس بازدیدکننده می‌گیرد و در مرورگر نگه می‌دارد تا هنگام بازگشت، شخص مکالمهٔ پیشین خود را ببیند نه گفت‌وگویی خالی.

از این نتیجه می‌شود:

  • در گفت‌وگوها چنین بازدیدکننده‌ای ناشناس دیده می‌شود: تا خودش ننویسد نه نامی دارد، نه تلفنی، نه رایانامه‌ای.
  • شناسه در یک مرورگر مشخص زندگی می‌کند. مرورگر دیگر، دستگاه دیگر یا پاک‌کردن داده‌های سایت یعنی بازدیدکننده‌ای تازه با تاریخچهٔ خالی.
  • بازدیدکنندهٔ ناشناس را می‌توان به مشتری‌ای که از پیش می‌شناسید پیوند داد — مثلاً کاربری که در ناحیهٔ کاربری شما وارد شده است. چگونگی‌اش در بخش بعدی آمده.

پیوند دادن بازدیدکننده به کاربر خودتان

اگر بازدیدکننده از پیش در سایت شما وارد شده باشد، می‌توانید به پلتفرم بگویید او کیست. پس از پیوند، گفت‌وگو دیگر ناشناس نیست: با پروندهٔ همان شخص ادغام می‌شود و پیام‌های ناشناس پیشینش از دست نمی‌رود.

یک فراخوان با تابعی که برهان را تولید می‌کند کافی است:

mybot.identify(async (visitorId) => {
  const res = await fetch("/mybot-sign", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ userId: currentUser.id, visitorId }),
  });
  return res.json(); // { userId, signature, expiresAt }
});

ویجت تابع شما را با visitorId فرا می‌خواند — شناسهٔ ناشناسِ بازدیدکنندهٔ فعلی برای این مرورگر، تنها مقداری که فقط ویجت آن را می‌داند — و منتظر می‌ماند تا { userId, signature, expiresAt } را برگرداند یا به آن تحلیل شود. تنها وظیفهٔ تابع شما این است که visitorId را به سرور خودتان بسپارد، همراه با شناسهٔ کاربرِ واردشده (currentUser.id در بالا هر چیزی است که در سایت شما این‌طور نامیده می‌شود)، و دقیقاً همان چیزی را که سرورتان پاسخ می‌دهد بازگرداند. امضای واقعی روی سرور شما رخ می‌دهد، نه در این تابع — ادامه را ببینید.

یک تابع بازخوانی، نه مقداری از پیش آماده و نه راهی برای خواندن مستقیم visitorId، به دو دلیل:

  • زمان وجود. ویجت visitorId را به‌صورت ناهمگام هنگام راه‌اندازی می‌سازد — در لحظه‌ای که اسکریپت بارگذار اجرا می‌شود این مقدار هنوز وجود ندارد، و خود mybot.identify تنها پس از پایان آن نصب می‌شود (جزئیات در ادامه). پس تا زمانی که صفحهٔ شما اصلاً بتواند mybot.identify را فرا بخواند، شناسه‌ای که تابع شما دریافت می‌کند تضمیناً واقعی است. یک getter ساده چنین تضمینی نمی‌داد: هیچ‌چیز مانع نمی‌شد صفحه‌ای آن را یک خط زودتر بخواند و چیزی دریافت نکند، و بی‌سروصدا امضایی بسازد که هرگز تأیید نمی‌شود، بی‌آنکه هیچ سرنخی از چرایی آن باشد.
  • دامنه. کد صفحهٔ خودِ شما هرگز لازم نیست visitorId را نگه دارد، ذخیره کند یا دستی جابه‌جا کند — این مقدار فقط درون همین یک تابع وجود دارد، برای همان یک فراخوانی که به آن نیاز دارد.

از لحظه‌ای که visitorId ویجت را ترک می‌کند، به یک قابلیت حامل‌محور (bearer capability) تبدیل می‌شود: هرکس بتواند امضایی برایش بگیرد، می‌تواند با نشست همان بازدیدکننده ادغام شود. آن را فقط به سرور خودتان بفرستید، از طریق درخواست احرازهویت‌شدهٔ خودتان، و جای دیگری نه — آن را لاگ نکنید، به شخص ثالثی منتقل نکنید و در فراخوانی تحلیلی سمت مرورگر قرار ندهید.

امضا فقط روی سرور خودتان محاسبه می‌شود

درون تابع بالای شما، سرور خودتان — هرگز مرورگر — امضا را محاسبه می‌کند: یک HMAC-SHA256 با کلید رمز ویجت، در نمایش شانزده‌شانزدهی، ۳۲ نویسهٔ نخست، از سه مقدار که در یک پیام یکی شده‌اند. همین فرمول در پنل، کنار رمز و زیر عنوان «Signing algorithm» نیز نشان داده می‌شود:

signature = hex(HMAC-SHA256(key: secret, message: userId + "\n" + visitorId + "\n" + expiresAt)).slice(0, 32)

هر + "\n" + در بالا یک کاراکتر خط جدید واقعی میان بخش‌هاست، نه دو کاراکتر بک‌اسلش و n. اگر تابع HMAC شما پیام را به‌صورت یک رشتهٔ واحد می‌گیرد، سه بخش را با یک خط جدید واقعی به هم بچسبانید — سه فراخوان جداگانهٔ .update() بدون خط جدید میان‌شان، هش پیامی دیگر و نادرست را می‌سازند.

سه بخش:

  • userId — شناسهٔ کاربرِ واردشده، همان مقداری که سرور شما از تابع بالا دریافت می‌کند و در پاسخش برمی‌گرداند.
  • visitorId — شناسهٔ ناشناسِ بازدیدکننده که تابع شما به‌عنوان آرگومان دریافت کرده و بدون تغییر به سرور شما فرستاده است.
  • expiresAt — یک برچسب زمانی یونیکس بر حسب ثانیه (نه میلی‌ثانیه)، که سرور شما هنگام امضا آن را می‌سازد و تا آن لحظه همین امضای مشخص معتبر می‌ماند. پلتفرم فراخوانی را که expiresAtاش از پیش در گذشته باشد رد می‌کند، و همچنین فراخوانی را که بیش از ۲۴ ساعت در آینده باشد — پس درست پیش از بازگرداندن آن از تابع خود امضا کنید، نه یک‌بار برای درخواست‌های بعدی کش‌کردن.

این انقضا نکتهٔ اصلی این تغییر است، نه جزئیاتی فرعی. فرمول پیشین فقط شناسهٔ کاربر را پوشش می‌داد، پس امضایی که یک‌بار به دست کسی می‌افتاد — جایی لاگ شده، از ترافیک شبکه گرفته‌شده، به هر شکلی — تا ابد معتبر می‌ماند و برای هر بازدیدکننده‌ای جواب می‌داد، نه فقط کسی که برایش صادر شده بود. هرکس آن را به دست می‌آورد می‌توانست آن را در مرورگری کاملاً متفاوت بازپخش کند، و پلتفرم گشت‌وگذار ناشناس یک غریبه را با پروفایل یک مشتری واقعی ادغام می‌کرد. پیوند دادن امضا به یک visitorId مشخص و دادن عمری کوتاه به آن، هر دو سر این حفره را می‌بندد: امضا فقط برای همان نشستی که صادر شده تأیید می‌شود، نه جای دیگر، و پس از گذشتن expiresAt کاملاً از اعتبار می‌افتد — پس حتی امضایی که لو برود، تنها یک خطر کوتاه‌مدت و محدود به یک نشست است، نه خطری دائمی.

هر سه مقدار را روی سرور خود محاسبه کنید و از تابع خود آماده بازگردانید. این تشریفات نیست: برای محاسبهٔ امضا در مرورگر باید خود رمز را به آنجا بفرستید، یعنی آن را به هر بازدیدکنندهٔ صفحه بسپارید. پس از آن هر کسی می‌تواند خود را هر یک از مشتریان شما جا بزند و گفت‌وگویش را بخواند. بازگرداندن امضا (و visitorId/expiresAtی که برایشان محاسبه شده) به مرورگر امن است، سپردن رمز نه.

خود فراخوان چیزی روی صفحه نشان نمی‌دهد: پیوند در سمت سرور و بی‌صدا انجام می‌شود. اگر تابع شما خطا پرتاب کند یا وعده‌اش رد شود، یا پلتفرم امضای به‌دست‌آمده را رد کند — جور نباشد، یا expiresAt غایب، از پیش گذشته، یا بیش از ۲۴ ساعت در آینده باشد — چیز دیگری رخ نمی‌دهد: بازدیدکننده چیزی نمی‌فهمد و همچنان ناشناس می‌نویسد.

mybot.identify بی‌درنگ وجود ندارد — پس از بارگذاری بستهٔ اصلی ویجت، همراه با یک visitorId واقعی، پدیدار می‌شود (نگاه کنید به «زمان وجود» در بالا). آن را از رویداد بارگذاری صفحه فرا بخوانید، نه در نخستین خط <head>.

رمز کجاست و چگونه عوضش کنیم

رمز ویجت همان کلیدی است که با آن امضا می‌کنید. در تنظیمات ویجت، در بخش «identify() secret» قرار دارد. اگر آن بخش بگوید ویجت هنوز وصل نشده، نخست کانال وب را وصل کنید — رمز همراه آن پدیدار می‌شود.

نمایش. دکمهٔ «Reveal secret» مقدار را می‌آورد. مقدار به‌صورت آشکار ظاهر نمی‌شود: نخست نقطه می‌بینید و نویسه‌ها را کلید جداگانهٔ «Show» نشان می‌دهد (برای بازگشت «Mask»). کنارش دکمهٔ «Clear from screen» هست که مقدار را از صفحه برمی‌دارد.

هر چند بار که بخواهید می‌توانید نمایشش دهید و نمایش چیزی را باطل نمی‌کند: رمز پس از بستن صفحه هم معتبر می‌ماند. علتش این است که به‌جای درهم‌سازی، رمزگذاری‌شده نگه‌داری می‌شود — پلتفرم برای بررسی هر امضا به مقدار واقعی نیاز دارد. اگر شش ماه دیگر بک‌اند تازه‌ای مستقر می‌کنید، کافی است دوباره سر بزنید و بخوانیدش.

پس از کپی‌کردن، خودتان جمع کنید. پلتفرم نمی‌تواند حافظهٔ موقت شما را پاک کند: از مرورگر این کار به‌طور مطمئن شدنی نیست، پس قولش را هم نمی‌دهیم. وقتی کارتان تمام شد مقدار را از صفحه بردارید و حافظهٔ موقت را دستی خالی کنید، به‌ویژه روی رایانهٔ مشترک.

تعویض. دکمهٔ «Rotate secret» با مرحلهٔ تأیید. این کنشی است که بی‌درنگ می‌شکند: همین که رمز تازه پدید آید، رمز قدیمی دیگر تأیید نمی‌شود. پنجرهٔ هم‌پوشانی وجود ندارد — لحظه‌ای که هر دو کلید کار کنند نیست.

آنچه می‌شکند دقیقاً پیوند بازدیدکنندگان به کاربران شماست. گفت‌وگوها قطع نمی‌شوند — بازدیدکنندگان همچنان می‌نویسند و پاسخ می‌گیرند، فقط ناشناس — تا وقتی بک‌اند شما با رمز تازه امضا کند. کد نصب و فهرست دامنه‌های مجاز دست‌نخورده می‌مانند و در سایت چیزی برای تغییر نیست.

پس آگاهانه عوض کنید: نخست استقرار بک‌اند با مقدار تازه را آماده کنید و تنها آنگاه «Rotate secret» را بزنید. زدنش برای اینکه ببینید چه می‌شود، فکر بدی است. مقدار تازه بی‌درنگ پس از تعویض روی صفحه نشان داده می‌شود، پس همان‌جا می‌توانید کپی‌اش کنید.

رفتار ویجت در صفحه

ویجت عمداً چنان ساخته شده که با سایت شما تداخل نکند:

  • در کانتینری جداشده زندگی می‌کند (Shadow DOM بسته). سبک‌های شما به درونش راه ندارند و سبک‌های آن به صفحهٔ شما نشت نمی‌کنند. اثر جانبی‌اش این است که نمی‌توانید با CSS خودتان ظاهرش را تغییر دهید — از تنظیمات ظاهر استفاده کنید.
  • کانتینر تمام صفحه را می‌پوشاند اما کلیک‌ها را نمی‌رباید: کلیک‌ها به صفحه می‌رسند و تنها دکمه و پنل گفت‌وگو پاسخ می‌دهند.
  • ویجت همیشه روی محتوای شماست؛ لایه‌های شما نمی‌توانند بپوشانندش.
  • هر خطایی درون ویجت همان‌جا می‌ماند: در بدترین حالت دکمهٔ گفت‌وگو کار نمی‌کند و سایت شما به کار خود ادامه می‌دهد. اگر ویجت پدیدار نشد، کنسول مرورگر را ببینید — تقریباً همیشه CSP است یا دامنه‌ای که به فهرست افزوده نشده.

اگر ویجت پدیدار نشد

به ترتیب بررسی کنید:

  1. سورس صفحه را باز کنید و مطمئن شوید هر دو تگ سر جای خود هستند و کلید خالی نیست.
  2. بررسی کنید نشانی سایت دقیقاً همان چیزی است که در فهرست آمده، همراه https:// و www.
  3. کنسول مرورگر را ببینید: پیام مربوط به Content Security Policy یعنی باید میزبان پلتفرم را در CSP سایت مجاز کنید.
  4. مطمئن شوید مسدودکنندهٔ تبلیغات ویجت را حذف نمی‌کند — در پنجرهٔ ناشناس بدون افزونه بیازمایید.

در ادامه