Questa guida è pensata per gli sviluppatori che creano pagine storefront personalizzate. Se ti serve solo una pagina fedeltà già pronta, usa invece la Shopify Loyalty Hub.

Lo Storefront SDK è una piccola libreria JavaScript che l'app JeriCommerce aggiunge al tuo tema Shopify. Dà alle tue pagine gli stessi dati e le stesse azioni che usa la Loyalty Hub: punti, livello e avanzamento del cliente, premi, codici sconto, modi per guadagnare, cronologia punti e carta wallet.

Tu scrivi HTML, stili e layout. Al resto pensa l'SDK: fa accedere il cliente tramite Shopify, chiama l'API di JeriCommerce, mette in cache ciò che leggi, aggiorna i dati dopo ogni azione e avvisa la pagina quando qualcosa cambia.

Quando usare l'SDK

  • Vuoi una pagina fedeltà con un design tutto tuo, oltre quello che permettono le impostazioni della Loyalty Hub.
  • Vuoi mostrare i dati fedeltà in altri punti del tema, come l'header, il carrello o una pagina prodotto.
  • Vuoi aprire il widget JeriCommerce dai tuoi pulsanti, oppure nascondere il suo launcher in alcune pagine.

Configurazione

1

Attiva l'app embed SDK

Vai su Shopify Admin > Online Store > Themes > Customize > App embeds e attiva SDK dell'app JeriCommerce. Salva il tema.

Questo app embed carica l'SDK in ogni pagina del negozio. È lo stesso embed che mostra il widget storefront. Il widget è facoltativo: puoi disattivarlo in JeriCommerce e l'SDK continua a funzionare.

2

Aggiungi il codice al tema

Aggiungi la tua pagina come sezione del tema (ad esempio sections/jeri-loyalty.liquid) e inserisci quella sezione in un template di pagina. La guida alla pagina fedeltà personalizzata illustra ogni passaggio con un template completo.

3

Aspetta l'SDK prima di usarlo

Esegui il codice come script differito, come modulo o dopo DOMContentLoaded. Poi verifica che l'SDK sia installato e aspettalo con JeriCommerce.ready().

Quando l'app embed SDK è disattivato, window.JeriCommerce non esiste. Controllalo sempre e mostra un breve messaggio al posto di una pagina rotta.

Avvio rapido

<div data-jeri-points>Loading your points...</div>

<script type="module">
  const box = document.querySelector("[data-jeri-points]");

  if (!window.JeriCommerce) {
    box.textContent = "Loyalty is not available right now.";
  } else {
    const jeri = await window.JeriCommerce.ready();
    const session = await jeri.auth.getSession();

    if (!session.authenticated) {
      box.innerHTML = '<button type="button">Sign in to see your points</button>';
      box.querySelector("button").addEventListener("click", () => jeri.auth.login());
    } else {
      const render = data => {
        box.textContent = `You have ${data?.customer.loyaltyData?.balance ?? 0} points`;
      };
      render(await jeri.customer.get());
      jeri.on("customer:updated", render);
    }
  }
</script>

JeriCommerce.ready() scarica l'SDK la prima volta che lo chiami e restituisce sempre la stessa istanza. Non carica alcun dato finché non chiami un metodo.

Come funziona l'accesso

L'SDK agisce sempre per conto del cliente che ha effettuato l'accesso al tuo negozio Shopify. Gli stati sono solo due:

  • Visitatore: auth.getSession() restituisce { authenticated: false }. I dati pubblici funzionano (programma, livelli, premi pubblici, modi per guadagnare, boost pubblici). customer.get() e customer.getTierProgress() restituiscono null. I metodi indicati come Customer nella reference vengono rifiutati con il codice di errore authentication_required.
  • Cliente connesso: { authenticated: true }. Tutto funziona per quel cliente.

L'SDK non accetta mai un token, un'email o un id cliente, quindi una pagina non può mai leggere o modificare i dati di un altro cliente. Per chiedere a un visitatore di accedere, chiama jeri.auth.login(). Lo porta al login di Shopify e poi di nuovo alla pagina corrente, oppure alla pagina che passi come returnTo.

Cosa succede dopo un'azione

Quando un cliente riscatta un premio, completa un modo per guadagnare o aggiorna il profilo:

  1. La promise si risolve subito con il risultato di quell'azione, ad esempio il codice sconto di un premio riscattato. Mostralo immediatamente.
  2. L'SDK segna come non aggiornati i dati coinvolti, così la lettura successiva non restituisce mai i dati precedenti all'azione.
  3. In background rilegge i dati che la tua pagina aveva già caricato e invia gli eventi corrispondenti, come customer:updated con il nuovo saldo.

