Skip to main content

Shopify App Integration

What is this? A production-ready Shopify app that rewards your customers with LTZ tokens for purchases and actions in your store.

Use this if you're: Running an online store on Shopify and want to reward customer loyalty.

You'll need:


We've built a production-ready template that handles:

  • ✅ Secure Webhook Verification (HMAC-SHA256)
  • ✅ Automatic Rewards for Purchases & Signups
  • ✅ Cloudflare Workers or Node.js/Express Support
  • ✅ Simple Configuration

📦 View the Repository

Clone the repository and follow the SETUP.md guide to get running in minutes.

git clone https://github.com/Alpha4-Labs/shopify-loyalty-app.git
cd shopify-loyalty-app
npm install
npm run dev

How It Works

Plain English Explanation:

  1. Customer does something (makes a purchase, creates account, etc.)
  2. Shopify tells your app "Hey, something happened!" (via webhooks)
  3. Your app tells Loyalteez "Give this customer a reward!"
  4. Customer gets LTZ tokens automatically

Step-by-Step Setup

Step 1: Deploy the App

You can run this on any server (Railway, Heroku, DigitalOcean) or as a Cloudflare Worker (Free & Fast).

Option A: Cloudflare Workers (Recommended)

  1. Clone the repo: git clone https://github.com/Alpha4-Labs/shopify-loyalty-app.git
  2. Install dependencies: npm install
  3. Set your secrets:
    npx wrangler secret put SHOPIFY_WEBHOOK_SECRET
    npx wrangler secret put LOYALTEEZ_BRAND_ID
  4. Deploy: npm run deploy

Option B: Node.js Server

  1. Set environment variables in .env:
    SHOPIFY_WEBHOOK_SECRET=your_secret
    LOYALTEEZ_BRAND_ID=0x...
  2. Run the server: npm start

Step 2: Configure Shopify Webhooks

  1. Go to your Shopify admin (yourstore.myshopify.com/admin)
  2. Navigate to: Settings → Notifications → Webhooks
  3. Create webhook for "Order creation":
    • Event: Order creation
    • Format: JSON
    • URL: https://your-app-url.com/webhooks/shopify
    • Click "Save"
  4. Create webhook for "Customer creation":
    • Event: Customer creation
    • Format: JSON
    • URL: https://your-app-url.com/webhooks/shopify
    • Click "Save"
  5. Copy the webhook secret and add it to your app configuration.

Shopify Webhooks Documentation Shopify Help Center guide for creating webhooks

Step 3: Test Your Integration

We've included a Simulation UI in the app.

  1. Visit your deployed app URL (e.g., https://shopify-demo.loyalteez.app).
  2. Use the Simulate Purchase form to trigger a fake order.
  3. Check your Loyalteez dashboard to see the reward appear!

Code Example

Here is the core logic used in the app to process orders:

/**
* Handle order creation webhook
*/
async function handleOrderCreated(order, brandId, apiUrl) {
const email = order.customer?.email;
const orderTotal = parseFloat(order.total_price || 0);

if (!email) return;

// Calculate Reward: 10 LTZ per $1 spent
const ltzAmount = Math.floor(orderTotal * 10);

// Bonus for large orders ($100+)
const bonus = orderTotal >= 100 ? 1000 : 0;

// Send to Loyalteez
await fetch(`${apiUrl}/loyalteez-api/manual-event`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
brandId,
eventType: 'place_order', // Matches your automation rule
userEmail: email,
metadata: {
order_id: order.id,
order_total: orderTotal,
ltz_earned: ltzAmount + bonus
}
})
});

console.log(`✅ Rewarded ${email}: ${ltzAmount + bonus} LTZ`);
}

Reward Strategies

Strategy 1: Purchase Rewards (10 LTZ per $1)

Why: Rewards every purchase, encourages repeat business. How: Default behavior in the template.

Strategy 2: Tiered Bonuses

Why: Encourages larger orders (AOV). How:

const bonus = orderTotal >= 100 ? 1000 : 0; // 1000 LTZ bonus for orders > $100

Strategy 3: First Purchase Bonus

Why: Rewards new customers, encourages conversion. How:

if (order.order_number === 1) {
// Send extra 'first_purchase' event
}

Interactive Widget

The Loyalteez Interactive Widget provides customers with a full loyalty experience directly in your storefront.

Features

  • Balance Display: View current LTZ balance
  • Streak Tracking: Daily check-in with streak multipliers
  • Perks Browsing: Browse and redeem perks
  • Daily Check-in: Customers can check in daily to maintain streaks

Installation

  1. Create Theme App Extension:

    shopify app generate extension
    # Select: Theme app extension
  2. Add Widget Component:

    • Copy src/widget/LoyalteezWidget.tsx to your extension
    • Add to theme template where desired
  3. Configure:

    {% render 'loyalteez-widget', 
    brand_id: '0x...',
    customer_email: customer.email
    %}

Option 2: Embed Script

Add to your theme's theme.liquid or specific pages:

