Kampanya ve Widget

Segment, deney, sıklık sınırı ve custom widget

Panelde tanımladığınız kampanya ve widget'lar uygulamada da çalışır. SDK size hangi yüzeylerin bu ekranda gösterilmeye hakkı olduğunu verir; Akinon App Maker eklentisi bunları native olarak çizer.

Hangi kapılardan geçer

getSurfaces() bir yüzeyi döndürmeden önce web widget'ının sorduğu soruların aynısını sorar — ve aynı sırada. Sıra önemlidir: her adım "gereğinden fazla gösterme" yönünde koruma sağlar.

  1. Test modu. Test modundaki bir kampanya gerçek ziyaretçiye görünmez; test edene ise yalnızca o görünür. Filtre değil, kapıdır.
  2. Sayfa hedefleme. app://home, app://product gibi sentetik ekran adlarına göre. Bkz. Event Takibi.
  3. Ülke hedefleme. Ülke, isteğin IP adresinden sunucu tarafında çözülür ve yapılandırmayla birlikte uygulamaya gelir — uygulamanın bunu bilmesi gerekmez. getSurfaces() çağrısında country geçerseniz sizin değeriniz kullanılır.
  4. Deney dışlaması. Bir A/B testi kontrol yüzeyini varyantıyla değiştirdiyse kontrol çizilmez. İkisini birlikte göstermek ziyaretçiye her iki kolu aynı anda göstermek olur.
  5. Segment hedeflemesi. include modunda ziyaretçi listedeki segmentlerden en az birinde olmalı; exclude modunda hiçbirinde olmamalıdır. Segment üyeliği sunucuya sorulur ve beş dakika önbelleklenir.
  6. Boş içerik. İçeriği olmayan bir kayıt atlanır. Tek istisna custom tipidir: orada kod içeriğin kendisidir.
  7. Deney içeriği. config_override modunda varyantın içeriği kontrolün üzerine birleştirilir. Dizi değerleri değiştirilir, birleştirilmez — üç slaytlı bir varyant altı slayt olmaz.
  8. Koşullu içerik ve sepet değerleri. Kampanyanın durumları varsa eşleşen ilk durum uygulanır; gizleyen bir durum yüzeyi düşürür. Metindeki sepet değerleri uygulamanın bildirdiği sepetle doldurulur. Ayrıntı aşağıda.
  9. Çatışma çözümü. Aynı yuvayı isteyen iki yüzeyden biri gösterilir.
  10. Sıklık sınırı. Harcanmış bir kota yüzeyi düşürür.

Segment kapısı ağ hatasında ne yapar

Sunucuya ulaşılamazsa cevap "hiçbir segmentte değil" olur. Bu, include modunda göstermemek, exclude modunda göstermek demektir — web ile birebir aynı davranış. Tersi olsaydı bir kampanya ya tüm kitlesinden saklanırdı ya da bastırılmış olduğu kitleye gösterilirdi.

Çatışma çözümü: uygulamada neden daha kritik

Web'de iki widget aynı CSS seçicisini hedeflediğinde çakışır. Uygulamada çekişilen kaynak yuva konumudur: top, bottom, center. Aynı yuvaya iki duyuru çubuğu üst üste biner, iki popup aynı anda açılır.

Kurallar web ile aynıdır:

DavranışSonuç
highest_priority (varsayılan)En yüksek öncelik kazanır; eşitlikte kayıt kimliğine göre kararlı seçim
allGruptaki herkes gösterilir
randomGrubun tamamı random ise biri seçilir

Pratik sonuç: aynı ekranda aynı yuvaya iki yüzey koyarsanız biri hiç görünmez. Panelde bunu görürseniz ya ekranları ayırın ya da öncelik verin. Seçiciyle yerleştirilmiş yüzeyler uygulamada bir yuva işgal etmez, dolayısıyla hiçbir şeyle çekişmez.

Sıklık sınırı

Panelde tanımladığınız perSession, perDay, perWeek, total ve minInterval kuralları uygulamada da geçerlidir.

Uygulamada bu web'den daha önemlidir: bir web sayfası her gezinmede yeniden yüklenirken uygulama süreci ekranların ötesinde yaşar. Kota kalıcı olarak diske yazılır, yani uygulama kapanıp açıldığında da korunur.