La tua pagina non ha mai bisogno di chiamare refresh() dopo un'azione. Iscriviti agli eventi che mostri e renderizza di nuovo quando vengono emessi. Lo storico dei punti, il link di referral e i link del wallet non hanno un evento. Per tenere aggiornato lo storico, chiama di nuovo history.list() quando viene emesso customer:updated.

Metodi

Ogni metodo restituisce una promise. I metodi contrassegnati come Customer richiedono un cliente connesso e vengono rifiutati con authentication_required per i visitatori. I metodi contrassegnati come Public funzionano per tutti.

Sessione e programma
Metodo Accesso Si risolve con
auth.getSession() Public { authenticated: boolean }
auth.login({ returnTo? }) Public Porta il visitatore al login di Shopify. returnTo è un percorso del tuo negozio che inizia con /, altrimenti la chiamata viene rifiutata con invalid_argument. Di default, la pagina corrente
program.get() Public Program
config.get() Public ProgramConfig. widget contiene le impostazioni attive del widget
Cliente
Metodo Accesso Si risolve con
customer.get() Public CustomerData, oppure null per un visitatore
customer.getTierProgress() Public TierProgressStatus, oppure null per un visitatore
customer.updateProfile(fields) Customer Customer. fields: { firstName?, lastName?, phone?, birthdate? }
customer.updatePreferences(preferences) Customer Customer. Vedi preferenze
Livelli e premi
Metodo Accesso Si risolve con
tiers.list() Public Tier[]
rewards.list({ scope: "public" }) Public PublicRewardDto[], il catalogo per i visitatori
rewards.list({ scope: "customer" }) Customer Reward[], con redeemable per questo cliente
rewards.claim({ rewardId, pointsToRedeem? }) Customer ClaimedReward. pointsToRedeem, un numero intero positivo, solo per i premi di tipo dynamic
Codici sconto e modi per guadagnare
Metodo Accesso Si risolve con
discounts.list({ page?, limit? }) Customer PaginatedCustomerCouponCodes
earnings.list() Public EngagementFlowWithProgramEngagementFlowDto[]
earnings.execute({ earningId, action: "flow" }) Customer ExecuteCustomEarningFlowResponseDto
earnings.execute({ earningId, action: "click", linkId }) Customer Niente. Registra il clic su un social network di un earning Follow us
Boost, referral, storico e wallet
Metodo Accesso Si risolve con
boosts.list({ scope, window? }) Public o Customer CustomerBoostsResponseDto. scope è "public" o "customer"
referrals.getLink() Public Il link referral del cliente, oppure null
history.list({ page?, limit? }) Customer PaginatedTransactions
wallet.getLinks() Public Link { ios, android, generic } per aggiungere la carta fedeltà a un wallet, oppure null
wallet.sendEmail() Customer Niente. Invia via email la carta wallet al cliente
Widget, refresh ed eventi
Metodo Accesso Si risolve con
widget.open({ page? }) Public Apre il widget. page è una delle pagine del widget
widget.close() Public Chiude il widget
widget.showLauncher() / widget.hideLauncher() Public Mostra o nasconde il pulsante del widget in questa visualizzazione della pagina
refresh() Public Rilegge la sessione e tutte le risorse che la tua pagina aveva già caricato
on(event, callback) Public Una funzione che rimuove l'iscrizione

Se ometti page e limit, l'API usa i propri valori predefiniti.

Dati che puoi mostrare

Tutti i risultati sono gli oggetti dell'API di JeriCommerce, invariati. Questi sono i campi che userai più spesso.

CustomerData

Restituito da customer.get() e inviato con customer:updated.

Campo Tipo Descrizione
customer.email string Email del cliente
customer.userData.firstName / lastName string Nome del profilo
customer.loyaltyData.balance number Punti che il cliente può spendere
customer.loyaltyData.referralLink string Link referral (disponibile anche con referrals.getLink())
customer.customerTier.currentTier Tier o null Livello VIP attuale
customer.customerTier.currentTierPoints number Punti che contano per i livelli
customer.balanceNotifications, tierNotifications, locationNotifications, rewardAvailableNotifications, marketingNotifications boolean Preferenze di notifica
engagementFlows object Avanzamento per ogni modo per guadagnare, con chiave il tipo di earning (ad esempio CUSTOM_1). count indica quante volte il cliente lo ha completato
TierProgressStatus

Restituito da customer.getTierProgress(). È lo stesso calcolo che usa la Loyalty Hub.

