Shopify Setup
Integrate Refuel with your Shopify store to run a full affiliate program. This guide covers widget installation, automatic conversion tracking via Shopify webhooks, and troubleshooting common issues.
Prerequisites
- A Refuel account with your company registered (see Getting Started)
- Your publishable key (
pk_...) and secret API key (sk_...) - A Shopify store on any plan (Basic, Shopify, Advanced, or Plus)
- Access to your Shopify admin panel
1Install the Affiliate Widget
Add the Refuel widget script to your Shopify theme so the affiliate signup button appears on every page of your store.
Option A: Theme Editor (Recommended)
- In your Shopify admin, go to Online Store → Themes
- Click Actions → Edit code on your active theme
- Open
theme.liquidfrom the Layout folder - Find the closing
</body>tag - Paste the following snippet directly above it:
{% comment %} Refuel Affiliate Widget {% endcomment %}
<script
src="https://sdk.refuel.dev/v1.js"
data-key="pk_your_publishable_key"
data-position="bottom-right"
async
></script>Option B: Shopify App Embed
If you prefer not to edit theme code, you can use the Refuel Shopify app (if available) which adds the widget as an app embed block via the theme customizer. Go to Online Store → Themes → Customize → App embeds and toggle on Refuel.
2Set Up Conversion Tracking
Conversion tracking requires a server-side integration so that Refuel is notified when an order is placed. The most reliable approach is using Shopify webhooks.
Create a Shopify Webhook
- Go to Settings → Notifications → Webhooks in your Shopify admin
- Click Create webhook
- Set the event to
Order payment - Set the format to JSON
- Set the URL to your webhook handler (see below)
- Click Save
Webhook Handler
You need a small server-side handler that receives the Shopify order webhook and forwards the conversion to Refuel. Here is an example using Express.js:
import express from "express";
import crypto from "crypto";
const app = express();
const SHOPIFY_SECRET = process.env.SHOPIFY_WEBHOOK_SECRET!;
const REFUEL_API_KEY = process.env.REFUEL_API_KEY!; // your sk_... key
app.post(
"/webhooks/shopify/orders",
express.raw({ type: "application/json" }),
async (req, res) => {
// Verify Shopify signature
const hmac = req.headers["x-shopify-hmac-sha256"] as string;
const hash = crypto
.createHmac("sha256", SHOPIFY_SECRET)
.update(req.body)
.digest("base64");
if (hmac !== hash) {
return res.status(401).send("Invalid signature");
}
const order = JSON.parse(req.body.toString());
// Extract the affiliate code from the order's landing page URL
// Shopify stores the landing_site in the order object
const landingSite = order.landing_site || "";
const refMatch = landingSite.match(/[?&]ref=([^&]+)/);
if (!refMatch) {
// No affiliate attribution -- skip
return res.json({ ok: true, attributed: false });
}
const affiliateCode = refMatch[1];
// Send conversion to Refuel
const response = await fetch("https://api.refuel.dev/track/conversion", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": REFUEL_API_KEY,
},
body: JSON.stringify({
orderId: String(order.id),
orderValue: Math.round(parseFloat(order.total_price) * 100), // convert to cents
currency: order.currency,
affiliateCode,
metadata: {
shopifyOrderNumber: order.order_number,
customerEmail: order.email,
},
}),
});
const result = await response.json();
console.log("Refuel conversion:", result);
res.json({ ok: true, attributed: true, conversionId: result.data?.conversionId });
}
);
app.listen(3000);3How Order Attribution Works
Understanding the attribution flow helps you debug issues and optimize your program.
Affiliate shares link
The affiliate shares a link like https://yourstore.com?ref=abc123
Visitor clicks the link
The Refuel SDK detects the ?ref= parameter and records a click event with the visitor's fingerprint, IP hash, and landing page.
Visitor browses and purchases
Shopify stores the landing_site URL (including the ?ref= parameter) on the order object.
Order webhook fires
Shopify sends the order/payment webhook to your handler. Your handler extracts the ref code and sends it to Refuel.
Refuel attributes the conversion
Refuel looks up the affiliate link, finds the most recent click within the attribution window (default 30 days), calculates the commission split, and runs fraud detection.
Commission is credited
If the conversion passes fraud checks (or is manually approved), the affiliate's pending balance is credited. Payouts happen on the configured schedule via Stripe Connect.
Attribution window: By default, a conversion is attributed to an affiliate if the click happened within the last 30 days. You can configure this (1-90 days) in your company settings.
4Configure Your Program
Fine-tune your affiliate program settings from the Refuel dashboard or via the API.
| Setting | Default | Description |
|---|---|---|
| commissionRate | 0.10 (10%) | Percentage of order value paid as commission |
| attributionWindow | 30 days | How long after a click a conversion can be attributed |
| payoutSchedule | monthly | How often payouts are sent (weekly, biweekly, monthly) |
| payoutMinimum | $50.00 | Minimum balance required before a payout is triggered |
Troubleshooting
Widget does not appear on my store
- Verify the script tag is inside
theme.liquid, before</body> - Check that the
data-keymatches your publishable key exactly - Open your browser console and look for any Refuel-related errors
- Ensure your company status is "active" (not paused)
- Try a hard refresh (Ctrl+Shift+R) to clear cached theme files
Conversions are not being tracked
- Check that your webhook handler is receiving Shopify order events (check server logs)
- Verify the Shopify webhook URL is correct and publicly accessible
- Ensure the
x-api-keyin your handler matches your secret key - Check that the order's
landing_sitecontains the?ref=parameter - Test with a manual curl request to
POST /track/conversion
Affiliate code is missing from the order
- Shopify only stores
landing_sitefor the first page the customer visits. If they navigate away and come back without the?ref=parameter, it will be lost. - Consider using the Refuel SDK's cookie-based tracking as a fallback. The SDK stores the ref code in a first-party cookie that persists across page views.
- For Shopify Plus stores, you can add the ref code to the checkout as a cart attribute for more reliable attribution.
Duplicate conversion errors
- The Refuel API rejects duplicate conversions by order ID. If you see
DUPLICATEerrors, the conversion was already recorded. - Shopify may send the order/payment webhook multiple times. Your handler should gracefully handle 409 responses.
Conversion stuck in "pending" status
- Conversions with fraud flags require manual review in your Refuel dashboard
- Go to Dashboard → Conversions and filter by "pending" to review flagged conversions
- You can approve or reject each one, or adjust your fraud sensitivity in settings
Alternative: Thank-You Page Script
If you cannot set up a webhook handler, you can track conversions client-side by adding a script to the Shopify order confirmation (thank-you) page. This approach is less reliable than server-side webhooks but requires no backend.
- Go to Settings → Checkout → Order status page → Additional scripts
- Paste the following script:
{% if first_time_accessed %}
<script>
// Read the affiliate code from the Refuel cookie
const refCode = document.cookie
.split("; ")
.find(c => c.startsWith("_refuel_ref="))
?.split("=")[1];
if (refCode) {
fetch("https://api.refuel.dev/track/conversion", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": "sk_your_secret_key" // Note: exposed client-side
},
body: JSON.stringify({
orderId: "{{ order.id }}",
orderValue: {{ order.total_price | times: 100 | round }},
currency: "{{ order.currency }}",
affiliateCode: refCode
})
});
}
</script>
{% endif %}Warning: The thank-you page approach exposes your secret API key in client-side JavaScript. For production use, we strongly recommend the server-side webhook approach described above, or proxy the conversion call through a serverless function.