Intermediate~15 min setupCRM & E-commerceVerified April 2026
HubSpot logo
Shopify logo

How to Automate HubSpot Lifecycle Stages from Shopify with Power Automate

Automatically updates a HubSpot contact's lifecycle stage when a Shopify customer makes their first purchase, places a repeat order, or hits a cumulative spending threshold.

Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.

Best for

E-commerce marketing teams already inside the Microsoft 365 ecosystem who want Shopify purchase behavior to drive HubSpot lifecycle stage changes without writing code.

Not ideal for

Teams outside Microsoft 365 who need fast iteration — Make or n8n will get this live faster with less licensing friction.

Sync type

real-time

Use case type

sync

Real-World Example

💡

A 12-person DTC apparel brand uses this flow to move customers from 'Subscriber' to 'Customer' in HubSpot the moment their first Shopify order is paid, then to 'Evangelist' once they hit $500 in total spend. Before this, the marketing manager exported Shopify reports weekly and manually updated lifecycle stages in bulk — a 2-hour job that was always 5-7 days behind actual purchase behavior, causing new buyers to receive acquisition emails for days after purchasing.

What Will This Cost?

Drag the slider to your expected monthly volume.

/mo
505005K50K

Each platform counts differently — Zapier: 1 task per trigger. Make: 1 operation per module per record. n8n: 1 execution per run.

Prices shown for annual billing. Based on published pricing as of April 2026.

Estimated ROI

1000

min saved/mo

$583

labor value/mo

Free

no platform cost

Based on ~2 min manual effort per operation at $35/hr fully loaded labor cost.

Implementation

Skip the setup

Import this workflow directly into Power Automate

Copy the pre-built Power Automate blueprint and paste it straight into Power Automate. All modules, filters, and field mappings are already configured — you just need to connect your accounts.

Before You Start

Make sure you have everything ready.

Shopify private app or custom app with Orders read and Customers read API scopes enabled
HubSpot account with OAuth app credentials — Power Automate's HubSpot connector authenticates via OAuth, not API key
HubSpot contact properties: lifecyclestage must be visible and editable via API (not locked by a HubSpot workflow — only one source can own this property at a time)
Power Automate plan with Premium connectors — both Shopify and HubSpot connectors are Premium, requiring at least a Power Automate per-user plan ($15/user/month)
Existing HubSpot contacts with emails matching Shopify customer records — the flow looks up contacts by email, so unmatched customers will cause silent skips

Field Mapping

Map these fields between your apps.

FieldAPI Name
Required
Customer Emailemail
Lifecycle Stagelifecyclestage
Orders Counths_ecomm_last_purchase_date
Total Spenths_analytics_revenue
4 optional fields▸ show
Shopify Customer IDhs_ecomm_last_purchase_amount
Last Order Datehs_ecomm_last_purchase_date
First Namefirstname
Last Namelastname

Step-by-Step Setup

1

make.powerautomate.com > My flows > + New flow > Automated cloud flow

Create a new Automated cloud flow in Power Automate

Go to make.powerautomate.com and sign in. In the left sidebar, click 'My flows', then click '+ New flow' at the top left and select 'Automated cloud flow'. Give the flow a clear name like 'Shopify → HubSpot Lifecycle Stage Updater'. You'll be prompted to choose a trigger — search for 'Shopify' in the trigger search bar to proceed.

  1. 1Go to make.powerautomate.com and sign in
  2. 2Click 'My flows' in the left sidebar
  3. 3Click '+ New flow' in the top left corner
  4. 4Select 'Automated cloud flow'
  5. 5Name the flow 'Shopify → HubSpot Lifecycle Stage Updater' and click 'Create'
What you should see: The flow canvas opens with an empty trigger block and a prompt to choose your trigger.
Common mistake — Do NOT select 'Instant cloud flow' or 'Scheduled cloud flow' — this workflow must fire on Shopify order events in real time, so Automated cloud flow is the only correct choice here.
2

Flow canvas > Trigger picker > Search 'Shopify' > When an order is created

