How it works

Follow these 10 simple steps to start syncing Shopify orders to Salesforce opportunities

Shopify logo icon

Order Created

App connector: Shopify • Time to complete: 0 minutes (Auto-configured)
Why this matters: This trigger monitors your Shopify store for completed orders and kicks off the Salesforce sync workflow. Without this automation, your sales team would need to manually create opportunities in Salesforce for every ecommerce order, leading to incomplete pipeline data and reporting gaps.

When any order is created in Shopify—whether from your online store, draft orders converted to paid, or any other order source—this trigger captures the complete order details including customer ID, line items, pricing, discounts, and order notes. The trigger watches your store continuously and passes the order data to the next step immediately after the order is placed.

Query Single Account

App connector: Salesforce • Time to complete: 0 minutes (Auto-configured)
Why this matters: To create a Salesforce opportunity, you need to link it to the customer's Account record in Salesforce. This step searches Salesforce for the Account that matches the Shopify customer who placed the order, ensuring the opportunity gets associated with the correct company or person.

The step queries Salesforce's Account object searching for a record where the custom field "Shopify_Customer_ID__c" matches the customer ID from the Shopify order. This custom field gets populated by the dependency workflow that syncs Shopify customers to Salesforce Accounts. The query returns the Account ID and Name, which get used in the opportunity creation step to properly link the records. If no matching Account is found, this workflow will fail—which is why the customer sync dependency workflow must be running first.

Custom: Get Order Variant IDs

App connector: Code • Time to complete: 0 minutes (Auto-configured)
Why this matters: Salesforce needs to match each product in the order to its corresponding Product record in Salesforce. This custom code extracts all the variant IDs from the order line items and formats them for a Salesforce query, enabling bulk product lookup in the next step rather than querying one at a time.

The code iterates through all line items in the Shopify order, extracts each product variant ID, and creates a comma-separated list formatted for Salesforce's SQL-style query syntax. For example, if an order contains three products, this step outputs something like '123456789','987654321','456789123' which the next step uses in a WHERE clause to find all matching products in one query. Here's the code:

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

module.exports = new class {
  script = (payload, context) => {
    const lineItems = context.steps['shopify-order-created'].line_items;

    let variantIds = lineItems.map(lineItem => {
      return `'${lineItem.variant_id}'`;
    });

    payload.variant_ids = variantIds;
    payload.variant_ids_csv = variantIds.join();

    Mesa.output.next(payload);
  }
}

Query Multiple Product

App connector: Salesforce • Time to complete: 0 minutes (Auto-configured)
Why this matters: Before creating opportunity products, you need the Salesforce Product IDs that correspond to each item in the Shopify order. This step searches Salesforce for all products that match the variant IDs from the order, enabling proper linking of line items to the Salesforce product catalog.

The step queries Salesforce's Product2 object searching for records where the custom field "Shopify_Variant_Id__c" matches any of the variant IDs from Step 3. This custom field gets populated by the product sync dependency workflow. The query returns multiple Product records in one API call—one for each unique product in the order—including their Salesforce IDs and Shopify variant IDs. These IDs get used later to create OpportunityLineItem records that link products to the opportunity.

Mapping to Salesforce Create Opportunity

App connector: Transform • Time to complete: 5 minutes
Why this matters: Shopify order data has different field names and formats than Salesforce Opportunity fields. This transformation step maps Shopify order values to the correct Salesforce Opportunity fields, ensuring data lands in the right places when the opportunity is created.

The transform maps several key fields:

  • AccountId: Uses the Salesforce Account ID from Step 2 to link the opportunity
  • Amount: Uses the Shopify order total price
  • CloseDate: Uses the order creation date
  • Description: Uses the Shopify order notes
  • StageName: Hard-coded to "Closed Won" since the order already completed
  • Pricebook2Id: You must manually enter your Salesforce Price Book ID here (see configuration instructions below)
  • Name: Combines the Account name and Shopify order name (like "Acme Corp - #1234")

Critical Configuration: You must enter your Salesforce Price Book ID in the "Pricebook2Id" field. To find this: log into Salesforce, go to Price Books, click your desired price book, and copy the ID from the URL between r/ and /view. For example, in https://ab11.force.com/lightning/r/01s2E000002pddCQAQ/view, the ID is 01s2E000002pddCQAQ.

Create Opportunity

App connector: Salesforce • Time to complete: 0 minutes (Auto-configured)
Why this matters: This is where the Shopify order actually becomes a Salesforce opportunity. The step creates a new Opportunity record with all the mapped data from the previous step, making the ecommerce sale visible in your Salesforce sales pipeline and reporting.

The step sends a POST request to Salesforce's Opportunity API endpoint with the transformed data from Step 5. Salesforce creates a new Opportunity record linked to the customer's Account, sets the stage to "Closed Won," records the order total as the opportunity amount, and uses the order date as the close date. The newly created Opportunity ID gets returned and is used in subsequent steps to create the associated product line items.

Custom: Append Salesforce Product ID to line items

App connector: Code • Time to complete: 1 minute
Why this matters: To create opportunity products in the loop, each Shopify line item needs to know its corresponding Salesforce Product ID. This code matches each line item to the Salesforce products retrieved in Step 4 and appends the Salesforce Product ID to each line item for use in the loop.

The code takes the line items from the Shopify order and the Salesforce products from Step 4, then matches them by comparing Shopify variant IDs. For each line item, it finds the matching Salesforce product and adds a new field called "salesforce_product_id" to that line item. This enriched line item data gets passed to the loop so each iteration has both the Shopify product details and the Salesforce Product ID needed to create the OpportunityLineItem. Here's the code:

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

