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 ¶
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.
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.
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()ecustomer.getTierProgress()restituiscononull. I metodi indicati come Customer nella reference vengono rifiutati con il codice di erroreauthentication_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:
- La promise si risolve subito con il risultato di quell'azione, ad esempio il codice sconto di un premio riscattato. Mostralo immediatamente.
- L'SDK segna come non aggiornati i dati coinvolti, così la lettura successiva non restituisce mai i dati precedenti all'azione.
- In background rilegge i dati che la tua pagina aveva già caricato e invia gli eventi corrispondenti, come
customer:updatedcon 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.