Connect Shopify and configure the 'When an order is created' trigger

In the trigger search bar, type 'Shopify' and select the Shopify connector. Choose the trigger 'When an order is created' — this fires immediately when Shopify marks an order as created, which happens at checkout completion for paid orders. Click 'Sign in' to create a new Shopify connection; you'll need your Shopify store URL (e.g. yourstore.myshopify.com) and a private app API key with Orders read scope. Once authenticated, select your store from the dropdown.

  1. 1Type 'Shopify' in the trigger search bar
  2. 2Select the Shopify connector from the results
  3. 3Click 'When an order is created'
  4. 4Click 'Sign in' and enter your Shopify store URL and API credentials
  5. 5Select your store name from the 'Store' dropdown
What you should see: The trigger block shows your store name and a green connection indicator. Power Automate will now listen for new Shopify orders via webhook.
Common mistake — The Power Automate Shopify connector uses Shopify's REST Admin API, not webhooks you configure manually. Do not create a separate webhook in Shopify's admin — doing so creates duplicate triggers and double-fires your flow.
Power Automate
+
click +
search apps
HubSpot
HU
HubSpot
Connect Shopify and configur…
HubSpot
HU
module added
3

Flow canvas > + New step > Search 'Shopify' > Get customer

Add a 'Get customer' action to retrieve full customer data

Click '+ New step' below the trigger and search for 'Shopify'. Select the action 'Get customer'. In the 'Customer ID' field, click inside the box and select 'Customer ID' from the dynamic content panel on the right — this is the customer ID from the order trigger payload. This step fetches the customer's full profile including email, total orders count, and total spend, which you'll use for lifecycle logic.

  1. 1Click '+ New step'
  2. 2Type 'Shopify' in the action search bar
  3. 3Select 'Get customer'
  4. 4Click the 'Customer ID' input field
  5. 5In the dynamic content panel, select 'Customer ID' from the trigger output
What you should see: The 'Get customer' action block populates with the dynamic Customer ID token and shows a preview of available output fields like Email, Orders Count, and Total Spent.
Common mistake — The 'Total Spent' field returned by this action is a string formatted as a decimal (e.g. '489.00'), not a number. You must use the float() expression to convert it before comparing it to a threshold in the next step.
4

Flow canvas > + New step > Search 'Condition' > Control > Condition

Add a 'Condition' action to determine lifecycle stage

Click '+ New step' and search for 'Condition'. This control block evaluates Shopify customer data to decide which HubSpot lifecycle stage to assign. You'll build two conditions in sequence: first check if the customer's orders count equals 1 (first-time buyer), and if not, check if total spend exceeds your threshold (e.g. $500). Use the 'Add row' option inside the condition to chain multiple checks within one branch using AND/OR logic.

  1. 1Click '+ New step' below the Get customer action
  2. 2Search 'Condition' and select it from the Control category
  3. 3In the left field of the condition, click and select 'Orders Count' from the Get customer dynamic content
  4. 4Set the operator to 'is equal to' and the right value to '1'
  5. 5Click 'Add row' and set a second condition: float(Total Spent) is greater than or equal to 500
What you should see: You see a condition block with a Yes branch and a No branch. The Yes branch will handle first-time buyers; you'll add another nested condition in the No branch for spend-threshold logic.
Common mistake — Filters are the most common place setups break. Double-check the field name and value exactly match what your app sends — a single capital letter difference will block everything.
HubSpot
HU
trigger
filter
Condition
matches criteria?
yes — passes through
no — skipped
Shopify
SH
notified
5

Flow canvas > Condition (No branch) > Add an action > Condition

Add a nested Condition in the 'No' branch for repeat buyers vs. high spenders

