Blog
Mağaza platformu olmadan e-ticaret etkinlikleri: Kendi ödeme akışınızdan GA4'e veri göndermek
Yayınlandı · Güncellendi · 5 dk okuma
Bir mağaza platformu size en azından boğuşacağınız bir eklenti sunar. Kendi kurduğunuz bir ödeme akışı — bir React uygulaması, bir rezervasyon akışı, arkasında Stripe olan bir SaaS kaydı — size hiçbir şey vermez: kendi kodunuz göndermedikçe hiçbir etkinlik tetiklenmez. İyi haber şu ki sözleşme küçük: bir avuç ad, tek bir nesne yapısı ve her gönderimin nereye ait olduğuna dair birkaç kural. Hepsi burada; çoğu rehberin atladığı kısım da dahil: sayfanızda kimse yokken gerçekleşen satın almalar.
Sözleşme: bir ad ve bir ecommerce nesnesi
Buradaki her şey Analytics'e aynı yoldan ulaşır. Sayfanız window.dataLayer'a GA4 adıyla bir etkinlik gönderir (push) ve bu etkinlik GA4 biçiminde bir ecommerce nesnesi taşır. Bir Tag Manager tetikleyicisi adı eşleştirir, bir GA4 etkinlik etiketi de nesneyi okuyup sunucu konteynerinize iletir. Her SignalHost konteynerinin web konteynerinde bu tetikleyiciler ve etiketler, SH önekiyle adlandırılmış olarak zaten bulunur — aşağıdaki mağaza etkinlikleri için ve ayrıca kayıtlar, deneme sürümleri ve potansiyel müşteriler için. Geriye kalan, gönderimin kendisidir.
İki kural hataların çoğunu yakalar. Önce önceki ecommerce nesnesini temizleyin; yoksa üç sayfa önceki bir view_item bir sonraki etkinliğin içinde onunla birlikte gider. Ve para taşıyan her etkinlikte value değerini sayı olarak, currency değerini ISO kodu olarak gönderin: metin olarak gönderilen bir value ya da eksik bir currency hiçbir uyarı vermeden kabul edilir ve sessizce gelirin dışında bırakılır.
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'begin_checkout',
ecommerce: {
currency: 'EUR',
value: 49.00,
items: [
{ item_id: 'plan-pro', item_name: 'Pro', price: 49.00, quantity: 1 }
]
}
});Hangi etkinlik, nereye ait
Özel bir akışta da bir mağaza platformundakiyle aynı anlar vardır. Yalnızca onları kendi kodunuzda bulmanız gerekir.
- view_item_list — birden fazla ürün ya da plan gösteren bir sayfa veya bileşen. Liste gösterildiğinde bir kez; her kaydırmada değil.
- view_item — tek bir ürün ya da plan sayfası.
- add_to_cart ve remove_from_cart — düğmenin işleyicisinde, sepetiniz gerçekten değiştikten sonra.
- view_cart — sepet gösterildiğinde: sepet sayfası ya da açılan sepet çekmecesi.
- begin_checkout — ziyaretçinin ödemeye geçtiği an: ödeme sayfasının ilk render'ı ya da bir ödeme penceresini açan tıklama.
- add_shipping_info — bir gönderim yöntemi seçildiğinde. Hiçbir şey kargolamıyorsanız bunu atlayın.
- add_payment_info — ödeme bilgileri kabul edildiğinde; form göründüğünde değil.
- purchase — sipariş onaylandığında, bir kez. Bu yazının büyük kısmı bunu doğru yapmakla ilgili.
- sign_up ve start_trial — abonelik işletmeleri için, para el değiştirmeden önceki dönüşümler. SignalHost ikisi için de mağaza etkinliklerinin yanında etiketler oluşturur; potansiyel müşteriler için de: generate_lead, contact, schedule, submit_application ve subscribe.
Gönderimi bir render'dan değil, değişikliğe neden olan işleyiciden yapın. Tek sayfalık bir uygulama serbestçe yeniden render edilir ve React, geliştirme ortamında efektleri iki kez çalıştırır: bir efektin içindeki gönderim geliştirme derlemesinde ikiye katlanır ve bir bileşen her yeniden bağlandığında (remount) tekrarlanır.
Onay sayfanızdaki satın alma: siparişi sunucunuzdan okuyun
Ziyaretçi ödeme yaptıktan sonra sizin sayfalarınızdan birine geri döndüğünde, purchase o sayfaya aittir — iki koşulla. Siparişi URL'den değil, kendi arka ucunuzdan alın: sorgu parametreleri düzenlenebilir, yönlendirmeler sırasında silinebilir ve başarısız ödemelerde de gelir. Örneğin Stripe, ödeme gerçekleşse de gerçekleşmese de aynı adrese geri döner ve hangisinin olduğunu kendine ait bir parametrede bildirir. Ve gönderimi bir kez yapın: sayfayı yeniden yüklemek, geri düğmesi ya da yer imlerine eklenmiş bir makbuz sayfası, hepsi o sayfaya geri döner.
// On your confirmation page. The order comes from YOUR server, by an id the
// page already knows — never from price or status parameters in the URL.
const order = await fetch(`/api/orders/${orderId}`).then((r) => r.json());
const key = `purchase-sent-${order.id}`;
if (order.status === 'paid' && !localStorage.getItem(key)) {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: order.id,
value: order.total,
tax: order.tax,
currency: order.currency,
items: order.items.map((i) => ({
item_id: i.sku, item_name: i.name, price: i.price, quantity: i.quantity
}))
}
});
localStorage.setItem(key, '1');
}transaction_id bir plan değil, bir güvenlik ağıdır. Analytics aynı oturum içinde tekrarlanan bir transaction_id değerini atar, ancak makbuz sayfasının ertesi sabah yeniden yüklenmesini atmaz.
Başkasının sayfasında ödeme: Stripe Checkout, PayPal, banka yönlendirmesi
Barındırılan bir ödeme sayfası, özel yapılar için olağan tercihtir ve keskin bir kenarı vardır: ziyaretçi hiç geri dönmeyebilir. Öder, sekmeyi kapatır ve onay sayfanız hiç yüklenmez. Kartlarda bu, satın almaların yüzde birkaçıdır. Banka havalesi, fatura ve sonra öde yöntemlerinde ise çoğunluğu olabilir, çünkü para saatler ya da günler sonra gelir.
Bu yüzden her ödeme yöntemi için gerçeğin nerede olduğuna karar verin. Arka ucunuz ödemeyi bir webhook'tan öğreniyorsa, onu raporlamanın güvenilir yeri webhook'tur — bir sonraki bölüme bakın — ve onay sayfası ayrıca purchase göndermemelidir; yoksa her kartlı ödeme iki kez sayılır. Ödemeyi öğrendiğiniz tek yer dönüş sayfasıysa, orada raporlayın ve aradaki boşluğu kabul edin.
Hiçbir tarayıcının görmediği satın almalar: onları sunucunuzdan gönderin
Abonelikler bunu kaçınılmaz kılar. Bir deneme sürümü yedi gün sonra ücretliye dönüşür, bir yenileme her ay gerçekleşir, bir fatura gelecek hafta havaleyle ödenir. Her biri bir satın almadır ve hiçbiri bir tarayıcının önünde gerçekleşmez. Çözüm, etkinliği sunucudan sunucuya göndermektir: ödemeyi öğrenen webhook'tan, sayfalarınızın kullandığı etiketleme uç noktasının aynısına — SignalHost adresiniz ya da kendi alan adınız — böylece diğer her hit gibi sunucu konteynerinizden geçer.
Bunun için ödeme adımından tek bir şey gerekir: ziyaretçinin Analytics istemci kimliği (client id); böylece satın alma, ziyaretleri ona yol açan kişiye kaydedilir. Bu kimlik _ga çerezindedir ve ödeme isteğiniz kendi alan adınıza gittiğinde bu çerezi zaten taşır. Onu siparişle birlikte saklayın. _ga çerezi yoksa ziyaretçi analiz iznini vermemiş demektir: hiti tek kullanımlık bir kimlikle, izin reddedilmiş olarak gönderin ya da hiç göndermeyin — o ziyaretçi için asla bir kimlik uydurmayın. Dönüşümleri Google Ads, Meta, TikTok veya diğer reklam platformlarına da iletiyorsanız, ziyaretçinin reklam tercihini siparişle birlikte saklayın ve izin verdiyse G111 gönderin: G101 olarak işaretlenmiş bir satın alma Analytics'e ulaşır, ancak reklam platformlarının hiçbirine ulaşmaz ve Google Ads onu bir tıklamaya bağlayamaz.
// In your checkout request handler: keep the visitor's Analytics id with the order.
const ga = req.cookies._ga; // "GA1.1.1234567890.1700000000"
order.gaClientId = ga ? ga.split('.').slice(-2).join('.') : null;
// Later, in your payment webhook — a trial converting, an invoice paid:
const params = new URLSearchParams({
v: '2',
tid: 'G-XXXXXXXXXX', // your GA4 measurement ID
cid: order.gaClientId ?? `${Date.now()}.${Math.floor(Math.random() * 1e9)}`,
gcs: order.gaClientId ? 'G101' : 'G100', // no _ga cookie = no consent
en: 'purchase',
'ep.transaction_id': invoice.id,
'epn.value': '49.00',
cu: 'EUR',
pr1: 'idplan-pro~nmPro~pr49.00~qt1',
});
await fetch(`https://metrics.example.com/g/collect?${params}`, { method: 'POST' });Her etkinlik için tek bir kaynak seçin ve ona bağlı kalın. signalhost.io kendi satışlarını tam olarak böyle ölçer: tarayıcı sign_up, begin_checkout ve add_payment_info gönderir; sunucumuz start_trial etkinliğini ancak bir deneme sürümü gerçekten başladığında gönderir, böylece kapanan bir sekme onu kaybettiremez; Stripe webhook'u da ilk fatura ödendiğinde purchase gönderir. Hiçbir etkinliğin iki kaynağı yoktur. Google'ın Measurement Protocol'ü de işe yarardı, ancak doğrudan Google'a gider ve sunucu konteynerinizi atlar; böylece sunucu tarafı etiketlerinizin hiçbiri satışı görmez.
Geç gelen satın almalar, GA4'ün sipariş listenizden daha az saymasının dört nedeninden biridir: diğer üçü ve hangilerini düzeltebileceğiniz.
İzin sizden ek bir şey istemez
Ziyaretçi ne seçerse seçsin etkinlikleri gönderin. Etiketler Consent Mode (izin modu) kurallarına uyar: izin varsa normal şekilde gönderir; yoksa Analytics'in raporlamak yerine modellediği çerezsiz ping'ler gönderir. Gönderimleri kendiniz durdurmanız, dönüşümleri yalnızca bu modellemeden gizler. Asıl önemli olan sıralamadır — Tag Manager kod parçacığı çerez bildiriminizin betiğinden sonra gelir; böylece izin varsayılanları ilk etkinlik gönderilmeden önce hazır olur.
Çalıştığını kontrol edin
- Konteyneri SignalHost'ta açın. Etkinlikler kartı ulaşanları ada göre, izin taşıyan paylarıyla birlikte listeler. Gönderdiğiniz ama orada görmediğiniz bir ad, etiketleme sunucunuza hiç ulaşmamıştır.
- Ödeme akışınızı Tag Manager'ın Preview modunda baştan sona deneyin. Her gönderimi, hangi etiketin tetiklendiğini ve gönderilen ecommerce nesnesini gösterir.
- Analytics'te DebugView etkinlikleri geldikleri anda gösterir. Standart raporlar bir gün sürebilir.
- Onay sayfasını iki kez yeniden yükleyin ve satın almaları sayın. Yine bir olmalı.
Buradaki hataların hepsi sessizdir: büyük/küçük harfi yanlış yazılmış bir ad, metin olarak gönderilen value, bir seviye fazla iç içe geçmiş items. Hiçbiri hiçbir yerde hata üretmez. Her biri, içinde bir boşluk olan bir rapor üretir.

