Реалізація lead nurturing на сайті
Lead nurturing — автоматизована серія комунікацій, яка «підігріває» ліда від першого дотику до покупки. Включає email-цепочки, триггерні листи, персоналізований контент та ремаркетинг на основі поведінки користувача.
Архітектура системи
Реєстрація/підписка → Визначення сегмента → Enroll у sequence →
→ Таймер + умови → Відправлення листа → Відстеження відкриттів та кліків →
→ Перехід в іншу sequence при виконанні цільової дії
Модель даних
Schema::create('nurture_sequences', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('trigger'); // 'trial_started', 'whitepaper_downloaded', 'pricing_page_3x'
$table->json('conditions')->nullable(); // {"plan": "free", "source": "organic"}
$table->boolean('is_active')->default(true);
$table->timestamps();
});
Schema::create('nurture_emails', function (Blueprint $table) {
$table->id();
$table->foreignId('sequence_id')->constrained('nurture_sequences')->cascadeOnDelete();
$table->integer('delay_hours'); // Відправити через N годин після попередника
$table->string('subject');
$table->string('template'); // Ім'я Blade-шаблону
$table->json('conditions')->nullable(); // Додаткові умови відправлення
$table->integer('order')->default(0);
});
Schema::create('nurture_enrollments', function (Blueprint $table) {
$table->id();
$table->foreignId('sequence_id')->constrained('nurture_sequences');
$table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
$table->string('email');
$table->integer('current_step')->default(0);
$table->enum('status', ['active', 'completed', 'exited', 'converted'])->default('active');
$table->timestamp('next_email_at')->nullable();
$table->timestamp('converted_at')->nullable();
$table->timestamps();
});
Сервіс управління послідовностями
class NurtureService
{
public function enroll(string $email, string $trigger, array $context = [], ?int $userId = null): void
{
// Знаходимо підходящі послідовності для триггеру
$sequences = NurtureSequence::active()
->where('trigger', $trigger)
->get()
->filter(fn($seq) => $this->matchesConditions($seq->conditions, $context));
foreach ($sequences as $sequence) {
// Не записуємо якщо вже в активній послідовності
$existing = NurtureEnrollment::where('sequence_id', $sequence->id)
->where('email', $email)
->whereIn('status', ['active'])
->exists();
if ($existing) continue;
$firstEmail = $sequence->emails()->orderBy('order')->first();
NurtureEnrollment::create([
'sequence_id' => $sequence->id,
'user_id' => $userId,
'email' => $email,
'current_step' => 0,
'next_email_at' => now()->addHours($firstEmail->delay_hours ?? 0),
]);
}
}
public function exit(string $email, string $reason = 'manual'): void
{
NurtureEnrollment::where('email', $email)
->where('status', 'active')
->update(['status' => 'exited']);
}
public function markConverted(string $email): void
{
NurtureEnrollment::where('email', $email)
->where('status', 'active')
->update(['status' => 'converted', 'converted_at' => now()]);
}
private function matchesConditions(?array $conditions, array $context): bool
{
if (!$conditions) return true;
foreach ($conditions as $key => $value) {
if (($context[$key] ?? null) != $value) return false;
}
return true;
}
}
Job для відправлення листів за розкладом
// Запускається кожні 15 хвилин через Scheduler
class ProcessNurtureEmails implements ShouldQueue
{
public function handle(): void
{
$enrollments = NurtureEnrollment::where('status', 'active')
->where('next_email_at', '<=', now())
->with(['sequence.emails'])
->get();
foreach ($enrollments as $enrollment) {
$emails = $enrollment->sequence->emails->sortBy('order');
$currentEmail = $emails->get($enrollment->current_step);
if (!$currentEmail) {
$enrollment->update(['status' => 'completed']);
continue;
}
// Перевіряємо додаткові умови кроку
if ($currentEmail->conditions && !$this->checkStepConditions($enrollment, $currentEmail->conditions)) {
// Пропускаємо крок
$this->advanceToNextStep($enrollment, $emails);
continue;
}
// Перевіряємо чи не відписався користувач
if (EmailUnsubscribe::where('email', $enrollment->email)->exists()) {
$enrollment->update(['status' => 'exited']);
continue;
}
// Відправляємо лист
Mail::to($enrollment->email)->queue(
new NurtureEmail($enrollment, $currentEmail)
);
$this->advanceToNextStep($enrollment, $emails);
}
}
private function advanceToNextStep(NurtureEnrollment $enrollment, Collection $emails): void
{
$nextStep = $enrollment->current_step + 1;
$nextEmail = $emails->get($nextStep);
if ($nextEmail) {
$enrollment->update([
'current_step' => $nextStep,
'next_email_at' => now()->addHours($nextEmail->delay_hours),
]);
} else {
$enrollment->update(['status' => 'completed', 'current_step' => $nextStep]);
}
}
}
Приклад послідовності для trial
День 0: "Добро пожаловати! Ось як почати" → Онбординг
День 1: "3 функції, що економлять час" → Цінність
День 3: "Відео: як інші компанії користуються нами" → Соціальний доказ
День 5: "Ти використав функцію X?" → Engagement-чек (відправляємо тільки якщо не використав)
День 7: "Твій trial закінчується через 7 днів" → Urgency
День 10: "Спеціальна пропозиція для тебе" → Офер
День 14: "Що тобі сподобалося/не сподобалося?" → CSAT + збереження
Триггери для виходу з послідовності
// Observer за покупками
class OrderObserver
{
public function created(Order $order): void
{
// При покупці — виходимо з усіх nurture-послідовностей
app(NurtureService::class)->markConverted($order->user->email);
}
}
// При підключенні до CRM — теж сповіщаємо систему
class HandleCrmOpportunityCreated
{
public function handle(): void
{
app(NurtureService::class)->exit($this->email, reason: 'crm_opportunity');
}
}
Аналітика послідовностей
-- Конверсія за послідовностями
SELECT
s.name,
COUNT(e.id) AS enrolled,
COUNT(e.id) FILTER (WHERE e.status = 'converted') AS converted,
ROUND(100.0 * COUNT(e.id) FILTER (WHERE e.status = 'converted') / NULLIF(COUNT(e.id), 0), 1) AS conversion_rate,
ROUND(AVG(EXTRACT(EPOCH FROM (e.converted_at - e.created_at)) / 3600)) AS avg_hours_to_convert
FROM nurture_sequences s
LEFT JOIN nurture_enrollments e ON e.sequence_id = s.id
GROUP BY s.id, s.name
ORDER BY conversion_rate DESC;
Тривалість
Повна система lead nurturing з послідовностями, умовами та аналітикою: 10–14 робочих днів.