Inside the 'No' branch of the first condition, click 'Add an action' and add another Condition. This second condition checks whether the customer's total spend has crossed your threshold — for example, $500. In the left field, use the expression float(body('Get_customer')?['total_spent']) to cast the string to a number. Set the right value to 500. The 'Yes' branch here handles high-spend customers; the 'No' branch handles repeat buyers who haven't yet hit the threshold.

  1. 1Inside the 'No' branch, click 'Add an action'
  2. 2Search and select 'Condition'
  3. 3In the left field, click 'Expression' tab and type: float(body('Get_customer')?['total_spent'])
  4. 4Set the operator to 'is greater than or equal to'
  5. 5Set the right value to 500
What you should see: You now have three logic paths: first-time buyer (outer Yes), high-spender (inner Yes), and repeat buyer not yet at threshold (inner No). Each branch will get its own HubSpot update action.
Common mistake — Shopify returns total_spent in the store's currency but without a currency check. If you operate multiple currencies, this comparison breaks. Add a condition on the currency_code field before the float comparison, or normalize in a separate Compose step first.
6

Flow canvas > Branch > Add an action > HubSpot > Search for contacts

Search for the HubSpot contact by email in each branch

In each of the three logical branches (first-time buyer, high-spender, repeat buyer), add a HubSpot action to find the existing contact. Click 'Add an action', search 'HubSpot', and select 'Search for contacts'. Set 'filterGroups' to search by email equal to the Shopify customer's Email from the Get customer dynamic content. This returns the HubSpot contact ID you need to update the lifecycle stage. Do this in each of the three branches independently.

  1. 1In the first-time buyer branch, click 'Add an action'
  2. 2Search 'HubSpot' and select 'Search for contacts (V2)'
  3. 3Sign in to HubSpot when prompted — use OAuth, not API key
  4. 4In the filter field, set property name to 'email', operator to 'EQ', and value to 'Email' from Get customer dynamic content
  5. 5Repeat in the high-spender and repeat-buyer branches
What you should see: Each branch has a HubSpot search action that will return a contact object including the contact's internal id when the flow runs.
Common mistake — HubSpot's 'Search for contacts' action returns an array. If zero results come back — the customer doesn't exist in HubSpot yet — the Update contact step downstream will fail silently. Add a separate 'Condition' in each branch to check that results[0] is not null before proceeding.
7

Flow canvas > Branch > Add an action > HubSpot > Update a contact

Update the HubSpot contact's lifecycle stage in each branch

After the search action in each branch, add a HubSpot 'Update a contact' action. For the 'Contact ID' field, use the expression first(body('Search_for_contacts')?['results'])?['id'] to pull the contact's ID from the search result. For the property to update, enter the internal name lifecyclestage and set the value to the appropriate HubSpot lifecycle stage internal value: 'customer' for first-time buyers, 'evangelist' for high spenders (or your equivalent custom stage), and 'customer' again for repeat buyers at a lower tier.

  1. 1Click 'Add an action' after the search step in a branch
  2. 2Search 'HubSpot' and select 'Update a contact'
  3. 3In 'Contact ID', switch to Expression and enter: first(body('Search_for_contacts')?['results'])?['id']
  4. 4Click '+ Add property' and enter property name 'lifecyclestage'
  5. 5Set the value to 'customer', 'evangelist', or the appropriate internal HubSpot stage name
What you should see: Each branch now has a complete update action. When the flow runs, the contact's lifecyclestage field in HubSpot will be changed to the value you specified.
Common mistake — HubSpot lifecycle stages can only move forward by default — you cannot downgrade a contact from 'Customer' back to 'Lead' via the API unless you've disabled that restriction in HubSpot's account settings under Objects > Contacts > Lifecycle stage. Check this before assuming bidirectional stage movement works.
8

Flow canvas > Branch > Add an action > Data Operation > Compose

Add a Compose action to log the stage change for debugging

At the end of each branch, add a 'Compose' action (from the Data Operation category) that outputs a readable summary of what happened. Set the input to a string combining the customer email, old stage, and new stage. This creates a log entry visible in the flow's run history, which is invaluable during the first week of production. Use the expression concat('Lifecycle updated for ', body('Get_customer')?['email'], ' → ', 'customer') as the Compose input.

  1. 1Click 'Add an action' at the end of a branch
  2. 2Search 'Compose' and select it from Data Operation
  3. 3Click into the Inputs field and switch to the Expression tab
  4. 4Enter: concat('Lifecycle updated for ', body('Get_customer')?['email'], ' → lifecyclestage: customer')
  5. 5Repeat for each branch, adjusting the lifecycle stage label in the string
