How it works

Follow these 4 simple steps to track Shopify refunds in Mixpanel automatically

Shopify logo icon

Refund Created

App connector: Shopify • Time to complete: 0 minutes (Auto-configured)
Why this matters: This trigger captures refunds the instant they're issued, providing immediate visibility into return activity and enabling real-time dashboards that track refund volume, amounts, and patterns as they happen.

This step automatically activates whenever a refund is processed in your Shopify store, whether it's a full or partial refund. No configuration is needed - MESA connects directly to your Shopify store's refund events and captures essential details like refund amount, timestamp, and order information. The trigger passes this refund data to the next step for order retrieval and enrichment.

Retrieve Order

App connector: Shopify • Time to complete: 0 minutes (Auto-configured)
Why this matters: Fetches the complete order record to provide context for the refund, including customer details, order name, and full line item information that's necessary for matching refunded items to their SKUs and product data.

This step automatically pulls the full order record associated with the refund using the order ID from the trigger. No configuration is required - the system retrieves comprehensive order data including customer details, billing information, and all line items from the original purchase. This enriched data gets passed to the custom code step for processing and formatting.

Custom Code

App connector: Code • Time to complete: 0 minutes (Auto-configured)
Why this matters: Transforms raw refund and order data into analytics-ready metrics by calculating total refund amount, formatting product lists, matching SKUs, and summing quantities—work that would be difficult to accomplish with standard workflow steps.

This step runs custom JavaScript code that calculates total refund amounts, formats line item titles into readable lists, sums refunded quantities, and extracts SKUs for the refunded products. The code processes transaction amounts to determine the actual refund value and creates comma-separated lists of product information for easy analysis. All calculated values are formatted specifically for Mixpanel's event structure and passed to the final tracking step.

const Mesa = require('vendor/Mesa.js');

/**
 * A MESA Script exports a class with a script() method.
 */
module.exports = new (class {
  /**
   * MESA Script
   *
   * @param {object} prevResponse The response from the previous step
   * @param {object} context Additional context about this task
   */
  script = (prevResponse, context) => {
    // Retrieve the Variables Available to this step
    // Line items from a Shopify Order Created trigger would be available as something like `vars.shopify.line_items`
    const vars = context.steps;

    // For storing response
    let response = {};
    // Get refund payload and Shopify order
    const refundPayload = vars.shopify;
    const shopifyOrder = vars.shopify_1;

    // Loop through transactions on the refund, and total up the refund amount
    let refundAmount = 0;
    refundPayload.transactions.forEach(transaction => {
      refundAmount -= transaction.amount;
    });

    // Format refunded line items' titles to comma-separated list (i.e. Title 1, Title 2, ...)
    const refundedLineItemsTitles = refundPayload.refund_line_items.map(item => item.line_item.title).join(', ');
    // Sum total quantity of refunded line items' quantities
    const refundedLineItemsTotalQuantity = refundPayload.refund_line_items.reduce((sum, item) => sum + item.quantity, 0);

    // Extract line item ids (line_items.id) from shopifyOrder.line_items
    const lineItemsById = {};
    shopifyOrder.line_items.forEach(item => {
      lineItemsById[item.id] = item;
    });

    // Find SKUs for matching refunded line items (refund_line_items)
    // Format SKUs into comma-separated list (i.e. SKU1, SKU2, ...)
    const refundedLineItemsSkus = refundPayload.refund_line_items
      .map(refundItem => {
        const match = lineItemsById[refundItem.line_item_id];
        return match ? match.sku : null;
      })
      .filter(Boolean)
      .join(",");
     
    // Add to response
    response.total_refund_amount = refundAmount;
    response.refunded_line_items_titles = refundedLineItemsTitles;
    response.refunded_line_items_total_quantity = refundedLineItemsTotalQuantity;
    response.refunded_line_items_skus = refundedLineItemsSkus;

    // Call the next step in this workflow
    // response will be the Variables Available from this step
    Mesa.output.next(response);
  };
})();
Mixpanel logo icon

Create an Event

App connector: Mixpanel • Time to complete: 2 minutes
Why this matters: Creates a rich refund event in Mixpanel with comprehensive properties that enable analysis of refund patterns by product, customer, amount, reason, and timing—insights critical for reducing returns and improving customer satisfaction.

You'll need to configure your Mixpanel project ID in the "project_id" field to connect this workflow to your Mixpanel account. The step automatically formats all refund data into Mixpanel's event structure, including order details, refund amounts, customer information, and product-specific data like SKUs and quantities. Each refund creates a distinct event in Mixpanel with the order name in the event title for easy identification.

Make it your own

Customize this workflow even further:

Add product-level refund details
Modify the custom code to create separate events for each refunded line item instead of one aggregated event, enabling product-specific refund rate analysis and identifying which products drive the most returns.
Include refund method information
Add properties to the Mixpanel event that capture the refund gateway, payment method, or whether it was a store credit versus original payment method refund, helping analyze refund processing patterns.
Send alerts for high-value refunds
Add a filter step before Mixpanel that checks {{custom.total_refund_amount}} and sends Slack notifications when refunds exceed a certain threshold, enabling immediate investigation of significant returns.
Track time-to-refund metrics
Modify the custom code to calculate the days between order creation ({{shopify_1.created_at}}) and refund creation ({{shopify.created_at}}), adding this as a property to analyze how quickly refunds are processed.

Frequently asked questions

What if a refund doesn't have a reason specified?
The Refund Reason property ({{shopify.order_adjustments[0].reason}}) will be empty if no reason was entered when processing the refund. The event will still be created with all other properties populated. Consider adding a filter or default value in the custom code if you want to ensure every event has a reason.
Can I track partial refunds versus full refunds differently?
Yes, add a comparison in the custom code that checks if {{custom.total_refund_amount}} equals the order's {{shopify_1.total_price}} to determine full versus partial refunds, then add this as a property or create different event names for each type.
How are refund amounts calculated when there are multiple transactions?
The custom code loops through all transactions in {{shopify.transactions}} and sums the amounts. The code negates the amounts because Shopify stores refund transaction amounts as positive numbers, but they represent money leaving your account, so the code converts them to negative values for accurate refund total calculation.
What is a template?
Templates are pre-made workflows by our team of experts. Instead of building a workflow from scratch, these have all the steps needed to complete the task.
Can I personalize a template?
Yes! Every step can be customized to meet your exact requirements. Additionally, you can even add more steps and make it more sophisticated.
Are templates free?
Yes! Our entire library containing hundreds of templates are free to use and customize to your exact needs.

Ready to track Shopify refunds in Mixpanel automatically?

Join thousands who've automated their work and saved an average of 3.5 hours every week.

Start with this template — It's free
7-day free trial • 5 min setup • Cancel anytime