<div id="loyalteez-widget" 
data-brand-id="0xYourBrandAddress"
data-customer-email="{{ customer.email }}">
</div>
<script src="https://widgets.loyalteez.app/shopify/embed.js"></script>

Widget Tabs

Balance Tab:

  • Shows current LTZ balance
  • Displays earning opportunities

Streak Tab:

  • Current streak count
  • Multiplier display
  • Daily check-in button
  • Next milestone progress

Perks Tab:

  • Available perks list
  • Cost and availability
  • Quick redemption buttons

Daily Check-in

Customers can check in daily to maintain streaks:

  1. Customer visits store (or widget page)
  2. Clicks "Check In Today" in Streak tab
  3. Streak recorded via shared services API
  4. Multiplier applied to next purchase reward

Implementation:

const handleDailyVisit = async () => {
const result = await fetch('/api/streak/record-activity', {
method: 'POST',
body: JSON.stringify({
brandId,
userEmail: customerEmail,
platform: 'shopify'
})
}).then(r => r.json());

// Update streak display
setStreak(result);
};

Streak System

Streaks apply multipliers to purchase rewards:

  • 3+ days: 1.25x multiplier
  • 7+ days: 1.5x multiplier
  • 14+ days: 1.75x multiplier
  • 30+ days: 2.0x multiplier

Enhanced Webhook Handler:

async function handleOrderCreated(order, brandId, env) {
const email = order.customer?.email;
if (!email) return;

// Get user's streak for multiplier
const streakData = await fetch(
`${env.SHARED_SERVICES_URL}/streak/status/${brandId}/${encodeURIComponent(email)}`
).then(r => r.json());

const baseReward = Math.floor(parseFloat(order.total_price) * 10);
const multipliedReward = Math.floor(baseReward * streakData.multiplier);

await fetch(`${env.LOYALTEEZ_API_URL}/loyalteez-api/manual-event`, {
method: 'POST',
body: JSON.stringify({
brandId,
eventType: 'place_order',
userEmail: email,
metadata: {
platform: 'shopify',
order_id: order.id,
order_total: order.total_price,
base_reward: baseReward,
streak_multiplier: streakData.multiplier,
total_reward: multipliedReward
}
})
});
}

Perk Redemption

Customers can redeem perks directly from the widget:

  1. Browse perks in Perks tab
  2. Click "Redeem" on desired perk
  3. LTZ deducted from balance
  4. Discount code generated (for discount perks)
  5. Code displayed to customer

Redemption Flow:

const handleRedeem = async (perkId: string) => {
if (balance < perk.cost) {
alert('Insufficient balance');
return;
}

const response = await fetch(`${SHARED_SERVICES_URL}/perks/redeem`, {
method: 'POST',
body: JSON.stringify({
brandId,
userEmail: customerEmail,
platform: 'shopify',
perkId
})
});

const result = await response.json();
if (result.success) {
// Show discount code or confirmation
showConfirmation(result.confirmationCode);
// Refresh balance
loadData();
}
};

Widget Customization

Customize widget appearance via CSS:

.loyalteez-widget {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 20px;
background: white;
}

.widget-header h3 {
color: #8CBC99;
margin: 0 0 15px 0;
}

.widget-tabs button.active {
background: #8CBC99;
color: white;
}

Shared Services Integration

The widget uses Loyalteez Shared Services:

  • Streak Service: /streak/record-activity, /streak/status
  • Perks Service: /perks/:brandId, /perks/redeem
  • Balance Service: Calls Loyalteez API for balance

See Shared Services Overview for details.

Show Rewards to Customers

Add Banner to Thank You Page

After checkout, show customers how much LTZ they earned.

  1. Go to: Shopify Admin → Settings → Checkout
  2. Scroll to: Additional Scripts
  3. Add this code:
<script>
// Get order info
const orderTotal = {{ checkout.total_price | money_without_currency }};
const ltzEarned = Math.floor(orderTotal * 10);

document.addEventListener('DOMContentLoaded', function() {
const banner = document.createElement('div');
banner.style.cssText = 'background: #8CBC99; color: white; padding: 20px; margin: 20px 0; border-radius: 8px; text-align: center;';
banner.innerHTML = `
<h2 style="margin: 0 0 10px 0;">🎉 You Earned ${ltzEarned} LTZ!</h2>
<p style="margin: 0;">Your rewards have been added to your wallet.</p>
<a href="https://marketplace.loyalteez.app" style="color: white; text-decoration: underline;">View Your Wallet →</a>
`;

const container = document.querySelector('.main-content') || document.body;
container.prepend(banner);
});
</script>

Troubleshooting

"Webhooks aren't being received"

Check:

  1. Is your server running and accessible?
  2. Did you configure webhooks in Shopify admin?
  3. Is the URL correct in Shopify settings?

"Events track but no LTZ given"

Check:

  1. Is your Brand ID correct?
  2. Are reward rules configured in Partner Portal?
  3. Check Partner Portal analytics for the event.

"Getting 401 Unauthorized errors"

Check:

  • Ensure your SHOPIFY_WEBHOOK_SECRET matches the one in your Shopify Admin.

Support