Kota yüzey gerçekten çizildiğinde harcanır, listeye girdiğinde değil. Tetikleyicisi hiç ateşlenmemiş bir popup ya da eşiğinin altında kalan bir sayaç kotasını kaybetmez.

Koşullu içerik, sepet ve ürün değerleri

Panelde bir kampanyaya koşullu içerik eklediyseniz SDK durumu sizin yerinize seçer. getSurfaces() size kazanan durumun içeriğini verir: surface.content o durumun metinlerini taşır, surface.stateId hangi durumun kazandığını söyler (temel içerikte null). Gizleyen bir durum eşleşirse yüzey listede hiç yer almaz; çizilmediği için gösterim de yazılmaz ve çatışma çözümünde başka bir yüzeyin yuvasını almaz.

Kampanya metnindeki {cart.total} ve {cart.itemCount} değerleri de uygulamanın bildirdiği sepetle doldurulur. Bir durumun metnindeki değer söylenemiyorsa (sepet henüz bildirilmemişse ya da tutarın yazılacağı bir para birimi yoksa) o durum atlanır ve sıradaki eşleşen duruma, en sonda temel içeriğe geçilir; temel içerik de söylenemiyorsa yüzey döndürülmez. Uygulamanız hiçbir zaman ham bir süslü parantez basmaz.

Ürün değerleri ({product.title}, {product.price}, {product.originalPrice}, {product.discountAmount}, {product.discountRate}, {product.stock}) ekranın gösterdiği üründen doldurulur. Uygulamada ürünü SDK'ya siz verirsiniz, çünkü ekran ürünü zaten mağazadan almıştır:

const surfaces = await selwise.getSurfaces('app://product', {
  product: {
    title: product.name,
    price: product.price,                 // şimdiki fiyat
    originalPrice: product.retailPrice,   // indirimden önceki fiyat; indirim yoksa vermeyin
    stock: selectedVariant.stock,         // bilinmiyorsa vermeyin
    currency: 'TRY',                      // isteğe bağlı; yoksa kanalın para birimi
  },
});
  • Ürünü yalnızca ürün ekranında verin. Ürün verilmeyen bir ekranda ürün değeri kullanan durum atlanır, temel içerik de ürün değeri kullanıyorsa yüzey döndürülmez.
  • Değerler web'deki kurallarla söylenir: önceki fiyat, indirim tutarı ve indirim yüzdesi yalnızca önceki fiyat şimdiki fiyattan yüksekse, stok yalnızca sıfırdan büyükse söylenir. Sayısal bir metin de kabul edilir ('899.00').
  • Ürün değiştiğinde (başka bir ürüne geçildiğinde, ya da ürün yeniden yüklendiğinde) getSurfaces() çağrısını yeni ürünle yineleyin. Yeni ürün yüklenirken önceki ürünü vermeyin; bunun yerine product: { pending: true } verin. Ürüne bağlı metni ya da durumu olan yüzey ürün gelene kadar döndürülmez; önce temel içerik gösterilip ürün gelince değiştirilmez. Diğer yüzeyler bundan etkilenmez.
  • Aynı ürün ürün koşullarını da yanıtlar: bir durumda ya da hedeflemede Ürün stoğu, Ürün indirimde, Ürün indirim oranı (%) veya Ürün fiyatı koşulu bu üründen okunur. Ürün verilmeyen bir ekranda bu koşullar eşleşmez: durum atlanır, ürün koşuluyla hedeflenmiş yüzey döndürülmez.

Durumlar ve değerler getSurfaces() çağrıldığı andaki sepete göre seçilir. Ekranınızdaki kampanyalar sepetten söz ediyorsa onCartChange geldiğinde getSurfaces() çağrısını yineleyin. Tutarların biçimi için getSurfaces(url, { locale: 'tr-TR' }) ile görüntüleyenin dilini verebilirsiniz; verilmezse cihazın dili kullanılır.

SDK, yapılandırma isteğinde hangi değerleri doldurabildiğini ve hangi koşulları tanıdığını sunucuya bildirir. Eski bir SDK sürümü bunu bildirmez ya da daha azını bildirir, ve sunucu ona dolduramayacağı değerleri ya da tanımadığı koşulları içeren kampanyaları hiç göndermez: sepet değerlerini tanıyan ama ürün değerlerini tanımayan bir sürüm yalnızca ürün değeri kullanan kampanyaları almaz; ürün koşullarını tanımayan bir sürüm ürün koşulu taşıyan kampanyaları almaz, çünkü tanımadığı kuralı yok sayıp kampanyayı daha geniş bir kitleye gösterirdi. SDK aynı bildirimi deney atamalarını isterken de yapar; bir kolunun söylediğini ya da sorduğunu tanımayan sürüm o denemeye hiç alınmaz. Böylece eski bir uygulama sürümü de süslü parantez basmaz.

