When to use it, when not to
Use it
- Use it when forecast reviews keep surfacing deals nobody touched in weeks.
- Use it to enforce a minimum touch cadence on mid-funnel stages (demo, proposal, negotiation).
Skip it
- Do not use a flat 14-day threshold across every stage. Long-cycle stages (legal review, procurement) need a longer threshold or an exclusion, or the alert becomes noise reps ignore.
- Do not use this as the only signal for deal health. Pair it with amount and stage in a combined risk score (see deal-hygiene-021) once the base version is stable.
Prerequisites
- Property:
Stale Deal Flag(internal namestale_deal_flag), object deal, field type single checkbox. Why: prevents the workflow from re-notifying every time the filter is re-evaluated before the deal actually goes quiet again. - Confirm the native property
Last Activity Date(internal namenotes_last_updated, the same on contacts, companies, deals and tickets, see https://developers.hubspot.com/ ) is present and populated by logged engagements (calls, emails, meetings) associated to the deal record, not only to the contact.changelog/ updates-to-next-activity-and-last-activity-property-groups - List of pipeline stages to exclude from this workflow (typically Closed Won, Closed Lost, and any stage that is expected to sit dormant, such as "Legal Review").
- Property:
Manager(internal namemanager), object deal, field type HubSpot user, optional and used only by the escalation step, or HubSpot Teams hierarchy (nested team hierarchies need an Enterprise subscription and there is no native "notify the owner's manager" action, so on Professional the Manager property is the only route, https://knowledge.hubspot.com/ ). A HubSpot user type property cannot be created through the batch properties API; create it once in Settings > Objects > Deals > Properties.user-management/ create-and-manage-teams
Enrollment
| Trigger type | filter-based, with re-enrollment on. |
|---|---|
| Criteria | Deal stage is not any of [Closed Won, Closed
Lost] AND Last Activity Date is more than 14 days ago AND
Stale Deal Flag is not equal to true. |
| Re-enrollment | yes, re-evaluate when Last Activity Date
changes. This lets a deal re-enter the workflow once it goes quiet again
after a fresh touch. |
| Suppression / exclusions | static list or property filter excluding sandbox/test pipelines (see deal-hygiene-038), and excluding any stage explicitly marked as long-dormant. |
Steps
- If/then branch:
Stale Deal Flagis equal to true- Yes: exit workflow (already flagged, avoid duplicate notifications)
- No: continue
- Set property value:
Stale Deal Flag= true - Create task: type "To-do", title "Deal stale - no activity 14+ days: {{deal.dealname}}", assigned to record owner, due in 1 business day
- Send internal email notification to: record owner, subject "No activity on {{deal.dealname}} in 14+ days"
- Delay for 14 days
- If/then branch:
Last Activity Dateis still more than 14 days ago ANDDeal stageis still not Closed Won/Closed Lost- Yes: Send internal email notification to: manager property (or Teams hierarchy contact), subject "Escalation: {{deal.dealname}} stale for 28+ days"
- No: Set property value:
Stale Deal Flag= false, then exit
Known pitfalls
Last Activity Dateon deals only updates from engagements logged against the deal record itself. A call logged only on the associated contact does not always roll up to the deal An activity logged on a contact is auto-associated only to the contact's primary company and its five most recent open deals, and only if the deal was already associated to the contact before logging (https://knowledge.hubspot.com/ ).records/ associate-activities-with-records - Re-enrollment loops: because step 2 sets
Stale Deal Flagin the same run, the enrollment criteria (Stale Deal Flagnot equal true) prevents an immediate re-trigger, but only if the criteria snapshot is taken before the property write. Test this explicitly. - Escalating to "manager" has no native lookup on Sales Hub
Professional. Without a populated
Managerproperty or Enterprise Teams hierarchy, this step silently fails to resolve a recipient. - Activating the workflow does not retroactively enroll existing stale deals unless "enroll existing records that match" is checked at activation time.
- Due dates on tasks use the portal's default timezone, which can be misleading for distributed teams.
Test plan
- Create a test deal in an open, non-excluded stage and leave
Last Activity Dateblank or older than 14 days. - Activate the workflow with "enroll existing records" checked, or wait for the next evaluation cycle.
- Open Automation > Workflows > this workflow > History tab, confirm the deal enrolled and each action shows success.
- Check the deal record's timeline for the created task and the internal notification event.
- Log a call against the deal, confirm
Last Activity Dateupdates, then confirmStale Deal Flagresets to false after the escalation branch resolves on the next cycle.
The UAT script of this spec holds 5 cases: a negative case, one case per branch, the expected result of each and a sign-off sheet. It comes as Markdown and as a CSV for your spreadsheet.
Variants
- Ticket version: same structure applied to tickets with no activity, for the tickets-sla category.
- Company-level version: flag companies with no open-deal activity instead of individual deals.
- Slack instead of email: route the notification through the Slack
integration action if connected (the action is "Send a Slack
notification" under Integrated apps > Slack in the action panel,
available once the Slack integration is connected,
https://
knowledge.hubspot.com/ ).integrations/ how-do-i-use-the-slack-integration
Build spec
trigger:
type: filter_based
reenrollment: true
reenrollment_property: notes_last_updated
object: deal
criteria:
- property: dealstage
operator: not_in
value: [closedwon, closedlost]
- property: notes_last_updated
operator: more_than_days_ago
value: 14
- property: stale_deal_flag
operator: not_equal
value: true
actions:
- type: if_then_branch
condition: stale_deal_flag == true
if_true:
- type: exit_workflow
if_false:
- type: set_property_value
property: stale_deal_flag
value: true
- type: create_task
task_type: todo
title: "Deal stale - no activity 14+ days: {{deal.dealname}}"
assigned_to: record_owner
due: +1_business_day
- type: send_internal_email_notification
to: record_owner
subject: "No activity on {{deal.dealname}} in 14+ days"
- type: delay
duration: 14_days
- type: if_then_branch
condition: notes_last_updated more_than_days_ago 14 AND dealstage not_in [closedwon, closedlost]
if_true:
- type: send_internal_email_notification
to: manager_property
subject: "Escalation: {{deal.dealname}} stale for 28+ days"
if_false:
- type: set_property_value
property: stale_deal_flag
value: falseFiles and install
| File | What it holds |
|---|---|
| PDF and Markdown | The spec as you read it here, with the YAML build spec at the end. |
| Properties JSON | Creates the fields in one API call. |
| Workflow JSON | Documents the build: the workflow in Automation API v4 format, switched off. |
| UAT script | The test cases, the expected results and a sign-off sheet, as Markdown and CSV. |
Take the PDF and build it by hand. One-click install comes with a category pack or the full library.
Install deal-hygiene-001
One email, and we tell you where this stands. When free installs open, that address is how you hear it first.
No card, no password, unsubscribe in one click.
Nothing deleted, enabled or enrolled.
deal-hygiene-001Spec version 2026-09