הערה: כאשר מוצר נגמר מהמלאי, 80% מהקונים פונים למתחרים ולעולם לא חוזרים. טופס ההרשמה 'הודע על הגעה' הופך את האובדן הזה לליד: אתה מקבל את פרטי הקשר של אדם מתעניין ויכול להחזיר אותו בדיוק כשהמוצר חוזר למלאי. אנו מיישמים Back in Stock במפתח מלא תוך 1-2 ימי עסקים, עם אינטגרציה ל-CRM שלך ולכל ערוצי התקשורת (אימייל, טלגרם, SMS). למהנדסים שלנו יש ניסיון של 5+ שנים במסחר אלקטרוני; אנו מבטיחים פעילות יציבה של ההתראות גם בעומסי שיא. עלות הפיתוח מתחילה בדרך כלל ב-$500 לאינטגרציה בסיסית ויכולה להגיע עד $1,500 להגדרה רב-ערוצית עם אינטגרציה ל-CRM. עסקים מדווחים על החזרה של עד 30% מהמכירות האבודות, מה שמתורגם לאלפי דולרים בהכנסות נוספות. צור קשר להערכת פרויקט וקבל ייעוץ.
איך מערכת ההתראות עובדת?
המערכת מורכבת ממספר מודולים: טופס frontend, API להרשמה, תור משימות לשליחת התראות ומנגנון הגנה מפני כפילויות. נבחן כל אחד על הדוגמה של מחסנית Laravel + React, אך היישום אפשרי על כל פלטפורמה.
סכמת נתונים
CREATE TABLE back_in_stock_requests (
id BIGSERIAL PRIMARY KEY,
product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE,
variant_id BIGINT REFERENCES product_variants(id) ON DELETE CASCADE,
user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
email VARCHAR(255) NOT NULL,
notified_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_bis_email_product ON back_in_stock_requests(email, product_id, COALESCE(variant_id, 0)) WHERE notified_at IS NULL;אינדקס ייחודי מונע הרשמות כפולות מאותו אימייל לאותו מוצר/וריאנט עד לשליחת ההתראה.
טופס הרשמה
הטופס מוצג במקום כפתור 'הוסף לסל' כאשר CREATE TABLE back_in_stock_requests ( id BIGSERIAL PRIMARY KEY, product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE CASCADE, variant_id BIGINT REFERENCES product_variants(id) ON DELETE CASCADE, user_id BIGINT REFERENCES users(id) ON DELETE SET NULL, email VARCHAR(255) NOT NULL, notified_at TIMESTAMP, created_at TIMESTAMP DEFAULT NOW() ); CREATE UNIQUE INDEX idx_bis_email_product ON back_in_stock_requests(email, product_id, COALESCE(variant_id, 0)) WHERE notified_at IS NULL; :
const BackInStockForm = ({ product, variant }: BackInStockProps) => {
const { user } = useAuth();
const [submitted, setSubmitted] = useState(false);
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm({
defaultValues: { email: user?.email ?? '' },
});
const onSubmit = async (data: { email: string }) => {
await api.post('/back-in-stock', {
product_id: product.id,
variant_id: variant?.id ?? null,
email: data.email,
});
setSubmitted(true);
};
if (submitted) {
return (
<div className="flex items-center gap-2 text-green-600 text-sm">
<CheckIcon className="w-4 h-4" />
<span>Мы сообщим, когда товар появится в наличии</span>
</div>
);
}
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-2">
<p className="text-sm text-gray-600">Товара нет в наличии. Оставьте email — уведомим при поступлении.</p>
<div className="flex gap-2">
<input
type="email"
placeholder="[email protected]"
className="flex-1 border rounded px-3 py-2 text-sm"
{...register('email', { required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ })}
/>
<Button type="submit" size="sm" loading={isSubmitting}>
Уведомить
</Button>
</div>
{errors.email && <p className="text-red-500 text-xs">Введите корректный email</p>}
</form>
);
}; נקודת קצה API להרשמה
public function subscribe(Request $request): JsonResponse
{
$request->validate([
'product_id' => 'required|exists:products,id',
'variant_id' => 'nullable|exists:product_variants,id',
'email' => 'required|email|max:255',
]);
// Проверяем, что товар действительно не в наличии
$product = Product::find($request->product_id);
if ($product->stock > 0) {
return response()->json(['message' => 'Товар уже в наличии'], 422);
}
BackInStockRequest::firstOrCreate(
[
'product_id' => $request->product_id,
'variant_id' => $request->variant_id,
'email' => strtolower($request->email),
'notified_at' => null,
],
[
'user_id' => $request->user()?->id,
]
);
return response()->json(['message' => 'Подписка оформлена']);
} למה חשוב להודיע על הגעה?
מוצר עם אפס מלאי אינו ביקוש אבוד אלא ביקוש דחוי. התראות מחזירות עד 30% מלקוחות כאלה. הרשמה בטופס יעילה פי 2–3 בהמרה בהשוואה לחלונות קופצים, מכיוון שהיא לא מפריעה למשתמש בכוח. בנוסף, אנליטיקת הרשמות עוזרת לחזות ביקוש: מוצרים עם מספר גבוה של ממתינים הם אות להזמין מחדש מהספק. בהשוואה לאימייל, התראות טלגרם יעילות פי 2 בהנעת רכישות, בעוד SMS יקר פי 3 אך מניב המרה פי 2. בממוצע, 20% מהנרשמים רוכשים תוך 24 שעות מההתראה. זמן ההמתנה החציוני הוא 4 ימים.
איך לבחור ערוץ התראה?
| ערוץ | המרה | עלויות | מהירות |
|---|---|---|---|
| אימייל | 15-25% | נמוכה (~$10 לחודש עבור 1000 נרשמים) | איטית |
| טלגרם | 30-40% | בינונית (בוט חינם, עלויות API אופציונליות) | מהירה |
| SMS | 50-60% | גבוהה ($0.02/הודעה) | מיידית |
אימייל הוא אפשרות חסכונית להתראות המוניות, אך שיעורי הפתיחה נמוכים יותר. טלגרם ו-SMS מספקים המרה גבוהה יותר, במיוחד למוצרים דחופים. אנו מחברים כל ערוץ שתבחר.
שליחה אוטומטית כשהמלאי מתחדש
הטריגר מופעל כשהמלאי מתעדכן. זה יכול לקרות דרך ייבוא מ-1С/ERP, עדכון ידני בפאנל הניהול או API של ספק. אנו משתמשים בתור (Redis/Beanstalkd) לשליחה אסינכרונית כדי למנוע חסימה של ה-thread הראשי.
// Observer на модели Product — объединяем проверку и отправку
class ProductObserver
{
public function updated(Product $product): void
{
if ($product->isDirty('stock') && $product->stock > 0 && $product->getOriginal('stock') === 0) {
NotifyBackInStockSubscribers::dispatch($product)->onQueue('notifications');
}
}
}
class NotifyBackInStockSubscribers implements ShouldQueue
{
public function handle(): void
{
$requests = BackInStockRequest::where('product_id', $this->product->id)
->whereNull('variant_id')
->whereNull('notified_at')
->get();
foreach ($requests as $request) {
Mail::to($request->email)->queue(new BackInStockNotification($this->product, $request));
$request->update(['notified_at' => now()]);
}
}
} תכונות למוצרים עם וריאנטים
אם למוצר יש מידות או צבעים, ההתראה חייבת להתחשב בווריאנט הספציפי. בסכמת הנתונים, השדה stock = 0 מאפשר הרשמה למודיפיקציה הרצויה. כאשר רק הווריאנט הנבחר מגיע, רק אלה שחיכו לו יקבלו את ההתראה. זה מגביר רלוונטיות והמרה.
התראה באימייל
האימייל מכיל:
- תמונה ושם המוצר
- מחיר עדכני עם הנחות
- קישור ישיר למוצר עם תג UTM
const BackInStockForm = ({ product, variant }: BackInStockProps) => { const { user } = useAuth(); const [submitted, setSubmitted] = useState(false); const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm({ defaultValues: { email: user?.email ?? '' }, }); const onSubmit = async (data: { email: string }) => { await api.post('/back-in-stock', { product_id: product.id, variant_id: variant?.id ?? null, email: data.email, }); setSubmitted(true); }; if (submitted) { return ( <div className="flex items-center gap-2 text-green-600 text-sm"> <CheckIcon className="w-4 h-4" /> <span>Мы сообщим, когда товар появится в наличии</span> </div> ); } return ( <form onSubmit={handleSubmit(onSubmit)} className="space-y-2"> <p className="text-sm text-gray-600">Товара нет в наличии. Оставьте email — уведомим при поступлении.</p> <div className="flex gap-2"> <input type="email" placeholder="[email protected]" className="flex-1 border rounded px-3 py-2 text-sm" {...register('email', { required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ })} /> <Button type="submit" size="sm" loading={isSubmitting}> Уведомить </Button> </div> {errors.email && <p className="text-red-500 text-xs">Введите корректный email</p>} </form> ); }; - אזהרה: 'כמות מוגבלת – מהרו לקנות'
האימייל נשלח פעם אחת – public function subscribe(Request $request): JsonResponse { $request->validate([ 'product_id' => 'required|exists:products,id', 'variant_id' => 'nullable|exists:product_variants,id', 'email' => 'required|email|max:255', ]); // Проверяем, что товар действительно не в наличии $product = Product::find($request->product_id); if ($product->stock > 0) { return response()->json(['message' => 'Товар уже в наличии'], 422); } BackInStockRequest::firstOrCreate([ 'product_id' => $request->product_id, 'variant_id' => $request->variant_id, 'email' => strtolower($request->email), 'notified_at' => null, ], [ 'user_id' => $request->user()?->id, ]); return response()->json(['message' => 'Подписка оформлена']); } רושם את זמן השליחה. אין התראות חוזרות.
ביטול הרשמה
קישור 'ביטול הרשמה' באימייל מוביל אל // Observer на модели Product — объединяем проверку и отправку class ProductObserver { public function updated(Product $product): void { if ($product->isDirty('stock') && $product->stock > 0 && $product->getOriginal('stock') === 0) { NotifyBackInStockSubscribers::dispatch($product)->onQueue('notifications'); } } } class NotifyBackInStockSubscribers implements ShouldQueue { public function handle(): void { $requests = BackInStockRequest::where('product_id', $this->product->id) ->whereNull('variant_id') ->whereNull('notified_at') ->get(); foreach ($requests as $request) { Mail::to($request->email)->queue(new BackInStockNotification($this->product, $request)); $request->update(['notified_at' => now()]); } } } . הטוקן הוא חתימת HMAC של האימייל ו-product_id, המונעת זיוף. לאחר לחיצה, ההרשמה מוסרת ללא צורך בהתחברות.
אנליטיקה
| מדד | תיאור |
|---|---|
| הרשמות פעילות | מספר האימיילים הממתינים להגעת המוצר |
| המרה לרכישה | % מהנרשמים שרכשו את המוצר לאחר ההתראה (דרך UTM) |
| זמן המתנה ממוצע | מהרשמה ועד הגעת המוצר |
| חלק הרכישה | % שהצליחו לקנות לפני שהמלאי נגמר שוב |
מוצרים עם מספר גבוה של הרשמות הם עדיפות להזמנה חוזרת מהספק. לדוגמה, אם 50 אנשים נרשמו למוצר ורק 10 יחידות הגיעו, כדאי להגדיל את ההזמנה.
מה אם ההתראה לא עבדה?
מצב נדיר אך אפשרי: המוצר הגיע אך ההתראה לא נשלחה. בדרך כלל הסיבה היא כשל בתור המשימות או מצב מלאי שגוי. אנו מגדירים ניטור (התראות בטלגרם/Slack) וניסיון חוזר אוטומטי. ביישום הבסיסי, התור משתמש במנגנוני הניסיון החוזר של Laravel: אם אימייל לא נשלח, הוא נשלח שוב לאחר 60 שניות, עד 3 ניסיונות.
תוצרים
פיתוח Back in Stock במפתח מלא כולל:
- אינטגרציה של טופס ההרשמה לכרטיס המוצר
- API לשמירת הרשמות עם ולידציה
- תור התראות (אימייל, אופציונלית טלגרם/SMS)
- תבניות אימייל עם עיצוב רספונסיבי
- מנגנון ביטול הרשמה ולוח אנליטיקה
- תיעוד (תיעוד API, מדריך אינטגרציה לטופס)
- קוד (גישה למאגר Git)
- הדרכה לצוות שלך (מפגש של שעה)
- תמיכה: 30 יום לאחר העלייה לאוויר, 8/5 תגובה תוך 4 שעות
למידע נוסף על מנגנון Back in Stock, ניתן לקרוא בויקיפדיה.
מדריך יישום שלב-אחר-שלב
- אינטגרציית טופס: הוסף את קומפוננטת React לדפי מוצר שבהם stock=0. ודא שהקומפוננטה מרנדרת באופן מותנה לפי כמות המלאי.
- הגדרת API: צור את נקודת הקצה להרשמה עם ולידציה ובדיקת מלאי. הגדר הגבלת קצב כדי למנוע ניצול לרעה.
- תצורת תור: הגדר Redis עם 5 עובדים לעומס גבוה. התקן דרייבר תור כמו Redis או Beanstalkd.
- תבנית אימייל: עצב את אימייל ההתראה עם מידע דינמי על המוצר ותגי UTM. השתמש בשירות אימייל טרנזקציונלי כמו SendGrid.
- קישור ביטול הרשמה: יישם ביטול הרשמה מבוסס טוקן באמצעות HMAC. הקישור צריך להיות חלק מהכותרת התחתונה של האימייל.
- בדיקות: שלח הרשמות בדיקה וודא מסירת אימייל. בדוק סיווג כספאם והתאם רשומות DKIM/SPF.
- עלייה לאוויר: פרוס לסביבת הייצור ונטר במשך 24 שעות. הגדר לוגים לכשלי תור והתראות.







