

How to Automate HubSpot Lifecycle Stages from Shopify with Pipedream
Automatically updates a HubSpot contact's lifecycle stage when a Shopify customer makes their first purchase, places a repeat order, or crosses a total spend 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 who need HubSpot lifecycle stages to reflect real Shopify purchase behavior without manual CSV imports or guesswork.
Not ideal for
Stores with high order volumes needing bulk backfills — use a direct HubSpot API script or Fivetran for historical data instead.
Sync type
real-timeUse case type
syncReal-World Example
A 12-person DTC apparel brand uses this to move customers from 'Lead' to 'Customer' the moment their first Shopify order is paid, then to 'Evangelist' once they hit $500 in total spend. Before this workflow, the marketing team ran a manual HubSpot import every Friday — lifecycle stages were always 4-7 days stale, meaning new buyers were still receiving acquisition emails days after purchasing.
What Will This Cost?
Drag the slider to your expected monthly volume.
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
Import this workflow directly into Pipedream
Copy the pre-built Pipedream blueprint and paste it straight into Pipedream. 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.
Optional
Field Mapping
Map these fields between your apps.
| Field | API Name | |
|---|---|---|
| Required | ||
| Customer Email | email | |
| Lifecycle Stage | lifecyclestage | |
| Total Shopify Spend | shopify_total_spend | |
| Shopify Order Count | shopify_order_count | |
4 optional fields▸ show
| First Name | firstname |
| Last Name | lastname |
| Last Order Date | shopify_last_order_date |
| Shopify Customer ID | shopify_customer_id |
Step-by-Step Setup
pipedream.com > Workflows > + New Workflow
Create a new Pipedream workflow
Go to pipedream.com and log in. From the left sidebar, click 'Workflows', then click the blue '+ New Workflow' button in the top right. Give the workflow a clear name like 'Shopify → HubSpot Lifecycle Stages'. You'll land on the workflow canvas with an empty trigger slot waiting.
- 1Click 'Workflows' in the left sidebar
- 2Click '+ New Workflow' in the top right
- 3Type a name: 'Shopify → HubSpot Lifecycle Stages'
- 4Click 'Create'
Workflow Canvas > Add a trigger > Shopify > New Order (Instant)
Add the Shopify order paid webhook trigger
Click the grey 'Add a trigger' block. In the search box, type 'Shopify' and select it. From the event list, choose 'New Order (Instant)' — this fires via webhook the moment Shopify marks an order as paid. Connect your Shopify store by clicking 'Connect Shopify Account' and entering your store URL and API credentials. Pipedream will auto-register the webhook in your Shopify admin.
- 1Click the 'Add a trigger' block
- 2Search for 'Shopify' in the app search bar
- 3Select 'New Order (Instant)' from the trigger list
- 4Click 'Connect Shopify Account'
- 5Enter your Shopify store URL (e.g., yourstore.myshopify.com) and generate a Private App API key
- 6Click 'Save and continue'
Workflow Canvas > + Add a step > Run Node.js code
Extract and normalize order data in a Node.js code step
Click '+ Add a step' below the trigger and choose 'Run Node.js code'. This step pulls the customer email, order total, and order count from the Shopify payload. You'll also set a preliminary lifecycle stage variable here based on the order data — this keeps the logic in one place before you make any API calls. Paste the code from the Pro Tip section below into this code step.
- 1Click '+ Add a step'
- 2Select 'Run Node.js code'
- 3Paste the lifecycle classification code into the editor
- 4Click 'Test' to verify the step runs against the sample Shopify payload
Paste this into the Node.js code step (step 3) that sits immediately after the Shopify trigger. It parses the raw Shopify order payload, calculates lifecycle stage based on order count and total spend thresholds, and exports clean values for every downstream HubSpot step to reference via steps.classify_lifecycle.
JavaScript — Code Step// Step name: classify_lifecycle▸ Show code
// Step name: classify_lifecycle
// Pipedream Node.js code step — paste into 'Run Node.js code' after Shopify trigger
export default defineComponent({... expand to see full code
// Step name: classify_lifecycle
// Pipedream Node.js code step — paste into 'Run Node.js code' after Shopify trigger
export default defineComponent({
async run({ steps, $ }) {
const order = steps.trigger.event.body;
// Safely extract customer data from Shopify payload
const customer = order.customer;
if (!customer || !customer.email) {
return $.flow.exit('No customer email in order payload — skipping.');
}
const email = customer.email.trim().toLowerCase();
const firstName = customer.first_name || '';
const lastName = customer.last_name || '';
const orderCount = parseInt(customer.orders_count, 10) || 1;
// Shopify sends total_spent as a string — parse it
const totalSpent = parseFloat(customer.total_spent) || 0;
// Define your lifecycle thresholds here
// Adjust SPEND_THRESHOLD and REPEAT_ORDER_MIN to match your store
const SPEND_THRESHOLD_EVANGELIST = 1000; // $1,000+ total spend
const SPEND_THRESHOLD_OPPORTUNITY = 400; // $400+ total spend
const REPEAT_ORDER_MIN = 2; // 2+ orders = repeat customer
// Determine lifecycle stage based on purchase behavior
let lifecycleStage;
if (totalSpent >= SPEND_THRESHOLD_EVANGELIST) {
lifecycleStage = 'evangelist';
} else if (totalSpent >= SPEND_THRESHOLD_OPPORTUNITY || orderCount >= REPEAT_ORDER_MIN) {
lifecycleStage = 'opportunity';
} else if (orderCount === 1) {
lifecycleStage = 'customer';
} else {
lifecycleStage = 'lead';
}
const orderDate = new Date(order.created_at).toISOString().split('T')[0];
console.log(`Customer: ${email} | Orders: ${orderCount} | Spent: $${totalSpent} | Stage: ${lifecycleStage}`);
// Return values for downstream steps
return {
customer_email: email,
first_name: firstName,
last_name: lastName,
total_spent: totalSpent,
order_count: orderCount,
lifecycle_stage: lifecycleStage,
shopify_customer_id: String(customer.id),
last_order_date: orderDate,
};
},
});Workflow Canvas > + Add a step > HubSpot > Search Contacts
Look up the HubSpot contact by email
Add another step and select the HubSpot app. Choose the action 'Search Contacts'. Set the search property to 'email' and the value to the customer email extracted in the previous step using the reference {{steps.nodejs_1.customer_email}}. Connect your HubSpot account via 'Connected Accounts' — you'll need a Private App token with contacts read/write scope. This step returns the HubSpot contact ID you need for the update call.
- 1Click '+ Add a step'
- 2Search for 'HubSpot' and select it
- 3Choose the action 'Search Contacts'
- 4Set 'Property' to 'email'
- 5Set 'Value' to {{steps.nodejs_1.customer_email}}
- 6Click 'Connect HubSpot Account' and paste your Private App token
Workflow Canvas > + Add a step > Run Node.js code
Handle the case where no HubSpot contact exists
Add a Node.js code step immediately after the search step. Check whether the results array is empty. If no contact is found, use the HubSpot API to create a new contact with the customer's email, first name, and last name from the Shopify payload. Return the new contact's ID so subsequent steps can reference it consistently. This prevents the update step from throwing a 404 on net-new Shopify customers.
- 1Click '+ Add a step'
- 2Select 'Run Node.js code'
- 3Write conditional logic: if results array length is 0, call HubSpot POST /crm/v3/objects/contacts
- 4Return the contact ID whether created or found
- 5Click 'Test' to verify both branches work
Workflow Canvas > + Add a step > Run Node.js code
Add a filter step to prevent lifecycle stage downgrades
HubSpot's lifecycle stage field has a strict progression: you cannot move a contact backward (e.g., from 'Customer' back to 'Lead') via a standard property update — but you can via API if you force it, which corrupts your funnel data. Add a Node.js code step that compares the contact's current lifecyclestage from the search result against the new stage you're about to set. If the new stage is not an advancement, export a flag and use Pipedream's $.flow.exit() to stop the workflow cleanly.
- 1Click '+ Add a step'
- 2Select 'Run Node.js code'
- 3Define the stage order array: ['subscriber', 'lead', 'marketingqualifiedlead', 'salesqualifiedlead', 'opportunity', 'customer', 'evangelist']
- 4Compare current stage index to new stage index
- 5Call $.flow.exit('Stage not an advancement') if the new stage index is not higher
Workflow Canvas > + Add a step > HubSpot > Update Contact
Update the HubSpot contact's lifecycle stage
Add a HubSpot step and choose 'Update Contact'. Set 'Contact ID' to the resolved contact_id from step 5. Map 'Lifecycle Stage' to the lifecycle_stage value from step 3's code output. You can also map additional fields here: total Shopify spend to a custom HubSpot property, and order count to another. This is the step that actually writes to HubSpot.
- 1Click '+ Add a step'
- 2Search for 'HubSpot' and select 'Update Contact'
- 3Set 'Contact ID' to {{steps.resolve_contact.contact_id}}
- 4Set 'Lifecycle Stage' to {{steps.nodejs_1.lifecycle_stage}}
- 5Add custom property: shopify_total_spend = {{steps.nodejs_1.total_spent}}
- 6Add custom property: shopify_order_count = {{steps.nodejs_1.order_count}}
- 7Click 'Test'
Workflow Canvas > + Add a step > Run Node.js code OR Settings > Error Handling
Add error handling and Slack alert for failures
Add a final Node.js code step that wraps in a try/catch. If any upstream step has thrown an error (check steps via Pipedream's event inspection), post a message to a Slack channel with the customer email, the attempted lifecycle stage, and the error message. This gives your team visibility without requiring manual log checks. Alternatively, use Pipedream's built-in error workflow feature under Settings > Error Handling.
- 1Click '+ Add a step'
- 2Select 'Run Node.js code'
- 3Add a try/catch block referencing upstream step outputs
- 4On catch, use the Slack API or Pipedream's Slack app to post to #ecommerce-alerts
- 5Alternatively, go to workflow Settings > Error Handling and set a dedicated error workflow
Workflow Canvas > Deploy > Events tab
Deploy and verify with a live test order
Click 'Deploy' in the top right of the Pipedream workflow canvas. Place a real test order in your Shopify store (use a $0.00 discount code if needed) with an email tied to an existing HubSpot test contact. Watch the Pipedream run log in real time under the 'Events' tab. Confirm the contact's lifecycle stage updates in HubSpot within 60 seconds of the order being marked paid.
- 1Click 'Deploy' button in the top right
- 2Place a test order in Shopify with a known contact email
- 3Open Pipedream > Workflows > [your workflow] > Events tab
- 4Watch for the new event to appear and click it to inspect each step's output
- 5Verify in HubSpot CRM that the contact's lifecycle stage has updated
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
Use Pipedream for this if your team includes at least one developer or a technical marketer comfortable with JavaScript. The Node.js code step is where this workflow earns its complexity — you need conditional logic across three threshold checks, a downgrade guard, and a create-or-update pattern for HubSpot contacts. Pipedream handles all of that in a single workflow without duct-taping together multiple tools. The one scenario where you'd pick something else: if your team is entirely non-technical, Make's visual conditional router handles the same branching logic without writing a line of code.
Pipedream pricing works on a credit model. Each workflow run consumes credits based on compute time. A typical run of this workflow — trigger + 4 steps + one HubSpot API call — costs roughly 10-15 credits. At 1,000 Shopify orders/month, that's 10,000-15,000 credits. Pipedream's free tier includes 10,000 credits/month, so you'll hit the ceiling right around 1,000 orders. The Basic plan at $19/month gives you 100,000 credits — enough for roughly 7,000-10,000 orders/month. Make's equivalent workflow costs about $9/month at the same volume using their operations model. Pipedream costs more at scale, but the code flexibility offsets it if you're doing anything non-trivial.
Zapier has a pre-built HubSpot 'Update Contact' action that's genuinely easier to configure for simple field mapping — no code required — but it can't handle the create-or-update pattern without a second Zap and a Filter step, which burns through tasks fast. Make's router module handles the multi-branch lifecycle logic visually and costs less, but debugging complex data transformations in Make's formula editor is painful compared to reading a Node.js stack trace. n8n's Function node is nearly identical to Pipedream's code step but requires self-hosting or n8n Cloud — add operational overhead. Power Automate has no native Shopify trigger; you'd need a third-party connector. Pipedream wins here because the webhook is instant, the code step is first-class, and the Shopify + HubSpot integrations are maintained by the Pipedream team.
Three things you'll hit after setup. First: HubSpot's lifecycle stage field does not fire a property change webhook when updated via API the same way it does via the UI — if you're planning to use HubSpot Workflows triggered by lifecycle stage changes, test this explicitly before assuming the chain works. Second: Shopify's orders_count on the customer object reflects all orders, including cancelled and refunded ones. A customer who ordered twice and refunded once shows orders_count: 2, which may incorrectly qualify them as a repeat buyer. Add a check against order.financial_status to filter out refunded orders. Third: Pipedream has a 30-second execution timeout per step by default. If you batch any HubSpot calls or add retries, stay well under that limit or your step will time out mid-write and leave the contact in a partial update state.
Ideas for what to build next
- →Trigger HubSpot Workflows from Lifecycle Stage Changes — Now that lifecycle stages update in real time, configure HubSpot Workflow automations to enroll contacts in email sequences when they hit 'customer' or 'evangelist' — this closes the loop between Shopify purchase data and your marketing campaigns.
- →Add a Reverse Sync for HubSpot-Qualified Leads to Shopify — Build a second Pipedream workflow that listens for HubSpot lifecycle stage changes (via HubSpot webhook) and adds a Shopify customer tag like 'hs-evangelist' — this lets your Shopify store display loyalty pricing or exclusive products to high-value HubSpot segments.
- →Enrich with Refund and Churn Signals — Extend this workflow to also listen for Shopify 'refunds/create' webhooks and move contacts back to an appropriate stage or add a HubSpot contact property like shopify_refund_count — giving your sales team visibility into at-risk customers before they churn.
Related guides
How to Share Notion Meeting Notes to Slack with Pipedream
~15 min setup
How to Share Notion Meeting Notes to Slack with Power Automate
~15 min setup
How to Share Notion Meeting Notes to Slack with n8n
~20 min setup
How to Send Notion Meeting Notes to Slack with Zapier
~8 min setup
How to Share Notion Meeting Notes to Slack with Make
~12 min setup
How to Create Notion Tasks from Slack with Pipedream
~15 min setup