Write-Back to HubSpot: Turning Churn Predictions into CSM Tasks Automatically
Most churn models end up as a dashboard that nobody checks. Here is how to wire churn probability scores directly into HubSpot so CSM tasks create themselves before the account goes dark.
The Last-Mile Problem Nobody Talks About
Teams that invest in churn prediction tend to focus on the hard part - data preparation, model training, AUC scores. Then the model is done, and someone exports the predictions to a spreadsheet. Or builds a Looker dashboard. Or sets up a weekly CSV email to the CS team.
And then nothing changes. The spreadsheet sits in a shared drive. The dashboard gets checked on Mondays, sometimes. The CSV goes to the same folder as last week's CSV. CSMs are still triaging accounts from memory and intuition, and the model predictions are not changing their behavior.
This is the last-mile problem. The model works, but the operational loop is broken. Predictions that are not embedded into the workflows CSMs already live in - HubSpot tasks, sequences, contact views, activity feeds - might as well not exist.
The fix is HubSpot write-back: push churn probability scores directly into HubSpot as a custom property, then build workflows that act on the score automatically. When a score crosses a threshold, a task creates itself. When a score surges week-over-week, the CSM gets notified. When a score hits critical, the account enters a save play sequence - without anyone manually doing the routing.
Here is how to set it up from scratch.
Step 1 - Create the Custom Property in HubSpot
Before writing a single line of code, the property needs to exist in HubSpot. Navigate to Settings > Properties > Company Properties (or Contact Properties, depending on whether your churn model scores at the company or contact level - most B2B CS teams use Company).
Create a new property with these settings:
- Label: Churn Probability Score
- Internal name:
churn_probability_score - Field type: Number
- Value range: 0 to 100 (where 100 = certain churn, 0 = no churn risk)
Also create a second property while you are here:
- Label: Churn Score Updated At
- Internal name:
churn_score_updated_at - Field type: Date picker
This timestamp property will be useful later for detecting score changes week-over-week and for auditing when the model last ran.
Step 2 - Update Scores via the HubSpot API
The HubSpot CRM v3 API makes property updates straightforward. No SDK is required - the requests library handles everything. The core function is a PATCH call to the company object endpoint:
import requests
from datetime import datetime
def update_churn_score(company_id: str, score: float, api_key: str) -> int:
url = f"https://api.hubapi.com/crm/v3/objects/companies/{company_id}"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload = {
"properties": {
"churn_probability_score": round(score, 1),
"churn_score_updated_at": datetime.utcnow().strftime("%Y-%m-%d")
}
}
response = requests.patch(url, json=payload, headers=headers)
return response.status_code
If you are updating scores for a full account portfolio - say, 500 companies after a weekly model run - use the HubSpot Batch Update endpoint instead of calling the single-object endpoint in a loop. Batch updates accept up to 100 records per request and are significantly faster:
def batch_update_churn_scores(records: list[dict], api_key: str) -> int:
"""
records: list of {"id": "<company_id>", "score": <float>}
"""
url = "https://api.hubapi.com/crm/v3/objects/companies/batch/update"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload = {
"inputs": [
{
"id": r["id"],
"properties": {
"churn_probability_score": round(r["score"], 1),
"churn_score_updated_at": datetime.utcnow().strftime("%Y-%m-%d")
}
}
for r in records
]
}
response = requests.post(url, json=payload, headers=headers)
return response.status_code
Split your full account list into chunks of 100 and call this function in sequence. Rate limits on the HubSpot v3 API are 100 requests per 10 seconds for Professional/Enterprise tiers - batch updates make it easy to stay within that limit even for large portfolios.
Step 3 - Build the Four Core HubSpot Workflows
With scores writing back automatically, HubSpot Workflows become the operational layer. Here are the four templates that cover the full at-risk intervention stack.
Workflow 1 - At-Risk Alert (score > 70)
Trigger: Company property churn_probability_score is greater than 70.
Actions:
- Create task for the company's HubSpot owner: "Retention Check - [Company Name] crossed 70 churn risk score"
- Set task due date: 2 business days from trigger
- Send internal Slack or email notification to the CS team lead
This is the daily triage workflow. It runs every time a score update pushes a company above the 70 threshold, which means CSMs do not need to check any dashboard. The task appears in their HubSpot queue.
Workflow 2 - Save Play Enrollment (score > 85)
Trigger: Company property churn_probability_score is greater than 85.
Actions:
- Enroll primary contact in "At-Risk Save Play" email sequence
- Add company to a static list "Active Save Plays" for manual CS review
- Create a deal in the pipeline stage "Churn Risk - Intervention Required"
A score above 85 means the model predicts high churn probability. This threshold should trigger active intervention - not just awareness. The sequence can include a direct CSM outreach, an executive business review invitation, or a product adoption check-in, depending on your save play strategy.
Workflow 3 - Health Score Activity Log (score changes by 10+ points)
Trigger: Company property churn_probability_score changes.
Filter: Only run if the absolute change is 10 or more points.
Actions:
- Log a custom activity note on the company record: "Churn score moved from [previous value] to [new value] on [date]"
This workflow turns the score history into a visible audit trail in HubSpot's activity feed. CSMs can open any account and see exactly how the risk profile has changed over time - which is more useful for account conversations than a single current score.
Workflow 4 - Weekly Surge Digest
This one requires a slightly different setup. Use a scheduled workflow that runs every Monday morning.
Trigger: Scheduled - every Monday at 8:00 AM.
Filter: Companies where churn_probability_score is greater than 60 AND churn_score_updated_at is within the last 7 days.
Actions:
- Create a task for the CS team lead: "Weekly At-Risk Review - [N] accounts above 60 score"
- Send a summary email to the RevOps lead with company count and list
The surge digest gives team leads a weekly pulse on portfolio risk without requiring them to run any manual report.
Step 4 - Build the CSM Daily Triage View
The four workflows handle automation. This step handles the human review layer.
In HubSpot, create an Active List with these filters:
churn_probability_scoreis greater than 60lifecyclestageis Customer
Sort the list by churn_probability_score descending.
Save this as a pinned view in the Companies section and share it with the CS team as their daily triage list. Every morning, the view shows the highest-risk active customers in rank order. CSMs work down the list, creating notes after conversations and marking tasks complete as they go.
Combined with the automated task creation from Workflow 1, most CSMs will find that their daily HubSpot queue already reflects the model's recommendations - they are acting on AI outputs without having to think about it as a separate tool.
Pulling It Together
NoCodePredict handles the write-back automatically - no Python required. The churn scores update on your defined cadence, the HubSpot properties stay current, and the workflows fire from there. But if you have an existing model and want to wire it to HubSpot manually, the steps above work regardless of what built the model. The HubSpot API does not care whether predictions came from a custom AutoML pipeline, a data science team's notebook, or a no-code platform.
The core insight is the same either way: predictions that live in a spreadsheet save no one. Predictions embedded in the tool your CSMs open 40 times a day have a chance of actually changing behavior before the account goes dark.
How is your team currently surfacing at-risk accounts to CSMs today - and how long does it take from "the model flagged this" to "a CSM took action"?