What you should see: Each branch ends with a Compose block. In run history, you'll see a readable string like 'Lifecycle updated for [email protected] → lifecyclestage: customer' for every execution.
9

make.powerautomate.com > My flows > [Flow name] > 28 day run history

Test the flow with a real Shopify test order

Save the flow by clicking the 'Save' button in the top right. Then place a real test order in Shopify using a customer email that already exists in HubSpot. Do not use Shopify's draft order feature — the trigger only fires on actual order creation events. After placing the order, go back to Power Automate, click your flow name, and scroll to '28 day run history' to see the run. Check each action for green checkmarks.

  1. 1Click 'Save' in the top right of the flow canvas
  2. 2Place a test order in your Shopify store using a known HubSpot contact's email
  3. 3Return to make.powerautomate.com > My flows and click your flow
  4. 4Scroll to '28 day run history' and click the latest run
  5. 5Expand each action block to confirm green checkmarks and inspect output values
What you should see: The run history shows a successful run with all actions marked green. In HubSpot, navigate to the test contact's record and confirm the Lifecycle Stage field now shows the correct updated value.
Common mistake — Power Automate run history can take 60-90 seconds to appear after a flow fires. If you don't see a run entry immediately, wait 2 minutes before assuming the trigger didn't fire.
Power Automate
▶ Test flow
executed
HubSpot
Shopify
Shopify
🔔 notification
received
10

Flow canvas > Action menu (...) > Configure run after > My flows > [Flow name] > Turn on

Enable error notifications and turn the flow on

Before turning the flow on permanently, add error handling. Click the three-dot menu on any HubSpot action and select 'Configure run after'. Enable the 'has failed' checkbox so you can add an error branch — add a 'Send an email (V2)' action from Office 365 Outlook to notify your team when the HubSpot update fails. Then click 'Turn on' in the flow detail page header. The flow is now live and will fire on every new Shopify order.

  1. 1Click the three-dot menu (...) on the HubSpot 'Update a contact' action
  2. 2Select 'Configure run after'
  3. 3Check the 'has failed' box and click Done
  4. 4Add a 'Send an email (V2)' action in the failure branch with your team's email address
  5. 5Click 'Turn on' in the flow detail page header to activate
What you should see: The flow status shows 'On' with a green indicator in My flows. You'll receive an email alert to your specified address if any HubSpot update action fails.

Paste this expression into a Compose action placed immediately after the 'Get customer' step. It evaluates all three lifecycle scenarios in one expression and outputs the correct HubSpot internal stage string — feed this Compose output directly into the lifecyclestage field of a single HubSpot 'Update a contact' action, replacing the entire nested Condition structure with one action.