Akinon App Maker eklentisi ürünü ProductDetail ekranında uygulamanın kendi ürün durumundan otomatik verir; ürün yüklenirken { pending: true } verir, önceki ürünü hiçbir zaman vermez.

Sepet

Sepet uygulamanızın içinde yaşar, bu yüzden SDK'ya onu siz bildirirsiniz. Sepet her değiştiğinde ve uygulama açılıp sepet yüklendiğinde çağırın:

selwise.setCart({
  total: 379.8,     // indirimler düşülmüş ürün toplamı, kargo hariç
  itemCount: 3,     // sepetteki ürün adedi
  currency: 'TRY',  // isteğe bağlı; yoksa kanalın para birimi
  codes: ['4055'],  // isteğe bağlı; sepet satırlarının ürün kodları
});

selwise.getCart();  // { known: true, total: 379.8, itemCount: 3, currency: 'TRY' }

const stop = selwise.onCartChange((cart) => {
  // hedef çubuğunu yeniden çözün, sepetten söz eden ekranlarda getSurfaces() çağırın
});
  • Tutar her seferinde sepetin tamamıdır, değişen satır değil. Kargo ve hediye paketi gibi ücretler dahil edilmez, çünkü ücretsiz kargo eşiği ürün toplamına göre yazılır. Sayısal bir metin de kabul edilir ('379.80').

  • Bildirilmemiş sepet bilinmeyen sepettir. Uygulama her açılışta bilinmeyen bir sepetle başlar; sepet diske yazılmaz. Önceki açılıştan kalan bir tutar başka bir cihazda değişmiş olabilir, ve yanlış bir tutar hiç tutar olmamasından kötüdür.

  • Sepet artık bilinmiyorsa (sipariş sonrası temizlendi, ziyaretçi çıkış yaptı) setCart(null) çağırın. Sepet olmayan bir değer (negatif ya da sayısal olmayan tutar) reddedilir, false döner ve sepeti bilinmeyen yapar.

  • Bildirilen sepet hedeflemede de kullanılır: behavior geçmediğiniz getSurfaces() çağrılarında Sepet tutarı ve Sepetteki ürün adedi kuralları bu sepetle değerlendirilir. Kendi behavior değerinizi geçerseniz sizin verdiğiniz sinyaller önceliklidir; SDK yalnızca vermediğiniz sepet sinyallerini doldurur.

  • codes isteğe bağlıdır: sepet satırlarının ürün kodları (ürün kodu, SKU ya da sepet kodu). Yalnızca Kargo Bedavaya Tamamla şeridine gönderilir ve sepetteki ürünlerin o şeritte önerilmemesini sağlar; sepetin ölçülmüş sayılıp sayılmamasını etkilemez. Tutar aynı kalıp bir satır başka bir ürünle değişirse bu da sepet değişikliği sayılır ve onCartChange çağrılır.

Akinon App Maker eklentisi bunu uygulamanın kendi sepetinden otomatik yapar.

Hedef çubuğu

goal_bar tipindeki bir yüzeyin ne söyleyeceğini resolveGoalBar verir. Web widget'ı ve paneldeki önizleme de aynı hesaplamayı kullanır, yani aynı sepet her kanalda aynı cümleyi okur. Her onCartChange geldiğinde yeniden çözün ve döneni çizin:

const view = selwise.resolveGoalBar(surface, { locale: 'tr-TR' });

if (view.visible) {
  // view.text              — "Ücretsiz kargo için 401 TL kaldı"
  // view.buttonText / view.buttonUrl — duruma göre değişen buton
  // view.progress.percent  — çubuğun doluluğu, 0–100
  // view.progress.markers  — ara adımların çubuk üzerindeki yeri
}
  • visible: false ise hiçbir şey çizmeyin ve gösterim yazmayın. Sepet bilinmiyorsa, boş sepette çubuğun gösterilmesi istenmemişse ya da cümledeki bir değer söylenemiyorsa durum budur.
  • Gösterimi (trackSurfaceView) görünür bir durum ilk kez çizildiğinde yazın, yüzey listeye girdiğinde değil.
  • Butonun metni ve adresi duruma göre değişir; tıklamada surface.content değil view.buttonUrl kullanın.