module.exports = new (class {
  script = (payload, context) => {
    const salesforceProducts =
      context.steps['salesforce-query-multiple-product'];

    let lineItems = context.steps['shopify-order-created'].line_items;

    lineItems.forEach((lineItem, key) => {
      let salesforceProduct = salesforceProducts.filter(
        product =>
        product.Shopify_Variant_ID__c == lineItem.variant_id
      );

      if (salesforceProduct && salesforceProduct.length > 0) {
        lineItems[key]['salesforce_product_id'] = salesforceProduct[0].Id;
      }
    });

    const newPayload = {};
    newPayload.line_items = lineItems;

    Mesa.output.next(newPayload);
  };
})();

Loop: Process Each Line Item

App connector: Loop • Time to complete: 0 minutes (Auto-configured)
Why this matters: Orders typically contain multiple products, and each product needs to become a separate OpportunityLineItem record in Salesforce. This loop processes one line item at a time, creating individual opportunity product records that show exactly what was purchased.

The loop iterates through all line items from Step 7 (which now include the Salesforce Product IDs), processing one product at a time through the remaining workflow steps. For example, if an order contains a t-shirt, a hat, and a mug, the loop runs three times—once for each item—creating three separate OpportunityLineItem records linked to the same Opportunity. This structure allows orders of any size to sync completely to Salesforce.

Mapping: Create Opportunity Product

App connector: Transform • Time to complete: 0 minutes (Auto-configured)
Why this matters: Each line item needs to be transformed into the format Salesforce expects for OpportunityLineItem records. This transformation maps Shopify line item data to Salesforce fields and includes custom logic to calculate discount percentages, ensuring accurate product-level data in your CRM.

The transform maps:

  • OpportunityId: Uses the Opportunity ID created in Step 6
  • UnitPrice: Uses the line item price from Shopify
  • Quantity: Uses the line item quantity
  • Product2Id: Uses the Salesforce Product ID appended in Step 7

Additionally, the custom transform code calculates discount percentages if any discounts were applied to the line item. It takes the discount amount, divides it by the total line item price (unit price × quantity), and converts it to a percentage. Here's the transform code:

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

module.exports = new class {
  script = (payload, context) => {
    const currentItem = context.steps.loop;

    const output = Transform.convert(context, payload);

    // Add discounts
    let totalDiscounts = parseFloat(currentItem.total_discount_set.shop_money.amount);

    if (currentItem.discount_allocations && currentItem.discount_allocations) {
      totalDiscounts = currentItem.discount_allocations.reduce((a, {amount}) => a + parseFloat(amount), 0);
    }

    if (totalDiscounts && totalDiscounts > 0) {
      // Get total price for line item (quantity * unit price, then divide by discount to get percentage)
      output['Discount'] = parseFloat(totalDiscounts / (output.UnitPrice * output.Quantity) * 100);
    }

    Mesa.output.next(output);
  }
}
salesforce logo icon

Create Opportunity Product

App connector: Salesforce • Time to complete: 0 minutes (Auto-configured)
Why this matters: This is where each line item actually becomes an OpportunityLineItem record in Salesforce. The step creates individual product records linked to the opportunity, giving your sales team complete visibility into what products were purchased, not just order totals.

The step sends a POST request to Salesforce's OpportunityLineItem API endpoint with the transformed data from Step 9. Salesforce creates a new OpportunityLineItem record for the current line item in the loop, linking it to the Opportunity created in Step 6 and the Product from your Salesforce catalog. This includes quantity, unit price, and any calculated discounts. The loop continues until all line items have been processed and added to the opportunity.

*Required: These following must be installed before using this workflow.

Make it your own

Customize this workflow even further:

Add order tags as opportunity fields
After creating the opportunity, add a step to update custom Salesforce fields with Shopify order tags, enabling sales reporting segmented by fulfillment status, marketing campaigns, or customer segments tracked through your tagging system.
Sync order status changes back to Salesforce
Create a companion workflow that triggers when Shopify order status changes (fulfilled, cancelled, refunded) and updates the Salesforce Opportunity stage accordingly, keeping your sales pipeline accurate even when orders change after initial sync.
Route high-value opportunities to specific sales reps
Add a filter after opportunity creation that checks the Amount field, then uses Salesforce assignment rules or direct owner updates to automatically assign opportunities over a certain threshold to your senior account executives.
Include shipping and tax as separate line items
Modify the line item loop to add additional OpportunityLineItem records for shipping charges and tax amounts, giving finance teams complete revenue breakdown for reporting and commission calculations.

Frequently asked questions

What happens if a customer or product doesn't exist in Salesforce yet?
The workflow will fail at Step 2 (for missing customers) or Step 4 (for missing products) because it can't find matching records to link. This is why the two dependency workflows must be installed and running first—they ensure customers and products are synced to Salesforce before orders arrive. If you're enabling this for an existing store, run the dependency workflows first and let them sync your historical data.
Can I modify the opportunity stage instead of always using "Closed Won"?
Yes, you can edit the transform in Step 5 to change the "StageName" mapping. For example, you could set it to "Prospecting" for draft orders, "Closed Won" for paid orders, or use conditional logic based on order tags to set different stages. Just make sure your stage name matches exactly what exists in your Salesforce setup.
Will this create duplicate opportunities if I manually replay the workflow?
Yes, each time the workflow runs it creates a new Opportunity and OpportunityLineItems in Salesforce. There's no duplicate checking built in. If you need to reprocess an order, you should manually delete the original Opportunity in Salesforce first, or modify the workflow to search for existing opportunities by a unique field (like adding a Shopify Order ID field) and update instead of create.
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 start syncing Shopify orders to Salesforce opportunities?

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 • 14 min setup • Cancel anytime