JavaScript — Code Step// Power Automate expression — paste into a Compose action's Inputs field
▸ Show code
// Power Automate expression — paste into a Compose action's Inputs field
// This collapses the nested Condition blocks into a single expression
if(

... expand to see full code

// Power Automate expression — paste into a Compose action's Inputs field
// This collapses the nested Condition blocks into a single expression

if(
  equals(int(body('Get_customer')?['orders_count']), 1),
  'customer',
  if(
    greaterOrEquals(
      float(coalesce(body('Get_customer')?['total_spent'], '0')),
      500
    ),
    'evangelist',
    'customer'
  )
)

// Then in HubSpot 'Update a contact', set lifecyclestage to:
// outputs('Compose_lifecycle_stage')
//
// This eliminates 6 separate branch actions and makes the flow
// easier to read, modify, and debug in run history.

Going live

Production Checklist

Before you turn this on for real, confirm each item.

Troubleshooting

Common errors and how to fix them.

Frequently Asked Questions

Common questions about this workflow.

Analysis

VerdictWhy n8n for this workflow

Use Power Automate for this if your company already pays for Microsoft 365 Business Premium or a Power Platform license — you're essentially getting this automation at no marginal cost. It also makes sense if your IT team controls connectors through a Power Platform admin center and needs governance, audit logs, and DLP policies on data moving between your e-commerce store and CRM. Third reason: if your marketing ops team lives in Excel and Teams, the Power Automate UI is already familiar enough that they can maintain this flow without engineering help. The one scenario where you'd skip Power Automate: if you're a standalone e-commerce brand with no Microsoft footprint, the Premium connector licensing ($15/user/month minimum) makes it the most expensive option for this specific workflow.

Cost

Here's the math. The Shopify and HubSpot connectors are both Premium, so you need at least the Power Automate per-user plan at $15/user/month. A store doing 300 orders/month runs 300 flow executions. Each execution makes roughly 4 API calls (trigger, get customer, search contact, update contact). Power Automate doesn't charge per action beyond the plan fee, so your cost stays flat at $15/month per user regardless of order volume. Zapier doing the same workflow at 300 tasks/month costs $19.99/month on the Starter plan — but Zapier counts each action as a task, so 300 orders × 4 actions = 1,200 tasks, pushing you to the Professional plan at $49/month. Make handles 300 operations on the free tier. For volume under 1,000 orders/month, Make is cheaper. Power Automate only wins on cost if you already have the license.

Tradeoffs

Make's biggest advantage here is its visual data flow — you can see the JSON from Shopify's order response mapped to HubSpot fields in a single screen without writing expressions. Zapier has a pre-built 'Update HubSpot contact' action that requires zero expression syntax, making it faster to configure for non-technical users — setup takes about 12 minutes versus 45 minutes for this Power Automate flow. n8n gives you a Code node where you can write the entire lifecycle decision logic in 15 lines of JavaScript, which is cleaner than Power Automate's nested Condition blocks. Pipedream lets you hit HubSpot's v3 API directly with async/await, bypassing connector limitations entirely. Power Automate is still the right call here when enterprise governance matters: data loss prevention policies, AAD-based access control, and integration with Azure Monitor for alerting are things none of the others provide out of the box.

Three things you'll hit after setup. First: Shopify's total_spent field returns as a string, not a number — every numeric comparison in Power Automate requires a float() or int() cast, and forgetting this causes silent condition failures where no branch evaluates as true. Second: HubSpot's lifecycle stage field has a unidirectional lock by default. If a contact is already at 'Customer' and your flow tries to set them back to 'Lead' on a refund scenario, the API accepts the call with a 200 status but the field doesn't change — no error, no indication. You need to explicitly disable backward movement in HubSpot settings or your refund logic will appear to work but won't. Third: Power Automate's Shopify connector does not expose Shopify's order financial_status field in the trigger payload by default. If you want to fire only on paid orders (not pending), you need to add a Condition immediately after the trigger checking that the financial_status from the trigger body equals 'paid' — otherwise you'll update lifecycle stages for orders that never actually completed payment.

Ideas for what to build next

  • Add a HubSpot enrollment trigger for lifecycle-specific email campaignsNow that lifecycle stages update automatically, create HubSpot enrollment workflows that fire when a contact enters 'customer' or 'evangelist' — this connects the stage update to your actual marketing campaigns without any manual list management.
  • Sync new Shopify customers who don't yet exist in HubSpotThe current flow skips contacts not found in HubSpot. Add a branch that creates a new HubSpot contact using the 'Create a contact' action when the search returns zero results, so no Shopify customer is ever left out of your CRM.
  • Write Shopify order data back to HubSpot as custom timeline eventsUse HubSpot's 'Create a timeline event' API call — triggered via Power Automate's HTTP action — to log each Shopify order as a visible event on the HubSpot contact timeline, giving your sales team a purchase history view without leaving the CRM.

Related guides

Was this guide helpful?
HubSpot + Shopify overviewPower Automate profile →