• Shopify Takibi

    İçindekiler tablosu

    Kısa ve tatlı

    Shopify'ı doğrudan Varify'a bağlayın ve deneylerinizi doğrudan Shopify'daki dönüşüm ve gelir verileriyle analiz edin. Ziyaretçi sayısı GA4'ten içe aktarıldığı için entegrasyon yalnızca GA4 kullanımıyla birlikte çalışır.

    Shopify takip verileri nasıl kullanılır?

    1. Adım: Shopify veri içe aktarımını etkinleştirme

    "Takip Kurulumu "na gidin ve "Gelişmiş Kurulum" sekmesine tıklayın. Burada "Shopify Verilerini Kullan" ayarını etkinleştirin.

    Adım 2: Varify izleme koduyla özel bir piksel oluşturun

    Shopify mağazanızda "Ayarlar "a tıklayın ve "Müşteri etkinlikleri "ni açın. Ardından "Özel piksel ekle "ye tıklayın ve piksele "varify-checkout" adını verin. Ardından aşağıdaki kodu ekleyin:

    Standart Kod

    Shopify mağazanızda yalnızca tek bir para birimiyle ödeme yapılabiliyorsa bu kodu kullanın.

    				
    					let storage;
    async function getVarifyData() {
      if (storage) {
        return storage;
      }
      storage = (async () => {
        try {
          const raw = await browser.localStorage.getItem('varify-data');
          return raw ? JSON.parse(raw) : {};
        } catch (error) {
          // Cache nicht dauerhaft vergiften: nach Fehler zuruecksetzen,
          // damit der naechste Aufruf erneut versucht statt still tot zu bleiben.
          storage = undefined;
          console.error('Varify: error reading local storage', error);
          return {};
        }
      })();
      return storage;
    }
    
    analytics.subscribe('varify', async (event) => {
      const {
        varify_experimentId,
        varify_variationId,
        teamId,
        storageType = 'localStorage',
      } = event.customData || {};
    
      if (!varify_experimentId || !teamId) {
        console.warn('Varify: event missing experimentId or teamId.');
        return;
      }
    
      const validVariationId =
        varify_variationId !== undefined ? varify_variationId : null;
    
      const existingData = await getVarifyData();
    
      if (!existingData.data) {
        existingData.data = [];
      }
    
      const experimentEntry = {
        experimentId: varify_experimentId,
        variationId: validVariationId,
        timestamp: Date.now(),
      };
    
      existingData.data = existingData.data.filter(
        (entry) => entry.experimentId !== varify_experimentId
      );
    
      existingData.data.push(experimentEntry);
      existingData.teamId = teamId;
      existingData.storageType = storageType;
    
      await browser.localStorage.setItem(
        'varify-data',
        JSON.stringify(existingData)
      );
    });
    
    const WINDOW_MS = 28 * 24 * 60 * 60 * 1000;
    
    const pruneEntries = (entries) => {
      const threshold = Date.now() - WINDOW_MS;
      return (entries || []).filter(
        (entry) => entry.timestamp && entry.experimentId && entry.timestamp >= threshold
      );
    };
    
    analytics.subscribe('checkout_started', async (event) => {
      const existingData = await getVarifyData();
      if (!existingData.data || existingData.data.length === 0) {
        return;
      }
    
      existingData.data = pruneEntries(existingData.data);
    
      await browser.localStorage.setItem(
        'varify-data',
        JSON.stringify(existingData)
      );
    });
    
    analytics.subscribe('checkout_completed', async (event) => {
      const orderId = event.data?.checkout?.order?.id;
      const orderRevenue = event.data?.checkout?.subtotalPrice?.amount;
    
      // 0 is a valid revenue (100% discount) and must not count as missing.
      if (!orderId || orderRevenue == null) {
        console.warn('Varify: checkout_completed missing orderId or revenue.');
        return;
      }
    
      const parsedData = await getVarifyData();
      if (!parsedData.data || parsedData.data.length === 0 || !parsedData.teamId) {
        console.warn('Varify: no valid data in local storage.');
        return;
      }
    
      // The order-status page refires checkout_completed on every visit.
      if (!Array.isArray(parsedData.sentOrders)) {
        parsedData.sentOrders = [];
      }
      if (parsedData.sentOrders.includes(orderId)) {
        return;
      }
    
      parsedData.data = pruneEntries(parsedData.data);
      if (parsedData.data.length === 0) {
        return;
      }
    
      const storedAccountId = parsedData.teamId;
      const experiments = parsedData.data.map((entry) => {
        return [entry.experimentId, entry.variationId];
      });
    
      const storageType = parsedData.storageType;
    
      const storeHandle = init.data?.shop?.myshopifyDomain?.replace('.myshopify.com', '');
    
      const lineItems = event.data?.checkout?.lineItems;
      let cartProducts = [];
    
      if (lineItems && Array.isArray(lineItems)) {
        cartProducts = lineItems
          .map((item) => {
            const productId = item.variant?.product?.id?.split("/").pop();
            const variantId = item.variant?.id?.split("/").pop();
    
            if (productId && variantId) {
              return {
                productId,
                variantId,
              };
            }
            return null;
          })
          .filter((p) => p !== null);
      }
    
      try {
        await fetch('https://ecommerce.varify.io/store_data', {
          method: 'POST',
          keepalive: true,
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            experiments,
            orderId,
            orderRevenue,
            accountId: storedAccountId,
            storageType: storageType,
            storeHandle,
            cartProducts,
          }),
        });
    
        parsedData.sentOrders = [...parsedData.sentOrders, orderId].slice(-50);
        await browser.localStorage.setItem('varify-data', JSON.stringify(parsedData));
      } catch (error) {
        console.error('Varify: error sending data', error);
      }
    });
    				
    			

    Çoklu Para Birimi Kodu

    Shopify mağazanızda birden fazla para birimiyle ödeme yapılabiliyorsa bu kodu kullanın.

    				
    					let storage;
    
    const SHOP_CURRENCY = init.data?.shop?.paymentSettings?.currencyCode || 'EUR';
    
    const FX_API = 'https://api.frankfurter.dev/v1/latest';
    const FX_TTL_MS = 6 * 60 * 60 * 1000;
    const FX_TIMEOUT_MS = 2000;
    
    async function getVarifyData() {
      if (storage) {
        return storage;
      }
      storage = (async () => {
        try {
          const raw = await browser.localStorage.getItem('varify-data');
          return raw ? JSON.parse(raw) : {};
        } catch (error) {
          // Reset so the next call retries instead of caching a poisoned promise.
          storage = undefined;
          console.error('Varify: error reading local storage', error);
          return {};
        }
      })();
      return storage;
    }
    
    // Returns units of <currency> per 1 <SHOP_CURRENCY>, or null. null => do not send.
    async function getFxRate(currency) {
      const cacheKey = `varify-fx-${SHOP_CURRENCY}-${currency}`;
    
      try {
        const cached = await browser.localStorage.getItem(cacheKey);
        if (cached) {
          const { rate, ts } = JSON.parse(cached);
          if (rate && ts && Date.now() - ts < FX_TTL_MS) {
            return rate;
          }
        }
      } catch (error) {
        // Broken cache -> fetch fresh below.
      }
    
      try {
        const url = `${FX_API}?from=${encodeURIComponent(SHOP_CURRENCY)}&to=${encodeURIComponent(currency)}`;
    
        let res;
        if (typeof AbortController === 'function') {
          const controller = new AbortController();
          const timer = setTimeout(() => controller.abort(), FX_TIMEOUT_MS);
          try {
            res = await fetch(url, { signal: controller.signal });
          } finally {
            clearTimeout(timer);
          }
        } else {
          res = await fetch(url);
        }
    
        if (!res.ok) {
          console.warn(`Varify: FX API returned ${res.status} for ${currency}.`);
          return null;
        }
    
        const json = await res.json();
        const rate = json?.rates?.[currency];
    
        if (typeof rate !== 'number' || !isFinite(rate) || rate <= 0) {
          console.warn(`Varify: FX API gave no usable rate for ${currency}.`, json);
          return null;
        }
    
        await browser.localStorage.setItem(
          cacheKey,
          JSON.stringify({ rate, ts: Date.now() })
        );
        return rate;
      } catch (error) {
        console.warn(`Varify: FX lookup failed for ${currency}.`, error);
        return null;
      }
    }
    
    analytics.subscribe('varify', async (event) => {
      const {
        varify_experimentId,
        varify_variationId,
        teamId,
        storageType = 'localStorage',
      } = event.customData || {};
    
      if (!varify_experimentId || !teamId) {
        console.warn('Varify: event missing experimentId or teamId.');
        return;
      }
    
      const validVariationId =
        varify_variationId !== undefined ? varify_variationId : null;
    
      const existingData = await getVarifyData();
    
      if (!existingData.data) {
        existingData.data = [];
      }
    
      const experimentEntry = {
        experimentId: varify_experimentId,
        variationId: validVariationId,
        timestamp: Date.now(),
      };
    
      existingData.data = existingData.data.filter(
        (entry) => entry.experimentId !== varify_experimentId
      );
    
      existingData.data.push(experimentEntry);
      existingData.teamId = teamId;
      existingData.storageType = storageType;
    
      await browser.localStorage.setItem(
        'varify-data',
        JSON.stringify(existingData)
      );
    });
    
    const WINDOW_MS = 28 * 24 * 60 * 60 * 1000;
    
    const pruneEntries = (entries) => {
      const threshold = Date.now() - WINDOW_MS;
      return (entries || []).filter(
        (entry) => entry.timestamp && entry.experimentId && entry.timestamp >= threshold
      );
    };
    
    analytics.subscribe('checkout_started', async (event) => {
      const existingData = await getVarifyData();
      if (!existingData.data || existingData.data.length === 0) {
        return;
      }
    
      existingData.data = pruneEntries(existingData.data);
    
      await browser.localStorage.setItem(
        'varify-data',
        JSON.stringify(existingData)
      );
    
      // Warm the rate while the customer is still typing.
      const currency = event.data?.checkout?.currencyCode;
      if (currency && currency !== SHOP_CURRENCY) {
        getFxRate(currency);
      }
    });
    
    analytics.subscribe('checkout_completed', async (event) => {
      const orderId = event.data?.checkout?.order?.id;
      const money = event.data?.checkout?.subtotalPrice;
      let orderRevenue = money?.amount;
      const orderCurrency = money?.currencyCode;
    
      // 0 is a valid revenue (100% discount) and must not count as missing.
      if (!orderId || orderRevenue == null || !orderCurrency) {
        console.warn('Varify: checkout_completed missing orderId, revenue or currency.');
        return;
      }
    
      // subtotalPrice is presentment currency; the event carries no rate or shop-money
      // amount, and /store_data books the number as shop currency. Convert here, or skip.
      if (orderCurrency !== SHOP_CURRENCY) {
        const rate = await getFxRate(orderCurrency);
        if (!rate) {
          console.warn(
            `Varify: skipping order ${orderId} — ${orderRevenue} ${orderCurrency}, no FX rate available.`
          );
          return;
        }
        const converted = +(orderRevenue / rate).toFixed(2);
        console.info(
          `Varify: converted order ${orderId} — ${orderRevenue} ${orderCurrency} @ ${rate} -> ${converted} ${SHOP_CURRENCY}.`
        );
        orderRevenue = converted;
      }
    
      const parsedData = await getVarifyData();
      if (!parsedData.data || parsedData.data.length === 0 || !parsedData.teamId) {
        console.warn('Varify: no valid data in local storage.');
        return;
      }
    
      // The order-status page refires checkout_completed on every visit.
      if (!Array.isArray(parsedData.sentOrders)) {
        parsedData.sentOrders = [];
      }
      if (parsedData.sentOrders.includes(orderId)) {
        return;
      }
    
      parsedData.data = pruneEntries(parsedData.data);
      if (parsedData.data.length === 0) {
        return;
      }
    
      const storedAccountId = parsedData.teamId;
      const experiments = parsedData.data.map((entry) => {
        return [entry.experimentId, entry.variationId];
      });
    
      const storageType = parsedData.storageType;
    
      const storeHandle = init.data?.shop?.myshopifyDomain?.replace('.myshopify.com', '');
    
      const lineItems = event.data?.checkout?.lineItems;
      let cartProducts = [];
    
      if (lineItems && Array.isArray(lineItems)) {
        cartProducts = lineItems
          .map((item) => {
            const productId = item.variant?.product?.id?.split("/").pop();
            const variantId = item.variant?.id?.split("/").pop();
    
            if (productId && variantId) {
              return {
                productId,
                variantId,
              };
            }
            return null;
          })
          .filter((p) => p !== null);
      }
    
      try {
        await fetch('https://ecommerce.varify.io/store_data', {
          method: 'POST',
          keepalive: true,
          headers: {
            'Content-Type': 'application/json',
          },
    
          body: JSON.stringify({
            experiments,
            orderId,
            orderRevenue,
            // Already converted above; always shop currency so a future server-side
            // conversion is a no-op, not a double conversion.
            orderCurrency: SHOP_CURRENCY,
            accountId: storedAccountId,
            storageType: storageType,
            storeHandle,
            cartProducts,
          }),
        });
    
        parsedData.sentOrders = [...parsedData.sentOrders, orderId].slice(-50);
        await browser.localStorage.setItem('varify-data', JSON.stringify(parsedData));
      } catch (error) {
        console.error('Varify: error sending data', error);
      }
    });
    				
    			

    Kodu ekledikten sonra kaydet'e tıklayın. Ayrıca izinlerinizin doğru ayarlandığını kontrol edin, aksi takdirde bir kullanıcı izni eksikse komut dosyası yürütülmeyecektir. Ardından "Bağlan "a tıklayın. Entegrasyon artık başarıyla kurulmuştur.

    3. Adım: Denemenize Shopify Hedefleri ekleyin

    İzleme kurulumunuzun ayarlandığından ve izleme sağlayıcısı olarak GA4'ü seçtiğinizden ve "Test Değerlendirmesi" öğesinin "Varify ve GA4'te" olarak ayarlandığından emin olun. Bu durumda, başlatılan deneyin sağ üst kısmında "yeni oluşturulan" deneyler için bir "Sonuçlar Bağlantısı" görünecektir. 

    "Sonuçlar Bağlantısı "na tıkladığınızda denemenin ilgili sonuç raporu açılır. Artık hedef olarak "Dönüşümler" veya "Gelir" eklemek için "Shopify Hedefi Ekle "ye tıklayabilirsiniz. Hedefin ziyaretçileri GA4'ten alınır. Dönüşüm değeri ve gelir değeri doğrudan Shopify'dan gelir.

    Önemli: GA4 verileri yalnızca yaklaşık 24 saat sonra güncellenir. Shopify'dan alınan veriler gerçek zamanlı olarak güncellenir.

    Sonuç raporunda ürün filtresi

    A/B testinizde belirli ürünlerin performansını analiz edin. Tek tek ürünleri veya ürün varyantlarını analiz edebilirsiniz. Bunu yapmak için, alana virgülle ayırarak bir ürün kimliği veya birkaç kimlik girin.

  • İlk adımlar