Campo Tipo Descrizione
currentTier Tier o null Livello attuale
nextTier Tier o null Livello successivo, oppure null al livello più alto
pointsToNextTier number Punti livello mancanti per raggiungere nextTier
progressValue number Avanzamento su tutti i livelli, da 0 (primo livello) a 100 (livello più alto). Usalo come percentuale per una barra di avanzamento
sortedTiers Tier[] Tutti i livelli, dal più basso al più alto
Tier
Campo Tipo Descrizione
id string Id del livello
name string Nome del livello
requiredPoints number Punti livello necessari per raggiungerlo
content string Testo dei vantaggi impostato in JeriCommerce (HTML). Sanificalo prima di inserirlo con innerHTML
image string o null Immagine del livello
Reward e PublicRewardDto

rewards.list({ scope: "customer" }) restituisce Reward, e rewards.list({ scope: "public" }) restituisce PublicRewardDto.

Campo Tipo Descrizione
id string Usalo come rewardId per riscattare
title, description, image string Contenuto del premio
type "fixed" o "dynamic" Fixed reward o Points as cash
cost (customer) / redeemCost (public) number Punti che costa un premio fisso
minPoints, maxPoints, currencyPerPoint number o null Limiti e valore di un premio Points as cash
redeemable (customer) boolean Il cliente può riscattarlo ora
nonRedeemableReason (customer) string Perché non può, ad esempio NOT_ENOUGH_BALANCE
ClaimedReward

Restituito da rewards.claim().

Campo Tipo Descrizione
code string Codice sconto da mostrare al cliente
pointsRedeemed number, opzionale Punti spesi
discountValue number, opzionale Valore dello sconto
expiresAt string o null Data di scadenza
PaginatedCustomerCouponCodes

Restituito da discounts.list(). data è l'elenco dei codici; count, total, page e pageCount descrivono la pagina. Ogni codice ha value (il codice), expiresAt, discountValue, claimed e coupon (il coupon a cui appartiene).

Modi per guadagnare

earnings.list() restituisce una voce per ogni tipo di earning. Ogni voce ha name (ad esempio FOLLOW_US, MEMBER_GET_MEMBER, CUSTOM_1), active e programEngagementFlows, la configurazione del programma per quel tipo. Usa il primo elemento:

Campo di programEngagementFlows[0] Descrizione
id Usalo come earningId in earnings.execute()
active Mostra solo gli earning attivi
title, description, buttonText, url Contenuto impostato in JeriCommerce
displayIconUrl Icona
properties.points Punti assegnati
properties.executeOnClick true quando il cliente guadagna premendo un pulsante: chiama earnings.execute({ earningId, action: "flow" }). Non vale mai per FOLLOW_US, MEMBER_GET_MEMBER o COMPLETE_USER_PROFILE, che vengono rifiutati con invalid_argument
properties.followUs Social network di un earning Follow us, con chiave il network (instagram, facebook, ...). Ognuno ha username e points
properties.requiredFields Campi del profilo richiesti da un earning Complete profile

Un clic richiede la chiave del network come linkId, ad esempio earnings.execute({ earningId, action: "click", linkId: "instagram" }). L'SDK registra il link impostato in JeriCommerce; non apre mai una finestra, quindi apri tu la pagina social.

earnings.execute() con action: "flow" si risolve con pointsAwarded, remainingExecutions e recurrence.

PaginatedTransactions

Restituito da history.list(). Ogni elemento di data ha name, amount, balanceChange, status e createdAt.

Boost

boosts.list() si risolve con { boosts }. Ogni boost ha name, startsAt, endsAt e isActive. L'SDK aggiorna l'elenco quando un boost inizia o termina.

Aggiornare le preferenze

customer.updatePreferences() richiede tutti i flag di notifica, più language se vuoi cambiarla:

const data = await jeri.customer.get();
await jeri.customer.updatePreferences({
  balanceNotifications: data.customer.balanceNotifications,
  tierNotifications: data.customer.tierNotifications,
  locationNotifications: data.customer.locationNotifications,
  rewardAvailableNotifications: data.customer.rewardAvailableNotifications,
  marketingNotifications: true,
});

Le richieste usano sempre la lingua della pagina. Salvare una preferenza di lingua aggiorna i dati del cliente ma non cambia la lingua della pagina.

Eventi

jeri.on(event, callback) restituisce una funzione che rimuove l'iscrizione. Gli eventi vengono emessi anche la prima volta che la pagina legge quei dati, e on() non reinvia l'ultimo valore. Renderizza quello che restituisce ogni lettura, come nell'avvio rapido, e usa gli eventi per le modifiche successive.

