Kampanya Raporları
Kampanya bittiğinde asıl soru “kaç kişi arandı” değil — “bu kampanya para kazandırdı mı?” Kampanya raporları tam bunu gösterir: 420 çağrının maliyeti ne oldu, kaçı gerçek görüşmeye döndü, kaç randevu açıldı ve bu maliyet hangi kaleme (konuşma tanıma, model, ses, hat) gitti. İki rapor var — ROI raporu her kampanyada çalışır; A/B raporu ise iki varyantı istatistiksel olarak karşılaştırıp “hangisi gerçekten kazandı, yoksa bu fark rastlantı mı?” sorusunu cevaplar.
İki rapor, iki soru
| Rapor | Cevapladığı soru | Uç nokta |
|---|---|---|
| ROI raporu | Kampanya kaça mal oldu, ne kazandırdı? Maliyet nereye gitti? | GET /api/campaigns/{id}/roi |
| A/B raporu | A ve B varyantından hangisi kazandı — ve bu istatistiksel olarak anlamlı mı? | GET /api/campaigns/{id}/ab-report |
Her iki rapor da panelde ilgili kampanyanın detay ekranından açılır; oturum (giriş) yetkisiyle çalışır ve sadece kendi kampanyalarını gösterir.
Dönüşüm ve maliyet her planda çalışır — süre ve cost_breakdown verisinden hesaplanır. Ama sonuç dağılımı, randevu sayısı ve duygu metrikleri AI Çağrı Analizi’ne dayanır (Premium özellik). Asistanında çağrı analizi kapalıysa bu alanlar boş/sıfır görünebilir.
ROI raporu
ROI = “return on investment”, yani yatırımın geri dönüşü. Rapor, kampanyaya ait tüm çağrıları okur, her çağrının maliyet kırılımını ve AI analizini toplar, sonra tek bir tabloya indirger.
Kampanya çağrıları biter
↓
Her çağrının cost_breakdown + AI analizi okunur
↓
Toplanır: maliyet (stt / llm / tts / sip) + sonuç + randevu + SMS
↓
ROI raporu: özet metrikler + maliyet kırılımı + sonuç dağılımıÖzet metrikler
Raporun summary bölümü, kampanyanın tek bakışta özetidir:
| Alan | Ne anlatır |
|---|---|
totalCalls | Kampanyada denenen toplam çağrı (başarılı + başarısız hepsi). |
completedCalls | Durumu completed olan, yani karşı tarafın açtığı çağrılar. |
successfulCalls | Tamamlanmış ve 30 saniyeden uzun süren çağrılar. 30 saniyenin altı meşgul/hatalı sayılır. |
conversionRate | successfulCalls ÷ totalCalls × 100. Yani tüm denemelerin yüzde kaçı gerçek görüşmeye döndü (sadece açılanların değil). |
avgDuration | Tamamlanan çağrılara bölünmüş toplam görüşme süresi (saniye). |
appointmentsBooked | AI analizinde başarıyla tamamlanmış booking (randevu) aksiyonlarının sayısı. |
smsSent | AI analizinde başarıyla gönderilmiş sms aksiyonlarının sayısı. |
Dönüşüm oranı beklediğinden düşük mü? Payda totalCalls — meşgul, cevapsız ve 30 saniyeden kısa çağrılar da bu paydanın içinde. Yani “arananların yüzde kaçı ile konuşabildik” sorusunun cevabı. Cevapsız çağrılar çoksa oran düşer; bu bir hata değil, gerçeğin ta kendisi. Cevaplanma oranını ayrı görmek için completedCalls / totalCalls’a bak.
Maliyet kırılımı
Her çağrının maliyeti dört ayrı sağlayıcının toplamıdır. Rapor bunları kampanya genelinde toplar (cost.breakdown). Bir sesli çağrının maliyetini şöyle düşün: karşı taraf konuşur (tanıma), asistan düşünür (model), asistan konuşur (ses) ve tüm bunlar bir telefon hattı üzerinden akar (hat).
| Kalem | Neyin karşılığı |
|---|---|
stt | Konuşma tanıma — karşı tarafın söylediklerini metne çeviren servis (Speech-to-Text). |
llm_input | Modele giren token — asistanın prompt’u, bilgi tabanı bağlamı ve o ana kadarki konuşma. |
llm_output | Modelin ürettiği token — asistanın söylediği her cümle. |
tts | Ses üretimi — metni doğal sese çeviren servis (Text-to-Speech). Uzun konuşan asistanlarda en büyük kalem genelde budur. |
sip | Telefon hattı — dakika bazlı hat/SIP ücreti. Görüşme uzadıkça artar. |
Ayrıca cost.total (kampanyanın toplam maliyeti) ve cost.avgPerCall (çağrı başına ortalama maliyet, 6 ondalık hassasiyetle) döner.
Kırılımın toplamı, total’dan biraz düşük çıkabilir. Sağlayıcı kırılımı yalnızca cost_breakdown verisi olan çağrılardan toplanır. Çok eski çağrılarda bu ayrıntı yoksa, o çağrının maliyeti total’a yansır ama kalem kalem dağılıma girmez. Yeni çağrılarda bu fark oluşmaz.
Kalem bazında birim fiyatların (dakika/1000 karakter/1M token) hesap genelindeki güncel karşılıkları için: Maliyet ve Gecikme.
Sonuç dağılımı
outcomes nesnesi, her çağrının AI analizinden çıkan outcome (sonuç) etiketini sayar. Böylece “132 kişi ilgilendi, 40 kişi reddetti, 102 kişi açmadı” gibi bir dağılım görürsün. Etiket üretilmemiş çağrılar unknown altında toplanır. Sık görülen etiketler:
| Etiket | Anlamı |
|---|---|
interested | İlgilendi (pipeline’da “değerlendiriyor”a taşınır). |
appointment_scheduled | Randevu oluştu (“karar aşaması”). |
callback_scheduled | Tekrar aranma sözü verildi. |
information_provided | Bilgi verildi, net karar yok. |
rejected | Reddetti (“kaybedildi”). |
no_answer | Açmadı. |
unknown | AI analizi bir etiket üretmedi. |
Örnek yanıt
{
"campaign": {
"id": "1842",
"name": "Ağustos Sıcak Lead'ler",
"status": "completed",
"createdAt": "2026-08-01T09:00:00.000Z"
},
"summary": {
"totalCalls": 420,
"completedCalls": 318,
"successfulCalls": 205,
"conversionRate": 49,
"avgDuration": 138,
"appointmentsBooked": 37,
"smsSent": 88
},
"cost": {
"total": 42.815,
"avgPerCall": 0.10194,
"breakdown": {
"stt": 6.204,
"llm_input": 9.881,
"llm_output": 7.442,
"tts": 14.903,
"sip": 4.385
}
},
"outcomes": {
"interested": 132,
"appointment_scheduled": 37,
"callback_scheduled": 41,
"information_provided": 27,
"rejected": 40,
"no_answer": 102,
"unknown": 41
}
}Bu örnekte kampanya 42,815 birim maliyetle 37 randevu açmış. Çağrı başına maliyet 0,10194 — yani bir randevunun maliyeti kabaca 42,815 ÷ 37 ≈ 1,16 birim. İşte “ROI” bu iki sayının oranıdır.
📸 [Ekran görüntüsü: Kampanya detayı → ROI sekmesi, özet kartları + maliyet kırılımı grafiği]
A/B raporu
İki farklı açılış cümlesi mi deniyorsun? İki farklı asistan mı? A/B testi kampanyanın çağrılarını iki gruba (A ve B) böler; bu rapor da iki grubu yan yana koyar. Ama en kritik kısmı sadece “hangisi daha yüksek” demez — bu farkın rastlantı olup olmadığını ölçer.
Rapor yalnızca kampanyada A/B testi açıksa (abTestEnabled) çalışır; kapalıysa 400 döner. Her varyant için şu metrikler hesaplanır:
| Metrik | Açıklama |
|---|---|
totalCalls | O varyanttaki çağrı sayısı. |
completedCalls | Açılan (tamamlanan) çağrılar. |
successfulCalls | Tamamlanmış ve en az 30 saniye süren çağrılar. |
conversionRate | successfulCalls ÷ totalCalls × 100. |
avgDuration | Ortalama görüşme süresi (saniye). |
totalCost / avgCostPerCall | Varyantın toplam ve çağrı başına maliyeti. |
sentimentPositive / sentimentNegative | AI analizinin “olumlu” / “olumsuz” işaretlediği görüşme sayısı. |
Rapor ayrıca splitRatio (A ve B arasındaki trafik dağılımı), winner (dönüşüm oranı yüksek olan varyant ya da tie) ve recommendation (öneri metni) döndürür.
İstatistiksel anlamlılık
Diyelim A yüzde 43, B yüzde 62 dönüştü. B daha iyi görünüyor — ama sadece 8 çağrıya bakıyorsan bu fark tamamen şans eseri olabilir. İstatistiksel anlamlılık işte bunu ayıklar: gözlemlediğin farkın gerçek mi yoksa gürültü mü olduğunu söyler.
Rapor bunu bir iki-oran z-testi ile yapar:
En az 30 çağrı şartı
Anlamlılık hesabı yalnızca her iki varyant da en az 30 çağrıya ulaştığında yapılır (minSampleSize: 30). Altındaysa sonuç statisticallySignificant: false kalır ve “daha fazla veri gerekli” önerisi döner. Bu, küçük örneklemle yanlış karar vermeni engeller.
Ortak oran ve standart hata
İki varyantın başarılı çağrıları birleştirilerek ortak bir dönüşüm oranı (pooled rate) bulunur; buradan farkın standart hatası (se) hesaplanır. Basitçe: “iki oran arasındaki fark, tesadüfle ne kadar oynayabilirdi?“
z değeri ve yüzde 95 güven
İki dönüşüm oranı arasındaki fark, standart hataya bölünerek bir z değeri elde edilir. Bu değer eşik olan 1.96’yı aşarsa fark yüzde 95 güvenle anlamlı kabul edilir (p < 0.05). Yani “bu farkın şans eseri olma ihtimali yüzde 5’ten az”.
“Kazanan” görünmesi yeterli değil. winner alanı her zaman doludur (dönüşümü yüksek olan varyant), ama statisticallySignificant false ise bu kazananı kalıcı bir karar için kullanma. Örneklem 30’un altındaysa ya da fark küçükse, “kazanan” bir sonraki gün rahatlıkla yer değiştirebilir. Kararı anlamlılık true olduğunda ver.
Örnek yanıt
{
"campaign": { "id": "1907", "name": "Eylül Deneme — Açılış Cümlesi" },
"splitRatio": 50,
"variantA": {
"variant": "A",
"totalCalls": 140,
"completedCalls": 108,
"successfulCalls": 60,
"conversionRate": 43,
"avgDuration": 127,
"totalCost": 13.9,
"avgCostPerCall": 0.099286,
"sentimentPositive": 52,
"sentimentNegative": 18
},
"variantB": {
"variant": "B",
"totalCalls": 145,
"completedCalls": 121,
"successfulCalls": 90,
"conversionRate": 62,
"avgDuration": 148,
"totalCost": 15.62,
"avgCostPerCall": 0.107724,
"sentimentPositive": 78,
"sentimentNegative": 9
},
"winner": "B",
"statisticallySignificant": true,
"minSampleSize": 30,
"recommendation": "Variant B is the winner with statistical significance (p<0.05)."
}Burada B varyantı yüzde 62 dönüşümle, hem daha çok olumlu duygu (78) hem de anlamlı bir farkla kazanmış. Artık B’yi tüm kampanyaya güvenle yayabilirsin.
📸 [Ekran görüntüsü: A/B raporu — A ve B kartları yan yana, “İstatistiksel olarak anlamlı” rozeti]
Metrikleri doğru okumak
- “Başarılı” = tamamlanmış + 30 saniye. Açılıp hemen kapanan çağrı başarı sayılmaz. Bu yüzden başarı sayısı, açılma sayısından her zaman düşüktür — bu doğru davranıştır.
- Dönüşüm oranı tüm denemeler üzerinden hesaplanır, sadece açılanlar üzerinden değil. Cevapsız çağrı çoksa oran düşük görünür; asistanın performansı değil, listenin ulaşılabilirliği zayıf olabilir.
- Maliyeti kalem kalem oku.
ttsçok yüksekse asistan gereğinden uzun konuşuyor olabilir;sipyüksekse görüşmeler uzun. Her ikisi de prompt ile kısaltılabilir. - A/B’de sabırlı ol. 30 çağrıya ulaşmadan “kazanan” ilan etme. Anlamlılık rozeti çıkana kadar test açık kalsın.
KVKK notu
Raporlar özet sayı gösterse de, altlarındaki çağrılar kayıt, transkript ve AI analizi içerir — bunlar kişisel veridir. Raporlara yalnızca kampanyanın sahibi (oturum yetkisiyle) erişebilir; başka bir hesabın kampanyası 404 döner. Aradığın kişi görüşmede “aramayın / verimi silin” derse, asistan onu otomatik olarak arama listesinden çıkarır ve sonraki kampanyalara dahil etmez.
Sorun giderme
| Belirti | Olası neden / çözüm |
|---|---|
| ROI raporu tamamen sıfır | Kampanyada henüz çağrı yok ya da çağrılar başladı ama tamamlanmadı. |
| Sonuç dağılımı / randevu / duygu boş | AI Çağrı Analizi kapalı (Premium). Maliyet ve dönüşüm yine de dolu olur. |
Maliyet kırılımı toplamı, total’dan düşük | Eski çağrılarda cost_breakdown yok; maliyet toplama girer ama kalem dağılımına girmez. |
appointmentsBooked 0 ama randevu aldınız | Asistana booking aksiyonu bağlı değil ya da AI analizi randevuyu yakalamadı. |
A/B raporu 400 hatası | Kampanyada A/B testi açık değil. A/B testini etkinleştir. |
statisticallySignificant hep false | Bir varyant henüz 30 çağrıya ulaşmadı; testi açık tut. |
| Kazanan var ama anlamlılık yok | Fark rastlantı olabilir; örneklem büyüyene kadar karar verme. |
| Dönüşüm oranı çok düşük | Çoğu çağrı 30 saniyenin altında (meşgul/cevapsız). Listeyi ve arama saatlerini gözden geçir. |