Hedefe ulaşma

goal_reached, sepetin bir adımı çubuk ekrandayken geçtiği anlamına gelir. Ekranda ne olduğunu yalnızca uygulama bildiği için bu olayı siz bildirirsiniz; kural web ile aynıdır:

import { goalStepsCrossed } from '@selwise/react-native';

// Aynı çubuğun bir önceki ve yeni görünümü:
for (const step of goalStepsCrossed(previousView, nextView)) {
  selwise.trackGoalReached(surface, { step });
}
  • Yalnızca önceki görünüm görünürken geçilen adımlar sayılır. Çubuk ilk kez göründüğünde zaten geçilmiş bir adım ve çubuk gizliyken geçilen bir adım bildirilmez. Yeni görünümün görünür olması gerekmez: hedefe ulaşınca kaybolan bir çubuğun son adımı da ekranda geçilmiştir.
  • Çubuk ekrandan çıktığında (başka bir ekran, kapatma) önceki görünümü unutun; geri dönüldüğünde karşılaştırma sıfırdan başlar.
  • SDK her adımı oturum başına bir kez gönderir; uygulama yeniden açılsa da aynı oturumda tekrar göndermez. trackGoalReached gönderip göndermediğini döndürür.
  • getSurfaces() sonucundaki yüzeyi geçerseniz { step } yeterlidir; eşik ve ölçüt çubuğun içeriğinden okunur. Yalnızca kimliği tuttuysanız threshold ve metric değerlerini de geçin.
  • Hedefe ulaşma bir tıklama değildir ve ciro kredisi almaz.

Geri sayım: günlük kesim saati

Geri sayım sayacı sabit bir bitiş tarihine ya da günlük kesim saatine ("14:00'e kadar verilen siparişler bugün kargoda") sayabilir. Kesim saati mağazanın saat dilimindedir ve geçtiğinde ertesi günün aynı saatine döner. Hedef anı countdownTarget verir; her saniye yeniden sorun, bir kez okuyup saklamayın:

import { countdownTarget } from '@selwise/react-native';

const target = countdownTarget(surface.content, Date.now()); // epoch ms ya da null

null dönerse sayacı çizmeyin. Akinon App Maker eklentisi bunu her saniye yapar.

Marka teması

Panelde tanımladığınız marka teması uygulamaya da gelir. Bu kozmetik bir ayrıntı değil: widget stil varsayılanları var(--selwise-brand, …) biçimindedir, yani hiçbir rengi elle değiştirmemiş bir merchant bile bu referansları gönderir. Eklenti bunları çözer; tema tanımlı değilse referansın içindeki yedek değer kullanılır — web'de olduğu gibi.

Kendi bileşenlerinizi boyamak isterseniz tokenlara doğrudan erişebilirsiniz:

const tokens = selwise.getTheme();
// { '--selwise-brand': '#d3145a', '--selwise-brand-text': '#ffffff', ... }

Panelden gelen takip ayarları

Panelin Takip Ayarları ekranındaki değerler uygulamada da uygulanır: yığın boyutu, gönderim aralığı, çevrimdışı kalıcılık, yeniden deneme sayısı ve kuyruk sınırı.

init() çağrısında açıkça geçtiğiniz bir seçenek panelden gelene göre önceliklidir — uygulama, panelin bilemeyeceği şeyleri bilir. Panelden gelen hata ayıklama modu yalnızca açabilir: kendi isteğiyle log açmış bir uygulamayı susturmaz.

Custom widget: kendi HTML/CSS/JS'iniz

custom tipindeki bir widget uygulamada izole bir WebView içinde çalışır. İçeriği panelin HTML alanından, stilini ve kodunu ise hem içerik bloğundan hem de panelin Özel CSS / Özel JS alanlarından okur.

WebView içindeki kodunuza bir köprü açılır:

selwise.track('kupon_kullanildi', { code: 'KIKOAPP20' });
selwise.addToCart('4711', 1);
selwise.navigate('/baskets/basket/');
selwise.close();

