Passa al contenuto principale

Tracciamento Shopify

Ultimo aggiornamento il 16 lug 20262 min di lettura

In breve​

Collega Shopify direttamente a Varify e analizza i tuoi esperimenti direttamente con i dati di conversione e fatturato di Shopify. L'integrazione funziona solo insieme all'utilizzo di GA4, poiché il numero di visitatori viene importato da GA4.

Valutazione degli obiettivi Varify con due obiettivi: „Conversions“ migliora del 9,49 % ed è significativo, „Revenue“ del 9,73 % con un livello di confidenza del 94,28 % e non lo è

Come utilizzare i dati di tracciamento Shopify​

Passo 1: Attiva l'importazione dei dati Shopify​

Vai su „Tracking Setup“ e clicca sulla scheda „Advanced Setup“. Qui, attiva l'impostazione „Use Shopify Data“.

Advanced setup di Varify con „Start Tracking on Activation Event“ e „Use Shopify Data“ entrambi attivati

Passo 2: Crea un custom pixel con il codice di tracciamento Varify​

Shopify «Customer events» con una freccia che indica il pulsante «Add custom pixel» sopra l'elenco dei pixel

Clicca su "Settings" nel tuo negozio Shopify e apri "Customer events". Poi clicca su "Add custom pixel" e assegna al pixel il nome: "varify-checkout". Quindi inserisci il seguente codice:

Codice Standard​

Usa questo codice se il tuo negozio Shopify accetta pagamenti in una sola valuta.

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);
}
});

Codice Multi-Valuta

Usa questo codice se il tuo negozio Shopify supporta pagamenti in più valute.

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);
}
});

Dopo aver aggiunto il codice, clicca su salva. Controlla anche che i tuoi permessi siano impostati correttamente, altrimenti lo script non verrà eseguito se manca un permesso utente. Poi clicca su «Connect». L'integrazione è ora installata con successo.

Il pixel creato «varify-checkout» con il suo codice che si sottoscrive all'evento «varify» e legge i dati della variazione

Passo 3: Aggiungi Shopify Goals al tuo esperimento​

Assicurati che il tuo tracking setup sia configurato e di aver selezionato GA4 come tracking provider e che la voce «Test Evaluation» sia impostata su «In Varify and GA4». Se è così, apparirà ora un «Results Link» per gli esperimenti «appena creati» in alto a destra dell'esperimento avviato.

Facendo clic su "Results Link" si apre il relativo report dei risultati dell'esperimento. Ora puoi aggiungere "Conversions" o "Revenue" come obiettivo cliccando su "Add Shopify Goal". I visitatori dell'obiettivo vengono presi da GA4. Il valore di conversione e il valore di revenue provengono direttamente da Shopify.

Importante: i dati di GA4 vengono aggiornati solo dopo circa 24 ore. I dati di Shopify vengono aggiornati in tempo reale.

Valutazione degli obiettivi Varify con due obiettivi: „Conversions“ migliora del 9,49 % ed è significativo, „Revenue“ del 9,73 % con un livello di confidenza del 94,28 % e non lo è

Filtro prodotti nel report dei risultati​

Analizza le performance di specifici prodotti nel tuo A/B test. Puoi osservare singoli prodotti o varianti di prodotto. Per farlo, inserisci un ID prodotto o più ID nel campo, separati da virgole.