כל מה שצריך כדי להטמיע את סוכן ה-AI של wichat באתר שלך - בכל פלטפורמה, בכל תרחיש, עם דוגמאות קוד מלאות ומוכנות להעתקה.
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
YOUR_KEY במפתח הייחודי של העסק שלכם (זמין במסך "הטמעה" בדאשבורד). הווידג'ט חושף API מלא למפתחים שמעוניינים בשליטה מלאה בווידג׳ט מתוך קוד האתר בנוסף לפאנל הניהול אצלנו - window.wichat (destroy, startAnimation, isReady, isOpen, open, close, hide, show, toggle, sendMessage, pendingMessage, setContext, updateConfig, resetConfig) - פירוט מלא בסעיף ה-API.
אתר רגיל ללא Framework - קבצי HTML נפרדים לכל דף.
הדביקו את השורה בכל דף שבו רוצים את הווידג'ט (או בקובץ תבנית/footer משותף אם יש).
<!doctype html>
<html>
<head>...</head>
<body>
<!-- התוכן של הדף -->
<!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
</body>
</html>
מוסיפים את השורה רק בקובץ של הדף הרצוי (למשל דף צור קשר) - ולא בשאר הדפים.
<!-- רק בקובץ contact.html -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
לשיפור ביצועים ניתן לטעון את הווידג'ט רק אחרי שהדף נטען במלואו, אחרי השהיה, או בגלילה ראשונה.
<script>
function loadWichat() {
if (window.__wichatLoaded) return;
window.__wichatLoaded = true;
var s = document.createElement('script');
s.src = 'https://wichat.ai/widget.js';
s.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(s);
}
// אפשרות א': 3 שניות אחרי טעינת הדף
window.addEventListener('load', function () {
setTimeout(loadWichat, 3000);
});
// אפשרות ב': בגלילה או במגע ראשון (מבטל את הטיימר)
window.addEventListener('scroll', loadWichat, { once: true });
window.addEventListener('touchstart', loadWichat, { once: true });
</script>
חשוב: כשטוענים דינמית, חובה להוסיף את data-key באמצעות setAttribute - בלעדיו הווידג'ט לא יעלה.
להסרה מלאה של הווידג'ט בזמן ריצה (למשל בכניסה לאזור אישי):
if (window.wichat) {
window.wichat.destroy(); // מסיר את הכפתור, החלון, המאזינים והטיימרים
}
אפליקציית React עם Vite / CRA / React Router. הווידג'ט מזהה לבד הסרה של תגית הסקריפט ומנקה את עצמו, אבל מומלץ לקרוא ל-destroy() במפורש ב-cleanup.
הדרך הפשוטה ביותר: מוסיפים את הסקריפט פעם אחת ב-index.html. ב-SPA כל ה"דפים" חיים באותו קובץ HTML, אז הווידג'ט יופיע בכולם.
<!-- index.html -->
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
<!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
</body>
אם אתם מעדיפים לשלוט בזה מתוך React (למשל להציג רק למשתמשים לא מחוברים):
import { useEffect } from 'react';
function wichatWidget() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(script);
return () => {
if (window.wichat) window.wichat.destroy();
script.remove();
};
}, []);
return null;
}
export default function App() {
return (
<>
{/* ...הראוטר והדפים שלכם... */}
<wichatWidget />
</>
);
}
מרנדרים את הקומפוננטה רק בדף הרצוי. ה-cleanup ב-useEffect מבטיח שהווידג'ט ייעלם כשעוזבים את הדף.
import { useEffect } from 'react';
export default function Contact() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(script);
return () => {
if (window.wichat) window.wichat.destroy();
script.remove();
};
}, []);
return <div>צור קשר</div>;
}
אם צריך את הווידג'ט בכמה דפים (אך לא בכולם) - Hook קטן חוסך כפילויות:
// src/hooks/useWichat.js
import { useEffect } from 'react';
export function useWichat(key) {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', key);
document.body.appendChild(script);
return () => {
if (window.wichat) window.wichat.destroy();
script.remove();
};
}, [key]);
}
// שימוש בכל דף רצוי:
// useWichat('YOUR_KEY');
להציג בכל האתר חוץ מנתיבים מסוימים (למשל אזור ניהול):
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
const HIDDEN_PATHS = ['/admin', '/checkout'];
function wichatWidget() {
const { pathname } = useLocation();
const hidden = HIDDEN_PATHS.some((p) => pathname.startsWith(p));
useEffect(() => {
if (hidden) return;
const script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(script);
return () => {
if (window.wichat) window.wichat.destroy();
script.remove();
};
}, [hidden]);
return null;
}
ב-Next.js משתמשים בקומפוננטת next/script המובנית. דוגמאות ל-App Router (גרסה 13+) ול-Pages Router.
import Script from 'next/script';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="he" dir="rtl">
<body>
{children}
<Script
src="https://wichat.ai/widget.js"
data-key="YOUR_KEY"
strategy="afterInteractive"
/>
</body>
</html>
);
}
strategy="afterInteractive" טוען את הווידג'ט אחרי שהדף אינטראקטיבי; אפשר גם lazyOnload לטעינה עצלה יותר.
מוסיפים את ה-Script רק בדף הרצוי. מכיוון ש-Next שומר סקריפטים בין ניווטים, מומלץ לעטוף בקומפוננטת Client עם ניקוי:
'use client';
import { useEffect } from 'react';
function wichatOnThisPage() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(script);
return () => {
if ((window as any).wichat) (window as any).wichat.destroy();
script.remove();
};
}, []);
return null;
}
export default function ContactPage() {
return (
<main>
<h1>צור קשר</h1>
<wichatOnThisPage />
</main>
);
}
import type { AppProps } from 'next/app';
import Script from 'next/script';
export default function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<Component {...pageProps} />
<Script
src="https://wichat.ai/widget.js"
data-key="YOUR_KEY"
strategy="afterInteractive"
/>
</>
);
}
import { useEffect } from 'react';
export default function Contact() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(script);
return () => {
if ((window as any).wichat) (window as any).wichat.destroy();
script.remove();
};
}, []);
return <h1>צור קשר</h1>;
}
אפליקציית Vue עם Vite ו-Vue Router.
<!-- index.html -->
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
<!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
</body>
<script setup>
import { onMounted, onUnmounted } from 'vue';
let script;
onMounted(() => {
script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(script);
});
onUnmounted(() => {
if (window.wichat) window.wichat.destroy();
script?.remove();
});
</script>
<template>
<div>צור קשר</div>
</template>
// src/composables/useWichat.js
import { onMounted, onUnmounted } from 'vue';
export function useWichat(key) {
let script;
onMounted(() => {
script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', key);
document.body.appendChild(script);
});
onUnmounted(() => {
if (window.wichat) window.wichat.destroy();
script?.remove();
});
}
// שימוש בכל View רצוי:
// useWichat('YOUR_KEY');
export default defineNuxtConfig({
app: {
head: {
script: [
{
src: 'https://wichat.ai/widget.js',
'data-key': 'YOUR_KEY',
tagPosition: 'bodyClose',
},
],
},
},
});
<script setup>
let script;
onMounted(() => {
script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(script);
});
onUnmounted(() => {
if (window.wichat) window.wichat.destroy();
script?.remove();
});
</script>
<template>
<div>צור קשר</div>
</template>
הקוד רץ רק בדפדפן (onMounted לא רץ ב-SSR), כך שאין צורך בבדיקת process.client.
<!-- src/index.html -->
<body>
<app-root></app-root>
<!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
</body>
import { Component, OnDestroy, OnInit } from '@angular/core';
declare global {
interface Window { wichat?: { destroy: () => void } }
}
@Component({
selector: 'app-contact',
standalone: true,
template: `<h1>צור קשר</h1>`,
})
export class ContactComponent implements OnInit, OnDestroy {
private script?: HTMLScriptElement;
ngOnInit(): void {
this.script = document.createElement('script');
this.script.src = 'https://wichat.ai/widget.js';
this.script.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(this.script);
}
ngOnDestroy(): void {
window.wichat?.destroy();
this.script?.remove();
}
}
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class wichatService {
private script?: HTMLScriptElement;
load(key: string): void {
if (this.script) return; // כבר טעון
this.script = document.createElement('script');
this.script.src = 'https://wichat.ai/widget.js';
this.script.setAttribute('data-key', key);
document.body.appendChild(this.script);
}
unload(): void {
(window as any).wichat?.destroy();
this.script?.remove();
this.script = undefined;
}
}
<!-- src/app.html -->
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
<!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
</body>
<script>
import { onMount } from 'svelte';
onMount(() => {
const script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(script);
// הפונקציה שמוחזרת מ-onMount רצה כשעוזבים את הדף
return () => {
if (window.wichat) window.wichat.destroy();
script.remove();
};
});
</script>
<h1>צור קשר</h1>
פרויקט Vite ללא Framework. אם אתם משתמשים ב-Vite עם React/Vue/Svelte - ראו את הסעיף של ה-Framework הרלוונטי.
<!-- index.html -->
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
<!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
</body>
ב-Multi-Page App של Vite (כמה קבצי HTML) - הוסיפו את השורה בכל קובץ HTML רצוי, או רק בדף הספציפי.
function loadWichat(key) {
const script = document.createElement('script');
script.src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', key);
document.body.appendChild(script);
return () => {
if (window.wichat) window.wichat.destroy();
script.remove();
};
}
// טעינה:
const unloadWichat = loadWichat('YOUR_KEY');
// הסרה בהמשך (אם צריך):
// unloadWichat();
אם יש לכם GTM באתר - אפשר להטמיע את הווידג'ט בלי לגעת בקוד האתר בכלל. עובד על כל פלטפורמה.
<script>
(function () {
var s = document.createElement('script');
s.src = 'https://wichat.ai/widget.js';
s.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(s);
})();
</script>
חשוב: ב-Custom HTML של GTM אי אפשר להשתמש ב-src ישירות עם data-attribute, לכן טוענים דינמית כמו בדוגמה.
Page Path equals /contact (או הנתיב הרצוי).באתרי SPA כדאי להשתמש ב-Trigger מסוג History Change ולהוסיף גם Tag של הסרה (window.wichat && window.wichat.destroy()) ביציאה מהנתיב.
שלוש דרכים: קוד ב-functions.php (למפתחים), תוסף Code Snippets (מומלץ למשתמשים), או ידנית בתבנית.
<?php
// wichat AI Widget - כל הדפים
function wichat_widget_script() {
?>
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
<?php
}
add_action('wp_footer', 'wichat_widget_script');
מומלץ להשתמש ב-Child Theme כדי שהקוד לא יימחק בעדכון תבנית. לחלופין: תוסף WPCode / Code Snippets ← Snippet חדש מסוג HTML ← מיקום Footer.
שימוש ב-Conditional Tags של WordPress - לפי slug, מזהה דף, או סוג תוכן:
<?php
function wichat_widget_script() {
// רק בדף עם ה-slug "contact"
if (!is_page('contact')) return;
// דוגמאות נוספות:
// if (!is_front_page()) return; // רק דף הבית
// if (!is_page(array(12, 'about'))) return; // לפי ID או כמה דפים
// if (!is_singular('product')) return; // רק דפי מוצר (WooCommerce)
?>
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
<?php
}
add_action('wp_footer', 'wichat_widget_script');
<?php
function wichat_widget_script() {
// לא להציג בעגלה ובקופה
if (is_page(array('cart', 'checkout'))) return;
?>
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
<?php
}
add_action('wp_footer', 'wichat_widget_script');
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
</body> ושמרו. <!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
</body>
</html>
שימוש בתנאי Liquid לפי סוג התבנית או ה-handle של הדף:
{% comment %} רק בדף צור קשר {% endcomment %}
{% if page.handle == 'contact' %}
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
{% endif %}
{% comment %} דוגמאות נוספות:
{% if template == 'index' %} - רק דף הבית
{% if template contains 'product' %} - רק דפי מוצר
{% if template contains 'collection' %} - רק דפי קטגוריה
{% endcomment %}
</body>
דפי ה-Checkout של Shopify לא מריצים קוד מהתבנית (אלא ב-Shopify Plus), כך שהווידג'ט ממילא לא יופיע שם. להסתרה גם בעגלה:
{% unless template contains 'cart' %}
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
{% endunless %}
</body>
ב-Wix מטמיעים דרך ממשק הניהול - בלי לגעת בקוד האתר. נדרשת תוכנית Premium עם דומיין מחובר.
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
בחירת "Load code once" חשובה - Wix הוא SPA, וכך הסקריפט לא ייטען מחדש בכל מעבר דף. הווידג'ט יישאר זמין בכל האתר.
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
Wix מסיר את הסקריפט אוטומטית במעבר לדף אחר - הווידג'ט מזהה זאת ומנקה את עצמו לבד (MutationObserver מובנה). אין צורך בקוד נוסף.
נדרשת תוכנית בתשלום (Site Plan) כדי להוסיף Custom Code.
<!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
קוד ברמת הדף נטען רק בדף הזה - אין צורך בניקוי ידני, כי כל ניווט ב-Webflow טוען דף חדש.
נדרשת תוכנית Business ומעלה (Code Injection זמין רק בתוכניות בתשלום).
<!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
חלופה ללא Code Injection: הוסיפו לדף בלוק מסוג Code (בעורך התוכן) והדביקו בו את אותה שורה.
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
ב-Framer אין הזרקת קוד לדף בודד, אבל אפשר להתנות לפי נתיב ה-URL:
<script>
(function () {
// רשימת הנתיבים שבהם הווידג'ט יופיע
var ALLOWED = ['/contact', '/pricing'];
function syncWichat() {
var allowed = ALLOWED.indexOf(window.location.pathname) > -1;
var loaded = !!window.wichat;
if (allowed && !loaded) {
var s = document.createElement('script');
s.src = 'https://wichat.ai/widget.js';
s.setAttribute('data-key', 'YOUR_KEY');
document.body.appendChild(s);
} else if (!allowed && loaded) {
window.wichat.destroy();
}
}
// Framer הוא SPA - מאזינים לשינויי ניווט
var push = history.pushState;
history.pushState = function () {
push.apply(this, arguments);
setTimeout(syncWichat, 0);
};
window.addEventListener('popstate', syncWichat);
syncWichat();
})();
</script>
הדוגמה הזו (טעינה/הסרה לפי נתיב עם האזנה ל-History) עובדת בכל אתר SPA שבו יש רק נקודת הזרקה גלובלית אחת.
בפרויקט Flutter Web, הווידג'ט מוטמע בקובץ ה-HTML המארח - הוא מרחף מעל אזור הציור של Flutter ולא מתנגש איתו.
<!-- web/index.html -->
<body>
<script src="flutter_bootstrap.js" async></script>
<!-- wichat AI Widget -->
<script src="https://wichat.ai/widget.js" data-key="YOUR_KEY"></script>
</body>
הווידג'ט מצויר ב-DOM מעל ה-canvas של Flutter (z-index גבוה), ולכן זמין מכל מסך באפליקציה.
שליטה מתוך Dart באמצעות JS interop - טעינה כשנכנסים למסך והסרה כשעוזבים:
// lib/wichat.dart
import 'dart:js_interop';
import 'package:web/web.dart' as web;
void loadWichat(String key) {
if (web.document.getElementById('wichat-script') != null) return;
final script = web.document.createElement('script') as web.HTMLScriptElement
..id = 'wichat-script'
..src = 'https://wichat.ai/widget.js';
script.setAttribute('data-key', key);
web.document.body!.appendChild(script);
}
void destroyWichat() {
// הסרת תגית הסקריפט מפעילה את הניקוי האוטומטי של הווידג'ט
web.document.getElementById('wichat-script')?.remove();
}
// שימוש במסך (StatefulWidget):
class ContactScreen extends StatefulWidget {
const ContactScreen({super.key});
@override
State<ContactScreen> createState() => _ContactScreenState();
}
class _ContactScreenState extends State<ContactScreen> {
@override
void initState() {
super.initState();
loadWichat('YOUR_KEY');
}
@override
void dispose() {
destroyWichat();
super.dispose();
}
@override
Widget build(BuildContext context) => const Scaffold(
body: Center(child: Text('צור קשר')),
);
}
הווידג'ט כולל MutationObserver שמזהה את הסרת תגית הסקריפט ומנקה את עצמו אוטומטית - לכן מספיק להסיר את התגית.
הממשק שהווידג'ט חושף למפתחים ותכונות ההתנהגות המובנות שלו.
| מאפיין | חובה | תיאור |
|---|---|---|
src | כן | https://wichat.ai/widget.js - כתובת הסקריפט. ה-API נגזר ממנה אוטומטית. |
data-key | כן | המפתח הייחודי של העסק. בלעדיו הווידג'ט לא ייטען (שגיאה ב-Console). |
מחזירה true או false - האם הווידג'ט סיים את הטעינה הראשונה שלו בכניסה לאתר/למסך: כלומר קיבל את כל ה-config שלו מהשרת שלנו וסיים להתרנדר. מומלץ לבדוק אותה לפני כל שימוש בכל אחת מפונקציות ה-API האחרות - כך מבטיחים שלא תהיה שגיאת timing כשקוראים לפונקציה לפני שהווידג'ט מוכן.
// דוגמה בסיסית: פתיחת הצ'אט רק אם הווידג'ט מוכן
if (window.wichat) {
if (window.wichat.isReady() === true) {
window.wichat.open();
}
}
// דוגמה: המתנה עד שהווידג'ט מוכן (בדיקה חוזרת קצרה)
function whenWichatReady(cb) {
if (window.wichat && window.wichat.isReady()) return cb();
setTimeout(function () { whenWichatReady(cb); }, 200);
}
whenWichatReady(function () {
window.wichat.sendMessage('שלום, אשמח לעזרה');
});
| מצב | ערך מוחזר |
|---|---|
| הווידג'ט קיבל את ה-config מהשרת וסיים את הרינדור הראשון | true |
| הסקריפט נטען אבל ה-config עדיין בטעינה | false |
הווידג'ט הוסר עם destroy() | false |
מחזירה true או false - האם חלון הצ'אט פתוח כרגע על המסך. true כאשר הצ'אט פתוח, false כאשר הוא סגור. שימושי כדי לסנכרן אלמנטים באתר שלכם עם מצב הצ'אט (למשל להסתיר כפתור צף משלכם כל עוד הצ'אט פתוח).
// דוגמה: כפתור באתר שמתנהג לפי מצב הצ'אט
document.getElementById('chat-btn').addEventListener('click', function () {
if (!window.wichat || !window.wichat.isReady()) return;
if (window.wichat.isOpen() === true) {
window.wichat.close(); // פתוח - נסגור
} else {
window.wichat.open(); // סגור - נפתח
}
});
// דוגמה: הסתרת כפתור צף משלכם כל עוד הצ'אט פתוח
setInterval(function () {
if (!window.wichat || !window.wichat.isReady()) return;
var myFab = document.getElementById('my-fab');
myFab.style.display = window.wichat.isOpen() ? 'none' : 'flex';
}, 500);
| מצב | ערך מוחזר |
|---|---|
חלון הצ'אט פתוח (המבקר לחץ על הכפתור או נקראה open()) | true |
| חלון הצ'אט סגור | false |
הווידג'ט הוסתר עם hide() (החלון נסגר אוטומטית) | false |
הווידג'ט עדיין בטעינה או הוסר עם destroy() | false |
מפעילה מחדש את אנימציית הפתיחה של הווידג'ט - אותה דמות מונפשת שמופיעה בכניסה לאתר ומתמזגת בחזרה לאייקון הווידג'ט. שימושי כאשר רוצים שלחיצה על כפתור מסוים באתר שלכם (או אירוע אחר בדף) תפעיל את האנימציה שוב, ללא תלות בהגדרת התדירות שנבחרה בפאנל.
אנימציות פתיחה זמינות למנויי Pro, Premium ו-Partner בלבד, והן גם אינן שדה חובה בהגדרות העסק. לכן אם המנוי אינו אחד מהשלושה, או שלא נבחרה אנימציית פתיחה לעסק - הפונקציה פשוט לא תעשה דבר ותרשום אזהרה ב-Console (ללא שגיאה ובלי לשבור את הדף).
// דוגמה: כפתור באתר שמפעיל מחדש את אנימציית הפתיחה
document.getElementById('replay-anim').addEventListener('click', function () {
if (window.wichat && window.wichat.isReady()) {
window.wichat.startAnimation();
}
});
// דוגמה: הפעלת האנימציה כשהמבקר מגיע לסקשן "צור קשר"
var contact = document.getElementById('contact');
var seen = false;
new IntersectionObserver(function (entries) {
if (seen || !entries[0].isIntersecting) return;
if (!window.wichat || !window.wichat.isReady()) return;
seen = true;
window.wichat.startAnimation();
}, { threshold: 0.5 }).observe(contact);
| מצב | התנהגות |
|---|---|
| המנוי הוא Pro / Premium / Partner ונבחרה אנימציית פתיחה | האנימציה מתנגנת מחדש מההתחלה ומתמזגת בחזרה לאייקון הווידג'ט. |
| המנוי אינו Pro / Premium / Partner | לא מתבצע דבר. אזהרה ב-Console: entrance animations are available on the Pro, Premium and Partner plans only |
| לא הוגדרה אנימציית פתיחה לעסק | לא מתבצע דבר. אזהרה ב-Console: no entrance animation is configured for this business |
הווידג'ט מוסתר עם hide() | לא מתבצע דבר. אזהרה ב-Console - יש לקרוא ל-show() קודם. |
| הווידג'ט עדיין בטעינה | לא מתבצע דבר. אזהרה ב-Console - מומלץ לבדוק isReady() לפני הקריאה. |
אין צורך לחכות לסיום האנימציה - היא מנוגנת מעל הדף ומסתיימת מעצמה, וכפתור הווידג'ט חוזר להיות לחיץ בסופה.
מסיר את הווידג'ט לחלוטין: כפתור, חלון צ'אט, מאזיני אירועים, טיימרים ו-Observers. בטוח לקריאה חוזרת (no-op אחרי הפעם הראשונה).
// דוגמה: הסרה בטוחה מכל מקום בקוד
if (window.wichat) {
window.wichat.destroy();
}
| התנהגות | פירוט |
|---|---|
| ניקוי אוטומטי | הווידג'ט עוקב (MutationObserver) אחרי תגית ה-<script> שלו. אם היא מוסרת מה-DOM (נפוץ בניווטי SPA) - הוא הורס את עצמו אוטומטית. |
| קריאה חוזרת | destroy() אידמפוטנטית - קריאות נוספות לא זורקות שגיאה. |
| טעינה מחדש | אחרי destroy, הזרקה חדשה של תגית הסקריפט טוענת מופע נקי לגמרי. |
| זיכרון שיחה | השיחה נשמרת ב-localStorage של הדפדפן - destroy לא מוחק אותה; המבקר ימשיך את אותה שיחה בטעינה הבאה. |
פותח את חלון הצ'אט אוטומטית, בלי שהמבקר יצטרך ללחוץ על כפתור הווידג'ט. אם החלון כבר פתוח - לא קורה כלום (בטוח לקריאה חוזרת). שימושי למשל כשעוברים למסך מסוים ורוצים שהצ'אט ייפתח מיד.
// דוגמה: פתיחת הצ'אט אוטומטית כשנכנסים לדף "צור קשר"
if (window.wichat) {
window.wichat.open();
}
// דוגמה ב-React: פתיחה אוטומטית במעבר למסך
useEffect(() => {
if (window.wichat) window.wichat.open();
}, []);
סוגר את חלון הצ'אט אוטומטית - הפעולה ההפוכה ל-open(). הפונקציה בודקת בעצמה אם החלון פתוח: אם הוא כבר סגור - לא קורה כלום ולא נזרקת שגיאה.
// דוגמה: סגירת הצ'אט כשעוזבים מסך מסוים
if (window.wichat) {
window.wichat.close();
}
פונקציית ביניים בין open() ל-close(): אם הצ'אט פתוח - היא סוגרת אותו; אם הוא סגור - היא פותחת. שימושי לכפתור "צ'אט" משלכם באתר.
// דוגמה: כפתור באתר שפותח/סוגר את הצ'אט
<button onclick="window.wichat && window.wichat.toggle()">
דברו איתנו
</button>
שולח הודעה לצ'אט בשם המבקר, אוטומטית: אם הצ'אט סגור - הוא נפתח קודם (אם כבר פתוח - נשאר כמו שהוא), ההודעה שהעברתם מודבקת לשדה הקלט ונשלחת מיד לסוכן, והסוכן עונה כרגיל. שימושי לכפתורים באתר שמתחילים שיחה על נושא ספציפי.
// דוגמה: כפתור "בדקו זמינות" שפותח את הצ'אט ושואל את הסוכן
<button onclick="window.wichat && window.wichat.sendMessage('היי, אני רוצה לבדוק זמינות לתור השבוע')">
בדקו זמינות
</button>
// דוגמה: שאלה על מוצר מתוך דף מוצר
document.getElementById('ask-btn').addEventListener('click', function () {
if (window.wichat) {
window.wichat.sendMessage('אשמח לפרטים נוספים על המוצר בדף הזה');
}
});
ההודעה נספרת במכסת ההודעות של השיחה כמו הודעה רגילה שהמבקר מקליד. טקסט ריק או ערך שאינו מחרוזת - נדחה עם אזהרה ב-Console (ללא שגיאה).
הקשר מסך עבור ה-AI. מגדירה לסוכן מה המשתמש רואה כרגע על המסך באתר שלכם. כך במקום שהמבקר יצטרך לכתוב "יש את האייפון 17 פרו 256GB בצבע שחור במלאי?" הוא יוכל לכתוב פשוט "יש את זה במלאי?" - והסוכן יבין בדיוק על מה מדובר.
איך זה עובד: הקריאה לפונקציה שומרת את המידע בזיכרון מקומי בדפדפן בלבד - שום דבר לא נשלח לשרת שלנו. רק כשהמבקר שולח הודעה בצ'אט, ההקשר העדכני ביותר מצורף להודעה ונשלח ל-AI יחד איתה. ה-AI מקבל הסבר שהמידע הזה מתאר את המסך שהמשתמש רואה כרגע, ומתייחס אליו רק כשהוא רלוונטי לשאלה. קיים "מקום" אחד בלבד להקשר: כל קריאה חדשה ל-setContext מחליפה את הקודמת ומוחקת אותה מהזיכרון המקומי, כך שתמיד נקלט רק ההקשר העדכני ביותר.
מבחינת ארכיטקטורה, הפונקציה חייבת להיות מוגדרת באתר שלכם בצורה הזו במדויק - page (מחרוזת - שם המסך בטקסט חופשי) ו-context (אובייקט JSON רגיל ותקין עם כמה שדות שרוצים):
window.wichat.setContext({
page: "",
context: {
}
});
דוגמה בדף מוצר:
window.wichat.setContext({
page: "product",
context: {
id: "123",
name: "iPhone 17 Pro 256gb black",
price: 4999,
in_stock: true
}
});
// עכשיו המבקר יכול לשאול בצ'אט: "יש את זה במלאי?"
// והסוכן יבין שמדובר ב-iPhone 17 Pro 256gb black.
דוגמה ב-React - עדכון ההקשר בכל מעבר בין מוצרים/מסכים:
useEffect(() => {
if (window.wichat && window.wichat.isReady()) {
window.wichat.setContext({
page: "product",
context: { id: product.id, name: product.name, price: product.price }
});
}
}, [product]);
| שדה | דרישה |
|---|---|
page | חובה. מחרוזת - שם המסך בטקסט חופשי (למשל "product", "checkout", "עמוד הבית"). |
context | חובה. אובייקט JSON רגיל ותקין - כמה שדות שרוצים (עד 2000 תווים כ-JSON). |
| התנהגות | פירוט |
|---|---|
| שמירה מקומית בלבד | הקריאה לא שולחת שום דבר לשרת - המידע נשמר בזיכרון הדף בלבד. |
| הקשר אחד בלבד | הגדרה חדשה מחליפה את הקודמת - רק ההקשר העדכני ביותר נקלט בהודעת המבקר. |
| שליחה ל-AI | ההקשר מצורף להודעת המבקר ונשלח יחד איתה בבקשה אחת בלבד - חוסך קרדיטים ומאפשר ל-AI להבין בצורה הטובה ביותר. |
| מבנה לא תקין | אזהרה ב-Console וההקשר לא נשמר (ללא שגיאה, הווידג'ט ממשיך לעבוד כרגיל). |
| ניקוי | רענון דף או destroy() מוחקים את ההקשר מהזיכרון. |
מומלץ: אם משתמשים ב-setContext במסך מסוים באתר שלכם - כדאי כבר להוסיף אותה לכל המסכים באתר. כך בכל מעבר מסך ההקשר מתעדכן, וה-AI מקבל תמיד את ההקשר העדכני ביותר של המסך שבו המבקר נמצא בעת שליחת ההודעה - ולא הקשר ישן ממסך קודם.
זהה כמעט לגמרי ל-sendMessage(text), בהבדל אחד: ההודעה לא נשלחת לסוכן. אם הצ'אט סגור - הוא נפתח קודם (אם כבר פתוח - נשאר כמו שהוא), וההודעה שהעברתם מודבקת לשדה הקלט ומחכה שם. המבקר צריך ללחוץ בעצמו על כפתור השליחה (או Enter) כדי שההודעה תישלח. שימושי כשרוצים להציע למבקר שאלה מוכנה, אבל להשאיר לו את ההחלטה ואפשרות לערוך אותה לפני השליחה.
// דוגמה: כפתור שמכין למבקר שאלה מוכנה בשדה הקלט (בלי לשלוח)
<button onclick="window.wichat && window.wichat.pendingMessage('היי, אני רוצה לבדוק זמינות לתור השבוע')">
שאלו על זמינות
</button>
// דוגמה: הכנת שאלה על מוצר מתוך דף מוצר
document.getElementById('ask-btn').addEventListener('click', function () {
if (window.wichat) {
window.wichat.pendingMessage('יש לי שאלה על ' + productName);
}
});
| התנהגות | פירוט |
|---|---|
| לא נשלח לסוכן | הטקסט רק מודבק לשדה הקלט. אין קריאה לשרת ולא נצרכת הודעה מהמכסה עד שהמבקר שולח בעצמו. |
| פתיחת הצ'אט | אם הצ'אט סגור הוא נפתח, והפוקוס עובר לשדה הקלט כדי שהמבקר יוכל לערוך ולשלוח. |
| קריאה חוזרת | קריאה נוספת מחליפה את הטקסט שנמצא בשדה הקלט. |
| טקסט לא תקין | ערך שאינו מחרוזת, או מחרוזת ריקה, מדולג עם אזהרה ב-Console - בלי שגיאה. |
מסתירה את הווידג'ט מהמסך באופן זמני בלבד. שונה מ-destroy() בכך שהיא לא מוחקת ולא הורסת שום דבר: הווידג'ט, השיחה, ההגדרות והמאזינים נשארים בדיוק כמו שהם - רק לא נראים. אם חלון הצ'אט היה פתוח הוא נסגר. קריאה חוזרת בטוחה (no-op).
// דוגמה: הסתרת הווידג'ט במסך מסוים
if (window.wichat) {
window.wichat.hide();
}
הפעולה ההפוכה ל-hide() - מחזירה את הווידג'ט להצגה על המסך, אותו מופע בדיוק עם אותה שיחה. אם לא נקראה קודם hide() הווידג'ט כבר מוצג, ולכן לא יקרה כלום ולא תיזרק שגיאה.
// דוגמה: הסתרה וחזרה במעבר בין מסכים
if (window.wichat) {
window.wichat.hide(); // הווידג'ט נעלם מהמסך
window.wichat.show(); // הווידג'ט חוזר, עם אותה שיחה
}
| התנהגות | פירוט |
|---|---|
| לא הורס | בשונה מ-destroy(), אין ניקוי של אלמנטים, מאזינים או טיימרים - הווידג'ט ממשיך לחיות מוסתר. |
| שמירת שיחה | היסטוריית השיחה נשמרת במלואה, וממשיכה מאותה נקודה כשקוראים ל-show(). |
| הגדרות הצגה | show() מכבדת את הגדרות "הצג במובייל / הצג במחשב" של העסק - היא לא תציג את הווידג'ט במסך שבו הוא הושבת מהפאנל. |
| קריאה מיותרת | show() ללא hide() לפניה, או hide() פעמיים - לא עושות כלום ולא זורקות שגיאה. |
שינויי תצורה מקומיים לדף בלבד. הפונקציה מקבלת אובייקט עם השדות שרוצים לשנות, ומחילה אותם על הווידג'ט באתר שלכם בלבד - שום דבר לא נשמר במסד הנתונים ולא משנה את ההגדרות בפאנל של wichat. כל שדה שהגדרתם כאן "דורס" מקומית את הערך המקורי מהפאנל, עד ש-resetConfig() נקרא או שהדף נטען מחדש.
| שדה | ערכים אפשריים | מי יכול |
|---|---|---|
widget_icon | message, bot, sparkles, headphones, zap, heart, globe, phone | Pro / Premium / Partner בלבד |
widget_position_mobile | bottom-right, bottom-left, top-right, top-left | Pro / Premium / Partner בלבד |
widget_position_desktop | bottom-right, bottom-left, top-right, top-left | Pro / Premium / Partner בלבד |
widget_size_mobile | xsmall, small, medium, large | Pro / Premium / Partner בלבד |
widget_size_desktop | xsmall, small, medium, large | Pro / Premium / Partner בלבד |
widget_welcome | טקסט חופשי (מחרוזת לא ריקה, עד 200 תווים) - טקסט הפתיחה שהסוכן מציג כשנפתח הצ'אט | Pro / Premium / Partner בלבד |
widget_timer | gloves, robot, ribbon | Pro / Premium / Partner בלבד |
widget_position | bottom-right, bottom-left, top-right, top-left | Free / Business בלבד (מיקום אחיד לכל המסכים) |
widget_size | xsmall, small, medium, large | Free / Business בלבד (גודל אחיד לכל המסכים) |
למה יש הבדל בין Free/Business ל-Pro/Premium? בתוכניות Pro/Premium לווידג'ט יש שני ערכים לכל אחד מהשדות גודל ומיקום - אחד למובייל ואחד למחשב. לכן משתמשי Pro/Premium חייבים לציין במפורש איזה מהם משנים (_mobile או _desktop) - ניסיון להשתמש בשדה הכללי (widget_position / widget_size) פשוט לא יעבוד ותופיע אזהרה ב-Console. בתוכניות Free/Business יש ערך אחד כללי לכל שדה, ולכן משתמשים בשדות הכלליים בלבד - והשדות המפוצלים (וגם widget_icon ו-widget_welcome) לא זמינים. בתוכניות Free/Business טקסט הפתיחה תמיד נשאר ברירת המחדל, והשרת שלנו הוא זה שקובע אילו שדות מותרים - כך שלא ניתן לעקוף את ההגבלה מצד הדפדפן.
דוגמאות למשתמשי Pro/Premium (כל 6 השדות):
// 1) שינוי אייקון הווידג'ט לאייקון רובוט (בדף הזה בלבד)
window.wichat.updateConfig({ widget_icon: 'bot' });
// 2) שינוי מיקום הווידג'ט במובייל לפינה השמאלית-תחתונה
window.wichat.updateConfig({ widget_position_mobile: 'bottom-left' });
// 3) שינוי מיקום הווידג'ט במחשב לפינה הימנית-עליונה
window.wichat.updateConfig({ widget_position_desktop: 'top-right' });
// 4) הקטנת הווידג'ט במובייל
window.wichat.updateConfig({ widget_size_mobile: 'small' });
// 5) הגדלת הווידג'ט במחשב
window.wichat.updateConfig({ widget_size_desktop: 'large' });
// 6) שינוי טקסט הפתיחה של הצ'אט (בדף הזה בלבד)
window.wichat.updateConfig({ widget_welcome: 'היי! מעניין אותך המוצר הזה? אני כאן לכל שאלה' });
// אפשר גם לשלב כמה שינויים בקריאה אחת:
window.wichat.updateConfig({
widget_icon: 'headphones',
widget_position_desktop: 'bottom-left',
widget_size_mobile: 'xsmall'
});
אנימציית טיימר:
window.wichat.updateConfig({
widget_timer: {
style: 'gloves',
text: 'המבצע מסתיים בעוד',
ends_at: '2027-07-01T20:00:00+03:00',
interval_seconds: 30
}
});
// Stop the timer animation on this page only:
window.wichat.updateConfig({ widget_timer: null });
// Restore the original timer and all other panel settings:
window.wichat.resetConfig();
| שדה / התנהגות | פירוט |
|---|---|
text | טקסט חובה מעל השעון, עד 60 תווים. מוצג כטקסט בלבד ולא כ-HTML. |
ends_at | מועד סיום חובה בפורמט ISO 8601 עם אזור זמן מפורש. כל הזמנים בפאנל הם לפי Asia/Jerusalem. בקוד יש להשתמש בהיסט המתאים לתאריך בישראל: +03:00 בקיץ או +02:00 בחורף; אפשר גם לשלוח את אותו רגע ב-UTC עם Z. אין להשתמש בתאריך ללא אזור זמן או באזור הזמן המקומי של המבקר. |
interval_seconds | מספר שלם של 20 שניות לפחות, בין תחילת הופעה לתחילת ההופעה הבאה. |
| תצוגה וסיום | לאחר אנימציית הפתיחה, השלט נשאר 5 שניות עם שעון דיגיטלי חי HH:MM:SS, ואז חוזר לווידג׳ט. השעות הן סך השעות שנותרו ולא מתאפסות אחרי 24 שעות. כשהזמן מסתיים, גם באמצע הופעה, האנימציה מוסרת ומפסיקה ללא שגיאה. |
| ללא קריאות חוזרות | הזמן והתדירות נקראים מההגדרות בעת הטעינה; הספירה והמחזור פועלים מקומית בדפדפן. נטען נכס אנימציה סטטי אחד, ללא בקשות חוזרות לשרת עבור הטיימר. |
| עדכון ואיפוס | יש לשלוח את אובייקט הטיימר המלא. עדכון מחליף את המחזור הקודם ומנקה אותו; null עוצר ומסיר אותו. resetConfig משחזר את ההגדרות המקוריות ומנקה אנימציות ותזמונים קודמים, ללא שינוי במסד הנתונים. אם הטיימר המקורי הסתיים, הוא לא יוצג. |
| חסימות | השרת מנקה הגדרות לא תקינות או ללא מנוי מתאים ומחזיר הרשאת טיימר לפי מנוי בעל העסק. שדות לא מורשים או ערכים לא תקינים ב-updateConfig מדולגים. האנימציה מושהית בזמן צ׳אט פתוח, אנימציית פתיחה, הסתרת הווידג׳ט או לשונית לא פעילה; destroy מנקה גם אותה. |
דוגמאות למשתמשי Free/Business (השדות הכלליים בלבד):
// 1) שינוי מיקום הווידג'ט (אחיד למובייל ולמחשב)
window.wichat.updateConfig({ widget_position: 'bottom-left' });
// 2) שינוי גודל הווידג'ט (אחיד למובייל ולמחשב)
window.wichat.updateConfig({ widget_size: 'large' });
// 3) שינוי אייקון - לא זמין בתוכנית Free:
window.wichat.updateConfig({ widget_icon: 'bot' });
// ← לא יקרה כלום, ותופיע אזהרה ב-Console.
| התנהגות | פירוט |
|---|---|
| מקומי בלבד | השינויים חיים בזיכרון הדף בלבד. רענון דף / ניווט מלא מחזירים את התצורה מהפאנל. שום דבר לא נכתב למסד הנתונים. |
| שדה לא מורשה | שדה שלא קיים בתוכנית שלכם (או שלא נתמך בכלל) פשוט מדולג עם אזהרה ב-Console - שאר השדות באותה קריאה כן מוחלים. |
| ערך לא חוקי | ערך שאינו מהרשימה המותרת מדולג עם אזהרה ב-Console - לא נזרקת שגיאה. |
| אכיפת תוכנית | זיהוי התוכנית מגיע מהשרת יחד עם התצורה - אי אפשר "לשחרר" שדות של Pro/Premium מה-Console בעסק בתוכניות Free / Business. |
| לפני טעינה | קריאה לפני שהווידג'ט סיים להיטען - אזהרה ב-Console ולא קורה כלום. קראו לה אחרי שהווידג'ט נטען. |
ביטול כל השינויים המקומיים. הפונקציה מוחקת את כל השינויים שבוצעו עם updateConfig(...) ומחזירה את הווידג'ט לתצורה המקורית כפי שהיא מוגדרת בפאנל של wichat (מיקום, גודל, אייקון, טקסט פתיחה ואנימציית טיימר). האיפוס מנקה גם את מחזור הטיימר המקומי ומחזיר את הטיימר המקורי, אם הוא עדיין בתוקף. אם לא בוצעו שינויים מקומיים - הקריאה בטוחה לגמרי: לא קורה כלום ולא נזרקת שגיאה.
// דוגמה: בדף המבצעים הווידג'ט גדול ובצד שמאל,
// ובחזרה לדף הבית - חוזרים להגדרות המקוריות מהפאנל.
// בדף המבצעים:
window.wichat.updateConfig({
widget_size_desktop: 'large',
widget_position_desktop: 'bottom-left'
});
// בחזרה לדף הבית:
window.wichat.resetConfig();
// ← הווידג'ט חוזר בדיוק להגדרות שבפאנל של wichat
// בטוח גם בלי שינויים קודמים:
window.wichat.resetConfig(); // לא קורה כלום, אין שגיאה
חשוב: resetConfig() מבטל שינויים מקומיים בלבד. הוא לא נוגע בהגדרות בפאנל של wichat - הן מעולם לא השתנו, כי updateConfig(...) לא כותב אליהן.
| תכונה | פירוט |
|---|---|
| עיצוב מבודד | הווידג'ט מזריק אלמנטים עם inline styles ו-z-index גבוה - לא מושפע מ-CSS של האתר ולא משפיע עליו. |
| מובייל/דסקטופ | תצוגה לפי הגדרות העסק בדאשבורד (הצג במובייל / הצג במחשב), עם גודל נפרד לכל מסך בתוכניות Pro/Premium. |
| RTL | חלון הצ'אט תמיד בעברית ו-RTL, ללא תלות בשפת האתר המארח. |
| עסק מושבת | אם העסק הושבת בדאשבורד, השרת לא מחזיר קונפיגורציה והווידג'ט לא יוצג כלל. |
פיצ'ר "נתונים דינמיים" (למנויי pro, partner,Premium) מאפשר לסוכן ה-AI לשלוף מידע חי מהמערכת שלכם בזמן השיחה - מלאי, סטטוס הזמנות, זמינות תורים וכדומה - ולענות ללקוחות על בסיס נתונים עדכניים. יש שתי דרכים לחבר: חיבור ידני (אתם בונים את ה-Endpoint בעצמכם) או Vibe Coding (מעתיקים prompt מוכן לסוכן ה-AI של הפלטפורמה שבה בניתם את האתר).
wichat לעולם לא מקבלת גישה ישירה למסד הנתונים שלכם. אתם יוצרים Endpoint ייעודי בשרת שלכם שמאמת מפתח API, קורא ממסד הנתונים בקריאה בלבד, ומחזיר אך ורק את המידע שבחרתם לחשוף. הסוכן פונה אליו רק כששאלת הלקוח דורשת מידע עדכני:
wichat AI -> wichat Backend -> Your Endpoint -> Your Database
המפתח נשמר מוצפן בצד השרת של wichat ואינו נחשף לעולם לדפדפן או למשתמש הקצה. הקריאה היא תמיד קריאה בלבד (read-only) - wichat לעולם לא כותבת או מוחקת דרך ה-Endpoint.
ה-Endpoint שלכם חייב לעמוד בחוזה הבא:
| מאפיין | דרישה |
|---|---|
| Method | POST בלבד |
| כתובת | HTTPS ציבורית בלבד. HTTP, localhost וכתובות פנימיות נדחים. |
| אימות | כותרת Authorization: Bearer <API_KEY> - מפתח ייעודי ל-wichat שנשמר כ-secret בשרת שלכם. בקשה ללא מפתח תקין - החזירו 401. |
| Redirects | חסומים - ה-Endpoint חייב לענות ישירות ללא הפניה (3xx). |
| זמן תגובה | מומלץ לענות תוך שניות בודדות - בקשה איטית מדי תיכשל. |
גוף הבקשה שנשלח אליכם:
POST /api/wichat/data HTTP/1.1
Content-Type: application/json
Authorization: Bearer YOUR_WICHAT_API_KEY
{
"query": "נשאר Nike Air Force במידה 42?",
"read_only": true
}
query (string) - טקסט חופשי שמתאר את המידע המבוקש (עד 300 תווים).read_only (boolean) - תמיד true. ה-Endpoint חייב להיות קריאה בלבד.גוף התשובה - JSON פשוט ועקבי עם המידע המינימלי הנחוץ בלבד:
{
"success": true,
"data": [
{ "product": "Nike Air Force 1", "size": "42", "in_stock": true, "quantity": 3 }
]
}
// WICHAT_API_KEY נשמר בסביבת השרת בלבד
app.post('/api/wichat/data', express.json(), async (req, res) => {
// 1. אימות מפתח
const auth = req.headers.authorization || '';
if (auth !== 'Bearer ' + process.env.WICHAT_API_KEY) {
return res.status(401).json({ success: false });
}
// 2. קריאת השאילתה עם הגבלת אורך
const query = String(req.body?.query || '').slice(0, 300);
// 3. חיפוש מוגדר מראש בלבד - לעולם לא SQL שמגיע מהלקוח
const products = await db.products.findByName(query); // read-only
// 4. החזרת מידע מינימלי בלבד
res.json({
success: true,
data: products.map((p) => ({
product: p.name,
size: p.size,
in_stock: p.quantity > 0,
quantity: p.quantity,
})),
});
});
אותו עיקרון עובד בכל backend - Next.js API Route, PHP, Python/Flask, Firebase Function, Supabase Edge Function וכדומה: אימות מפתח, קריאה בלבד, החזרת מידע מינימלי.
# יצירת מפתח אקראי ב-Node
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# או ב-OpenSSL
openssl rand -hex 32
במקרה חשד לדליפה - החליפו (rotate) את המפתח בשני הצדדים מיד: בשרת שלכם ובכפתור "החלף API Key" בדאשבורד.
בניתם את האתר עם פלטפורמת Vibe Coding (Base44, Lovable, Bolt, v0 וכדומה)? העתיקו את ה-prompt הבא לסוכן ה-AI של הפלטפורמה - התאימו את סעיף 7 לסוג הנתונים שתרצו לחשוף - והוא ייצור עבורכם Endpoint ומפתח מאובטחים המוכנים לחיבור:
אני משתמש ב-wichat - פלטפורמת סוכני AI לעסקים. אני צריך שתיצור עבורי באתר Endpoint ייעודי ומאובטח ש-wichat תוכל לקרוא כדי לקבל נתונים בזמן אמת ממסד הנתונים של האתר.
מה לבנות:
1. צור endpoint חדש בצד השרת (backend) של האתר בנתיב ייעודי, למשל: POST /api/wichat/data
2. צור API Key ייעודי, חזק ואקראי עבור wichat בלבד (לא סיסמת מסד הנתונים ולא מפתח קיים שנותן גישה מלאה למערכת). שמור אותו כ-secret בצד השרת בלבד - לעולם לא בקוד ה-frontend. אם ביכולתך, צור את ה-API Key בעצמך ואז תגיד לי מה הוא כדי שאדביק אותו בממשק wichat, אם אתה לא יכול תגיד לי כיצד ליצור אותו ומה לרשום.
3. ה-endpoint יקבל בקשת POST עם JSON בפורמט: { "query": "<טקסט חופשי>", "read_only": true } ועם כותרת: Authorization: Bearer <API_KEY>
4. אמת את המפתח בכל בקשה (authentication + authorization). בקשה ללא מפתח תקין - החזר 401 בלי שום מידע נוסף.
5. ה-endpoint הוא קריאה בלבד (read-only): אסור לבצע בו שום יצירה, עדכון או מחיקה במסד הנתונים, בשום מקרה.
6. בצע validation על ה-input. אסור להעביר את query ישירות למסד הנתונים ואסור לאפשר SQL או שאילתות שרירותיות שמגיעות מהלקוח - השתמש בחיפוש/שליפה מוגדרים מראש בלבד.
7. החזר אך ורק את המידע הבא: [תאר כאן את המידע שברצונך לחשוף, למשל: שם מוצר, מידה, צבע, האם במלאי וכמות זמינה]
8. אסור להחזיר מידע אישי, פרטי לקוחות, כתובות, סיסמאות, פרטי תשלום, מפתחות, הערות פנימיות או כל credential.
9. פורמט התשובה: JSON מוגדר וברור, למשל:
{ "success": true, "data": [ { "product": "Nike Air Force 1", "size": "42", "in_stock": true, "quantity": 3 } ] }
10. אם אפשר - הוסף rate limiting בסיסי ל-endpoint.
לאחר שתסיים, תן לי את כתובת ה-Endpoint המלאה (HTTPS) ואת ה-API Key כדי שאזין אותם בממשק של wichat.
גישת קריאה (Read-only) ב-JSON לשיחות, לפניות ולתורים של העסקים שלכם - לחיבור CRM, אוטומציות (Make / Zapier / n8n), דשבורדים ומערכות פנימיות. זמין למנויי Business, Premium ו-Partner.
Authorization: Bearer wc_live_...כתובת בסיס: https://wichat.ai/functions/public-api. כל הבקשות הן GET. את business_key מעתיקים מכרטיס העסק בדאשבורד (אותו מפתח שמשמש ב-data-key של הווידג'ט).
| Resource | כתובת | פילטרים |
|---|---|---|
| שיחות | ?business_key=KEY&resource=conversations | status = open | closedinclude_messages = true |
| פניות | ?business_key=KEY&resource=leads | read = true | falseinclude_messages = true |
| תורים | ?business_key=KEY&resource=appointments | status = booked | cancelleddate_from, date_to (YYYY-MM-DD) |
פרמטרים משותפים: limit (ברירת מחדל 50, מקסימום 100) ו-cursor לדפדוף. התוצאות מסודרות מהחדש לישן.
curl "https://wichat.ai/functions/public-api?business_key=YOUR_BUSINESS_KEY&resource=leads&read=false&limit=20" \
-H "Authorization: Bearer wc_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
const BASE = 'https://wichat.ai/functions/public-api';
const KEY = process.env.WICHAT_API_KEY; // לעולם לא בקוד צד-לקוח
async function fetchAll(businessKey, resource, params = {}) {
const items = [];
let cursor = null;
do {
const qs = new URLSearchParams({ business_key: businessKey, resource, limit: '100', ...params });
if (cursor) qs.set('cursor', cursor);
const res = await fetch(`${BASE}?${qs}`, { headers: { Authorization: `Bearer ${KEY}` } });
if (!res.ok) throw new Error((await res.json()).error.message);
const json = await res.json();
items.push(...json.data);
cursor = json.pagination.next_cursor;
} while (cursor);
return items;
}
const appointments = await fetchAll('YOUR_BUSINESS_KEY', 'appointments', { status: 'booked', date_from: '2026-01-01' });
{
"business": { "key": "YOUR_BUSINESS_KEY", "name": "שם העסק" },
"data": [
{
"id": "6aa46b5c23ebeb8708e76fcc",
"visitor_id": "v_8f3a",
"contact_name": "דנה לוי",
"contact_phone": "050-0000000",
"contact_email": "dana@example.com",
"summary": "מתעניינת בחבילת פרימיום",
"read": false,
"created_date": "2026-09-11T20:58:04.530000",
"updated_date": "2026-09-11T20:58:04.530000"
}
],
"pagination": { "limit": 50, "has_more": true, "next_cursor": "bzo1MA" }
}
| Resource | שדות |
|---|---|
| conversations | id, visitor_id, summary, status, message_count, last_message_at, created_date, updated_date + messages[] (role, content, created_date) כאשר include_messages=true |
| leads | id, visitor_id, contact_name, contact_phone, contact_email, summary, read, created_date, updated_date + messages[] כאשר include_messages=true |
| appointments | id, visitor_id, date, start_time, end_time, duration_minutes, service_name, service_price, staff_name, customer_name, customer_phone, customer_email, customer_details, status, cancelled_at, rescheduled_from, created_date, updated_date |
כל שגיאה מוחזרת בפורמט אחיד: { "error": { "code": "...", "message": "..." } }
| HTTP | code | משמעות |
|---|---|---|
| 400 | INVALID_CURSOR | ה-cursor לא תקין - התחילו את הדפדוף מחדש. |
| 401 | UNAUTHORIZED | Header חסר או מפתח שגוי / שנמחק. |
| 403 | FORBIDDEN | העסק אינו בבעלות החשבון שאליו שייך המפתח. |
| 403 | PLAN_REQUIRED | התוכנית של החשבון אינה כוללת שיחות / פניות / תורים. |
| 404 | NOT_FOUND | business_key לא קיים או resource לא מוכר. |
| 405 | METHOD_NOT_ALLOWED | רק GET נתמך. ה-API הוא לקריאה בלבד. |
| 429 | RATE_LIMITED | עד 60 בקשות לדקה לכל מפתח. כבדו את ה-Header Retry-After. |
| בעיה | סיבות נפוצות ופתרון |
|---|---|
| הווידג'ט לא מופיע בכלל | 1) data-key חסר או שגוי - בדקו את ה-Console (הודעת [wichat]). 2) העסק מושבת בדאשבורד. 3) כיביתם "הצג במובייל"/"הצג במחשב" בהגדרות הווידג'ט. 4) בטעינה דינמית - שכחתם setAttribute('data-key', ...). |
| הווידג'ט נעלם אחרי ניווט ב-SPA | ה-Framework הסיר את תגית הסקריפט וההרס האוטומטי הופעל. אם רוצים אותו בכל הדפים - הזריקו אותו ב-HTML הראשי (index.html / layout) ולא בתוך קומפוננטת דף. |
| שני כפתורים מופיעים | הסקריפט הוזרק פעמיים (למשל גם ב-index.html וגם ב-useEffect). השאירו נקודת הזרקה אחת בלבד, וב-React ודאו cleanup ב-useEffect (חשוב במיוחד ב-StrictMode שמריץ effects פעמיים בפיתוח). |
| הסקריפט נחסם (Console: CSP) | אם לאתר יש Content-Security-Policy, הוסיפו: script-src https://wichat.ai וגם connect-src https://wichat.ai. |
| השיחה לא נשמרת בין ביקורים | ההיסטוריה נשמרת ב-localStorage. במצב גלישה פרטית / WebView ללא domStorageEnabled (Android) או ללא websiteDataStore (iOS) - כל טעינה תתחיל שיחה חדשה. |
| ב-WebView הצ'אט לא שולח הודעות | ודאו JavaScript מאופשר, שיש הרשאת אינטרנט, ושהעברתם baseUrl תקין (https://wichat.ai) בטעינת ה-HTML - בלעדיו בקשות הרשת עלולות להיחסם. |
| הכפתור מוסתר מאחורי אלמנט באתר | הווידג'ט משתמש ב-z-index מקסימלי (2147483000). אם אלמנט באתר עדיין מכסה אותו - הנמיכו את ה-z-index של אותו אלמנט, או שנו את מיקום הווידג'ט (פינה אחרת) בהגדרות בדאשבורד. |
חסרה פלטפורמה? הפתרון הכללי תמיד עובד: מצאו איפה מזריקים HTML לפני </body> בפלטפורמה שלכם, והדביקו שם את שורת הסקריפט. לשאלות נוספות - היכנסו למסך "הטמעה" בדאשבורד, שם יש גם מחולל הנחיות ל-AI (Vibe Coding) שמתאים את ההוראות לפרויקט שלכם.