addToCart uygulamanın kendi sepet aksiyonunu tetikler, doğrudan istek atmaz: WebView'in mağaza oturumu yoktur, oradan eklenen ürün ziyaretçinin görmediği bir sepete düşerdi. Sepet ikonundaki sayı da bu sayede güncellenir.

selwise.track ile gönderdiğiniz isim custom_event olarak kaydedilir ve verdiğiniz ad üstverisinde saklanır.

Yüksekliği ölçmeniz gerekmez; belge kendi boyunu bildirir ve WebView ona göre büyür.

Arama yönlendirmeleri

Panelde tanımlı bir arama yönlendirmesi (kargo → kargo sayfası) uygulamada da çalışır: eklenti sonuç listesi yerine hedefe götürür. Bu bir cevaptır, başarısız arama değildir — bu yüzden sıfır sonuç raporunuza yazılmaz.

Ürün zenginleştirme

Panelde yazdığınız kendi HTML/CSS içeriğiniz uygulamada da çalışır. Tek fark yerleştirmenin nasıl söylendiği: webde bir CSS seçicisi verirsiniz, uygulamada bir yuva adı.

<SelwiseEnrichment plugin={Selwise} code={product.sku} slot="pdp-specs" />

Panelde kurala pdp-specs adını verdiğinizde içerik bu ekranda görünür. Kuralı sonradan değiştirmeniz, silmeniz veya yenisini eklemeniz için uygulamada hiçbir şey yapılması gerekmez — yeni sürüm de, yapılandırma da, dağıtım da. Bu, zenginleştirmenin tamamen dinamik kalmasını sağlayan şey.

Hangi yuva adlarının tanımlı olduğunu SDK söyler:

selwise.getEnrichmentSlots();
// ['basket-shipping', 'pdp-specs']

Markup uygulamaya nasıl geliyor

Webde widget ham blokları ve bir token haritası alır, yorumlamayı ve CSS kapsamlamasını kendisi yapar — çünkü içeriği merchant'ın kendi sayfasına yerleştirir ve oradaki stillerden korunması gerekir.

Uygulamada bu gerekmez: içerik izole bir WebView'de çizilir. Bu yüzden yorumlama, temizleme (sanitize) ve CSS kapsamlaması sunucuda yapılır ve uygulamaya bitmiş markup gelir. Alternatif, bir CSS temizleyicisinin kopyasını React Native paketinin içinde taşımak olurdu — ayrışması en pahalı kod türü.

Sonuç olarak panelde onayladığınız şey ekranda görünen şeydir; iki yol aynı prepareEnrichmentBlock ve aynı DOMPurify geçişini kullanır.

Token'lar ve kendi feed alanlarınız

Webdekiyle birebir aynı: ${title}, ${brand}, ${formattedPrice}, ${imageUrl} ve besleme dosyanızın kendi alanları için ${attr.gtin}, ${attr.garanti_suresi} gibi. Kanalınız kataloğu başka bir kanaldan ödünç alıyorsa (uygulama kanallarında olağan durum) token'lar o katalogdan çözülür.

Bir yuvada birden fazla kural

Bir yuvaya birkaç kural yığılabilir — künye tablosu, altında SSS, altında kargo notu. Hepsi tek WebView içinde çizilir, ama her kural kendi kökünü korur: gösterim kural başına bir kez raporlanır, kaç blok yığdığından bağımsız olarak. Bir bağlantıya dokunulduğunda tıklama, o bağlantıyı içeren kurala atfedilir.

Segment ve test modu

Kampanya ve widget'larla aynı: segment hedeflemesi ve test modu istemcide uygulanır. Bu, bir ürün için verilen cevabın tüm ziyaretçiler için önbelleklenebilmesini sağlayan şey.

Uygulamada geçerli olmayan tek ayar

Sunucu tarafı render (SSR). Webde bir kuralı merchant'ın kendi sunucusunun çizmesini seçebilirsiniz; amacı JavaScript çalıştırmayan istemcilerdir — GPTBot, ClaudeBot, bağlantı önizleme botları. Bir uygulamayı hiçbir tarayıcı tarama yapmaz, dolayısıyla bu seçeneğin uygulamada bir karşılığı yoktur. Uygulama kanalında panel bu seçeneği hiç göstermez ve renderMode değeri uygulamadaki görünürlüğü etkilemez: SEO için server işaretlediğiniz bir kural uygulamada da görünür.

Sırada ne var

Son güncelleme: 9 Ekim 2026