

How to Sync Shopify Revenue Data to HubSpot for Attribution with Pipedream
When a Shopify order is placed, Pipedream pulls the customer's HubSpot contact, matches the order to the originating campaign or traffic source, and writes revenue attribution data back to HubSpot deal and contact properties.
Steps and UI details are based on platform versions at time of writing — check each platform for the latest interface.

Best for
E-commerce marketers who need to see exactly which HubSpot campaigns, email sends, or ad sources drove Shopify revenue — without exporting CSVs manually.
Not ideal for
Stores under 100 orders/month with no HubSpot campaign tracking set up yet — start with HubSpot's native Shopify integration first and graduate to Pipedream when you need custom attribution logic.
Sync type
real-timeUse case type
reportingReal-World Example
A 12-person DTC apparel brand runs 6-8 HubSpot email campaigns per month and spends $40K/month on paid ads tracked through HubSpot UTM parameters. Before this workflow, their marketing analyst spent 4 hours every Monday joining Shopify export CSVs with HubSpot campaign reports in Excel to figure out which campaign drove last week's $180K in orders. With Pipedream firing on every Shopify order webhook, HubSpot contact properties like 'Last Campaign Attributed Revenue' and 'Lifetime Order Value' update within 30 seconds of purchase — and the weekly report now takes 15 minutes to pull.
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.
Field Mapping
Map these fields between your apps.
| Field | API Name | |
|---|---|---|
| Required | ||
| Customer Email | email | |
| Order Total Revenue | amount | |
| Shopify Order ID | shopify_order_id | |
| UTM Campaign | last_attributed_campaign | |
| Order Created Date | last_purchase_date | |
| Deal Close Date | closedate | |
| Shopify Order Name | dealname | |
4 optional fields▸ show
| UTM Source | hs_analytics_source |
| UTM Medium | hs_analytics_source_data_1 |
| Product Names | hs_note_body |
| First Order Flag | hs_is_first_order |
Step-by-Step Setup
pipedream.com > Workflows > New Workflow
Create a new Pipedream workflow
Go to pipedream.com and click 'New Workflow' in the top left of the Workflows dashboard. Give the workflow a name like 'Shopify → HubSpot Revenue Attribution' so it's findable later. You'll land on the workflow canvas with an empty trigger slot at the top. This is where you'll connect Shopify's order webhook in the next step.
- 1Click 'New Workflow' in the top left
- 2Enter a descriptive workflow name in the name field
- 3Click 'Save' to confirm the name before adding a trigger
Workflow Canvas > Add a trigger > Shopify > New Order (Instant)
Add the Shopify 'New Order' webhook trigger
Click the 'Add a trigger' block and search for 'Shopify' in the app search box. Select the Shopify app and choose 'New Order (Instant)' as the trigger — this fires via webhook the moment an order is created in Shopify, not on a polling schedule. Connect your Shopify store by selecting or adding a Connected Account. Pipedream will register a webhook directly in your Shopify store's admin under Settings > Notifications.
- 1Click the 'Add a trigger' block
- 2Type 'Shopify' in the search box and select the Shopify app
- 3Select 'New Order (Instant)' from the trigger list
- 4Click 'Connect a Shopify account' and authorize with your store credentials
- 5Click 'Save and continue'
Workflow Canvas > + Add a step > Custom Code (Node.js)
Extract UTM and traffic source from the Shopify order
Add a Node.js code step immediately after the trigger. Shopify stores UTM attribution data in the order's landing_site and referring_site fields, and in note_attributes if you're passing UTM params through checkout. Write a code step to parse these fields and extract utm_source, utm_medium, utm_campaign, and utm_content so they're available as clean variables for HubSpot in later steps. Without this normalization step, the raw Shopify landing_site field is a full URL string — not useful for matching against HubSpot campaign names.
- 1Click '+ Add a step' below the trigger
- 2Select 'Custom Code' and choose 'Node.js'
- 3Paste your UTM parsing logic into the code editor (see Pro Tip below)
- 4Click 'Test' to run the step against the sample order payload
- 5Verify the parsed UTM fields appear in the step's output in the right panel
Workflow Canvas > + Add a step > HubSpot > Find Contact by Email
Look up the HubSpot contact by email
Add a Pipedream HubSpot step to find the contact record that matches the Shopify order's customer email. Select the 'Search Contacts' or 'Get Contact by Email' action. Map the email field from the Shopify trigger payload (steps.trigger.event.customer.email) into the email search parameter. This step returns the full HubSpot contact object, including the contact's original traffic source, first conversion, and any campaign memberships HubSpot has tracked.
- 1Click '+ Add a step' and search for 'HubSpot'
- 2Select the 'Find Contact' or 'Search Contacts' action
- 3Connect your HubSpot account via Connected Accounts
- 4Set the email parameter to {{steps.trigger.event.customer.email}}
- 5Click 'Test' to confirm the contact is found
Workflow Canvas > + Add a step > HubSpot > Create Deal
Create or update a HubSpot deal for the order
Add a HubSpot 'Create Deal' or 'Update Deal' step. You'll create one deal per Shopify order, representing it as a closed-won revenue event tied to the contact. Map the Shopify order total to the deal's amount field, the order ID to a custom deal property (shopify_order_id), and the parsed UTM campaign name to the deal's hs_analytics_source_data_1 or a custom attribution field. Associate the deal with the contact found in the previous step using the HubSpot contact ID from step 4.
- 1Click '+ Add a step' and select HubSpot
- 2Choose 'Create Deal' from the action list
- 3Set 'Deal Name' to the Shopify order name (e.g. '#1042 - [email protected]')
- 4Map 'Amount' to {{steps.trigger.event.total_price}}
- 5Set 'Pipeline Stage' to your 'Closed Won' stage ID
- 6Add the contact association using the ID from step 4
- 7Map your custom shopify_order_id property to {{steps.trigger.event.id}}
Workflow Canvas > + Add a step > HubSpot > Update Contact
Update HubSpot contact attribution properties
Add a HubSpot 'Update Contact' step to write revenue attribution data back to the contact record itself. This is separate from the deal and gives you contact-level aggregate metrics. Update properties like last_order_revenue (the Shopify order total), last_attributed_campaign (the UTM campaign from step 3), last_purchase_date (the Shopify order created_at timestamp), and lifetime_order_value if you're computing a running total. Use the contact ID from step 4 as the record identifier.
- 1Click '+ Add a step' and select HubSpot
- 2Choose 'Update Contact'
- 3Set the Contact ID to {{steps.find_contact.contact.id}}
- 4Map last_order_revenue to {{steps.trigger.event.total_price}}
- 5Map last_attributed_campaign to {{steps.parse_utms.utm_campaign}}
- 6Map last_purchase_date to {{steps.trigger.event.created_at}}
Workflow Canvas > + Add a step > Shopify > Update Order
Write Shopify order tags back for segmentation
Add a Shopify 'Update Order' step to tag the Shopify order with the HubSpot attribution data. This creates a bidirectional record — Shopify orders get tagged with campaign names like 'hs-campaign:spring-sale-2024' and 'hs-source:google-cpc', which lets your Shopify analytics and any downstream apps also see the attribution context. Use the Shopify order ID from the trigger payload and append new tags without overwriting existing ones.
- 1Click '+ Add a step' and select Shopify
- 2Choose 'Update Order'
- 3Set Order ID to {{steps.trigger.event.id}}
- 4Set Tags to a concatenated string of existing tags plus your new attribution tags
- 5Click 'Test' and verify the tags appear in Shopify admin under the order
Workflow Canvas > Step options (...) > Add error handler
Add error handling with a catch branch
Click the '...' menu on any step that might fail (the HubSpot contact lookup and both write steps are the highest-risk) and enable 'Continue on error' or add an error path. In Pipedream, you can add a conditional step after the contact lookup that checks if the contact was found before proceeding. Log failed attribution events to a Pipedream data store or send a summary to a Slack channel so unmatched orders don't silently drop attribution data.
- 1Click the '...' menu on the HubSpot 'Find Contact' step
- 2Enable 'Continue workflow on error'
- 3Add a conditional step below to check if steps.find_contact.contact exists
- 4In the false branch, add a Pipedream Data Store step to log the unmatched order
- 5Optionally add a Slack notification step in the false branch
Shopify Admin > Settings > Payments > Test mode
Test with a real Shopify test order
In Shopify Admin, go to Settings > Payments and enable test mode. Place a test order using an email address that exists in your HubSpot CRM. Watch the Pipedream workflow event inspector fire in real time — each step should go green within a few seconds. Confirm the deal was created in HubSpot, the contact properties were updated, and the Shopify order now has attribution tags. Then disable Shopify test mode.
- 1Enable test mode in Shopify Payments settings
- 2Place a test order using a real HubSpot contact email
- 3Switch to Pipedream and watch the workflow run in the event inspector
- 4Verify each step shows green status
- 5Open HubSpot CRM and confirm the deal and contact property updates
- 6Disable Shopify test mode when done
Workflow Canvas > Deploy button (top right)
Deploy the workflow and monitor the first 48 hours
Click 'Deploy' in the top right of the Pipedream workflow canvas to move the workflow from development to production. Pipedream will activate the Shopify webhook and start processing live orders. Monitor the Pipedream event inspector for the first 48 hours — check for any steps showing yellow warnings or red errors. Pay particular attention to orders where the HubSpot contact lookup returns empty, as these are your unmatched attribution gaps.
- 1Click the blue 'Deploy' button in the top right corner
- 2Confirm deployment in the dialog that appears
- 3Click 'Runs' in the left sidebar to monitor live events
- 4Filter by 'Error' status to catch any failing runs immediately
- 5Check your Pipedream Data Store for unmatched order logs after 24 hours
Paste this code into the Node.js step at position 2 (immediately after the Shopify trigger). It parses UTM parameters from Shopify's landing_site URL, falls back gracefully to 'direct' when landing_site is null, converts the order total to a proper float, and exports a clean attribution object that every downstream HubSpot step can reference via steps.parse_attribution.
JavaScript — Code Step// Step: parse_attribution▸ Show code
// Step: parse_attribution
// Extracts UTM data from Shopify order and prepares HubSpot-ready attribution fields
export default defineComponent({... expand to see full code
// Step: parse_attribution
// Extracts UTM data from Shopify order and prepares HubSpot-ready attribution fields
export default defineComponent({
async run({ steps, $ }) {
const order = steps.trigger.event;
// Parse UTM parameters from landing_site URL
let utmSource = 'direct';
let utmMedium = null;
let utmCampaign = 'direct';
let utmContent = null;
if (order.landing_site) {
try {
const url = new URL(order.landing_site);
utmSource = url.searchParams.get('utm_source') || 'direct';
utmMedium = url.searchParams.get('utm_medium') || null;
utmCampaign = url.searchParams.get('utm_campaign') || 'direct';
utmContent = url.searchParams.get('utm_content') || null;
} catch (e) {
// landing_site exists but isn't a valid URL — treat as direct
console.log(`Could not parse landing_site: ${order.landing_site}`);
}
}
// Safely convert Shopify's string price to a float HubSpot will accept
const orderRevenue = parseFloat(order.total_price);
if (isNaN(orderRevenue)) {
throw new Error(`Invalid total_price value: ${order.total_price}`);
}
// Build clean product name list from line items
const productNames = (order.line_items || [])
.map(item => `${item.title} (x${item.quantity})`)
.join(', ');
// ISO date string for HubSpot date properties (milliseconds since epoch)
const closeDateMs = new Date(order.created_at).getTime();
return {
customerEmail: order.customer?.email?.toLowerCase().trim(),
shopifyOrderId: order.id.toString(),
orderName: order.name,
orderRevenue,
closeDate: closeDateMs,
utmSource,
utmMedium,
utmCampaign,
utmContent,
productNames,
isGuestCheckout: !order.customer?.id,
};
}
});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 has a developer (or you're comfortable writing Node.js) and you need custom attribution logic that no point-and-click tool can handle. Specifically: UTM parsing from Shopify's landing_site field, fallback attribution strategies for null traffic sources, or multi-touch weighting across order history. Pipedream fires the webhook in under 500ms of the Shopify order creation and gives you a Node.js environment to transform data exactly how you need it. The one scenario where you'd pick something else: if your attribution needs are simple last-touch UTM → HubSpot deal, HubSpot's native Shopify integration (under Settings > Integrations > Shopify) handles that with zero code and zero monthly cost.
Pipedream's free tier gives you 10,000 invocations/month. Each order run through this workflow costs 1 invocation plus roughly 2-3 compute credits per step — at 5 active steps, that's about 15 credits per order. The free tier includes 100,000 compute credits/month, so you can process roughly 6,600 orders/month before hitting limits. Stores doing 300+ orders/day need Pipedream's Basic plan at $19/month (10M credits). Compare that to Zapier, where this same 5-step workflow would cost you $49-$73/month on a Professional plan at equivalent volume. Make's Core plan at $9/month handles the same volume for significantly less, but you lose the Node.js code step flexibility.
Zapier has a pre-built 'HubSpot + Shopify' template that maps order data to contacts in about 8 minutes — if your needs fit the template, it wins on setup speed. Make's scenario builder is better for conditional routing (e.g. apply different attribution logic for orders over $500 vs. under $500) because its filter UI is visual and immediate. n8n gives you the same Node.js power as Pipedream and is cheaper at self-hosted scale, but the webhook setup is more manual — Pipedream auto-registers Shopify webhooks through its Connected Accounts system, saving 20-30 minutes per setup. Power Automate has a Shopify connector but it's a premium connector ($15/user/month add-on) and HubSpot's PA connector is notoriously slow to authenticate — avoid it for this use case. Pipedream wins specifically because of how fast the webhook processing is and how cleanly the Connected Accounts system handles Shopify + HubSpot auth simultaneously.
Three things you'll hit after setup. First: Shopify's landing_site field is null for roughly 30-40% of orders from returning customers who navigate directly — your attribution reports will show a lot of 'direct' unless you implement a secondary attribution method like HubSpot's tracking cookie or a first-touch property stored on the contact. Second: HubSpot's API rate limit is 100 requests per 10 seconds on Starter plans. During a flash sale where you process 50 orders in a minute, Pipedream will queue the webhooks but your HubSpot write steps will start returning 429 rate limit errors — add exponential backoff retry logic in your code step if you run promotions. Third: Shopify returns created_at timestamps in the store's local timezone, but HubSpot's date properties expect Unix milliseconds in UTC. If you don't convert properly, your deal close dates will be off by your timezone offset hours and your monthly revenue attribution reports in HubSpot will miscount orders near midnight.
Ideas for what to build next
- →Add campaign-level revenue roll-ups to HubSpot — Extend this workflow to also write to HubSpot's custom object layer — create a 'Campaign Revenue' custom object and update an aggregate revenue total per campaign each time an order fires. This gives you a live campaign revenue dashboard inside HubSpot without needing to pull a deal report.
- →Build a weekly attribution digest to Slack — Create a second Pipedream workflow on a weekly schedule that queries HubSpot's deal API for the past 7 days, groups deals by utm_campaign, computes revenue per campaign, and posts a ranked summary to your #marketing Slack channel every Monday morning.
- →Add multi-touch attribution scoring — Modify the contact update step to maintain an array of all campaign touchpoints in a HubSpot multi-line text property, not just the last-touch campaign. Then add a code step that computes linear or time-decay attribution weights across touchpoints and writes individual campaign credit values back to HubSpot.
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