Evento Quando viene emesso Cosa riceve il callback
session:changed La sessione viene conosciuta per la prima volta, e ogni volta che cambia { authenticated }
customer:updated I dati del cliente sono cambiati, ad esempio il saldo dopo un riscatto CustomerData, oppure null per un visitatore
rewards:updated Un elenco di premi letto dalla tua pagina è stato aggiornato { scope, rewards }, con lo stesso elenco di rewards.list({ scope })
discounts:updated Un elenco di codici sconto letto dalla tua pagina è stato aggiornato { query, discounts }, con il { page, limit } letto e un PaginatedCustomerCouponCodes
earnings:updated I modi per guadagnare sono stati aggiornati Lo stesso elenco di earnings.list()
boosts:updated Un boost è iniziato o terminato, oppure i boost sono stati aggiornati { scope, boosts }, con lo stesso valore di boosts.list({ scope })

Gli eventi segnalano solo le modifiche ai dati. Il risultato di un'azione è il valore con cui si risolve la sua promise.

Errori

Ogni chiamata fallita viene rifiutata con uno StorefrontSdkError. Controlla il suo code, non il testo del messaggio:

Codice Significato
invalid_argument La chiamata ha un valore mancante o errato, ad esempio un rewardId vuoto
authentication_required La chiamata richiede un cliente connesso, oppure la sessione del cliente è scaduta
session_unavailable Non è stato possibile caricare la sessione del cliente. Riprova più tardi; non viene mai trattato come un visitatore
api_error JeriCommerce ha rifiutato la richiesta. status contiene lo stato HTTP e serverCode il codice dell'API, come NOT_ENOUGH_POINTS
network_error Una lettura non è arrivata a JeriCommerce. Un'azione che non arriva viene rifiutata con mutation_unconfirmed
widget_unavailable Il widget è disattivato, oppure non è stato possibile caricare le sue impostazioni o il suo codice, quindi non può aprirsi
mutation_unconfirmed L'azione potrebbe non essere stata applicata, per esempio perché non è arrivata a JeriCommerce. Rileggi i dati prima di riprovare

Il widget e l'SDK

L'SDK può controllare il widget storefront nella pagina corrente: jeri.widget.open(), close(), showLauncher() e hideLauncher(). Queste chiamate influiscono solo sulla visualizzazione della pagina; le impostazioni salvate del widget non cambiano. Quando il widget è disattivato in JeriCommerce, widget.open() viene rifiutato con widget_unavailable e tutto il resto continua a funzionare.

Pagine del widget

widget.open({ page }) accetta queste pagine:

page Apre
advantages Vantaggi del programma
profile Profilo
orders Ordini
coupons Codici sconto
rewards Premi
loyalty Modi per guadagnare
referrals Referral

I visitatori vedono sempre la pagina dei vantaggi del programma e dell'iscrizione.

Limitazioni

  • L'SDK è disponibile solo negli storefront Shopify tramite l'app embed. Non esiste un pacchetto npm.
  • L'editor di temi Canvas di Shopify non supporta ancora gli app embed, quindi l'SDK non è disponibile nei temi Canvas.
  • L'SDK non crea account e non iscrive i clienti. I visitatori accedono tramite Shopify.
  • I punti non vengono mai calcolati nel browser. Se l'API restituisce ancora il saldo precedente, quello è il dato più recente fino alla lettura successiva.

Esempi

Riscattare un premio e mostrare il codice
try {
  const claimed = await jeri.rewards.claim({ rewardId: reward.id });
  showCode(claimed.code); // The balance updates through "customer:updated".
} catch (error) {
  if (error.code === "api_error" && error.serverCode === "NOT_ENOUGH_POINTS") {
    showMessage("You need more points for this reward.");
  } else {
    showMessage("Something went wrong. Please try again.");
  }
}
Riscattare un premio Points as cash
await jeri.rewards.claim({ rewardId: reward.id, pointsToRedeem: 200 });
Guadagnare punti con un pulsante
const result = await jeri.earnings.execute({ earningId: earning.id, action: "flow" });
showMessage(`+${result.pointsAwarded} points`);
Aprire il widget nella pagina dei premi
document.querySelector("[data-open-rewards]").addEventListener("click", () => {
  jeri.widget.open({ page: "rewards" }).catch(() => {
    window.location.href = "/pages/loyalty"; // The widget is turned off.
  });
});
Tenere aggiornato il saldo nell'header
const badge = document.querySelector("[data-points-badge]");
const show = data => {
  badge.hidden = !data;
  if (data) badge.textContent = data.customer.loyaltyData.balance;
};
show(await jeri.customer.get());
jeri.on("customer:updated", show);

Una pagina completa costruita con questi metodi è nella guida alla pagina fedeltà personalizzata.