How to calculate sales engagement over the last 90 days?

Hi everyone!

I’m working on a Customer Health Score for a SaaS client and would love some input from other Solutions Partners on the best way to structure this in HubSpot.

The client has customers in the Grow project stage, with different engagement expectations depending on their tier (Tier 1, 2, or 3).

The health score needs to consider the number of sales activities completed within a specific timeframe, specifically:

  • 1:1 sales emails

  • Meetings logged

  • Calls logged

The timeframe varies depending on the customer’s tier. For example, we may need to evaluate engagement over the previous 90 days for one tier.

The challenge

HubSpot’s default Number of times contacted property doesn’t work for this because it represents the lifetime number of times a company has been contacted, rather than the number of activities within a specific period.

I’m considering creating a custom number property and using workflows to increment the value whenever one of these sales activities is logged.

However, I’m not sure this is the best architecture — especially because I also need to account for existing activity from the previous 90 days when implementing this for existing customers.

Has anyone built something similar?

I’d particularly love to hear how you would approach:

  1. Tracking the number of calls, meetings, and 1:1 emails within a rolling timeframe (e.g. the last 90 days).

  2. Backfilling the activity count for existing records when the solution is first implemented.

  3. Handling different engagement windows depending on the customer tier.

  4. Avoiding the count becoming inaccurate over time as activities fall outside of the timeframe.

  5. Whether you would recommend workflows + custom number properties, calculated properties, or another HubSpot-native approach.

I’m trying to keep this as native and maintainable in HubSpot as possible, rather than introducing an external tool just to calculate the engagement component.

Would really appreciate any approaches or examples from anyone who has implemented a similar health-score model. :folded_hands:

Lifetime “Number of times contacted” is the wrong primitive for this. It is lifetime, not rolling, and it will never give you tier-specific windows. Treat the health-score engagement component as a recalculated snapshot, not as a forever-incrementing counter.

Here is the architecture that usually stays maintainable in HubSpot:

  1. Decide the grain. Put the engagement score on the object you score (usually Company for SaaS “customer”). Define which activities count: logged calls, meetings, and 1:1 sales emails associated to that company (via contact or deal associations). Write the rules down so Sales cannot invent a second definition later.

  2. Avoid “increment on activity” as the long-term system. A workflow that +1 on each call/meeting/email is easy to start and hard to keep honest. When an activity ages out of the 90-day window you need a matching -1 (or a full recount). Miss one path and the number drifts. Use increment only as a temporary prototype, not as the production source of truth.

  3. Preferred native pattern: nightly (or hourly) recount into a custom number property.

    • Custom company properties, e.g. eng_calls_90d, eng_meetings_90d, eng_emails_90d, eng_total_90d, plus eng_window_days (or derive window from Tier).
    • A scheduled workflow / Operations Hub process (or a Custom Coded action if you have it) that, for each in-scope Grow customer, recounts associations in the last N days and overwrites the numbers. Overwrite beats increment for rolling windows.
    • If you lack coded actions, a practical fallback is a custom report / Data Hub dataset that already filters activities by date, then a lighter sync into the score property. The key is: recompute from source activities, do not trust a running total.
  4. Tier-specific windows. Store Tier on the company. Branch the recount: Tier 1 → 30 days, Tier 2 → 60, Tier 3 → 90 (or whatever the client defined). Persist eng_window_days next to the counts so the health formula can explain itself (“12 activities in a 90-day window”).

  5. Backfill for existing customers. On day one, run the same recount job across all Grow companies (manual enrollment / one-shot workflow / import of computed values). Do not try to reconstruct history by replaying old workflows. A full recount is the backfill.

  6. Keep the health score formula boring. Health Score = weighted function of (engagement counts vs tier target) + other signals. Store targets as properties too (eng_target_90d). Then a workflow or calculated property can mark Red/Yellow/Green without hiding the math.

  7. Ownership / accuracy ops. Document who owns the definition, which activity types are in/out (sequenced email vs 1:1, no-show meetings, etc.), and a monthly audit: pick 5 companies, compare property vs activity timeline. That is how you stop silent drift.

So: rolling engagement = recalculate from activities on a schedule, keyed by tier window, written onto company properties the health score reads. Skip lifetime contacted. Skip permanent +1 counters unless you also build the aging-out logic (usually not worth it).

If you share whether this is Company-level vs Contact-level scoring and whether you have Operations Hub / custom coded actions, the exact workflow shape gets obvious fast.

VK | AXIOPRAX

Hey @CarolinaDeMares :waving_hand: , it’s great to see you ask on the HubSpot Community, thank you!

And thanks @kishoreaxioprax for your contribution!

To start with, I’d like to share these resources that can help:

Now, let’s see what our Top Experts have to say: Hi @danmoyle and @UlianaV, do you have additional tips to share with @CarolinaDeMares, please?

Thanks so much and I hope that you’ll have an amazing day!

Bérangère

Good points above. I’d add that since calls and emails are usually logged on contacts, make sure the recount also pulls in activities from associated contacts, not just company-level ones. Also, storing a date-stamped property like “last recount date” makes it much easier to audit when the numbers start going stale.

Hi @CarolinaDeMares what a great use case. My first thought is, what about the HubSpot Customer Success Health Score? Is the client on Service Hub? The way I understand it, the native score builder can evaluate calls, meetings, and engagement events within a configured timeframe, require a frequency threshold, and automatically recalculates as events move in or out of the window. That directly avoids the main failure mode of increment-only number properties: they go up, but do not naturally decrement when an activity becomes older than 90 days.

I think you could build the score on the company or contact object, provided that’s where the customer’s Grow stage and tier live. And I bet you could create the health score to a customer segment like this:

  • Customer lifecycle/status = active customer
  • Project stage = Grow
  • Tier is known
  • Exclude closed, churned, paused, or implementation-only accounts as appropriate

Then create an Engagement event group in the Customer Success Health Score for:

  • Completed/logged calls
  • Logged or completed meetings
  • One-to-one sales emails

The Health Score tool supports event-based rules, configurable timeframes, and frequency conditions such as “at least X occurrences.” It also includes predefined groups for 1:1 Engagement and 1:1 Call Engagement, which may give you a useful starting point.

Of course if they don’t have this, then I think you’re right that you’d have to create custom properties and workflows to not only populate based on time, but also clear out after a time frame. My concern there would be that it’s an all or nothing, not depreciation like I think you’d want.

And in that case, I’d probably prompt Breeze to give me ideas on how it can work. Wish I had a better answer for that path.

Hi @CarolinaDeMares ,

I’ve built similar engagement-based scoring models, and I’d avoid using a simple “increment a number every time an activity happens” setup. It looks attractive at first, but the rolling window is where it starts getting messy.

For this, I’d keep the activity itself as the source of truth and let the health score look at activity within the relevant timeframe.

For example, if Tier 1 is based on the last 90 days, I’d use the activity/reporting data to determine how many qualifying calls, meetings, and 1:1 emails happened during that period, rather than maintaining a lifetime counter on the company. Then the health score can translate that engagement into the appropriate points.

The tier-specific requirement is another reason I’d avoid having one counter that simply increments. If Tier 1 uses 90 days, Tier 2 uses 60, and Tier 3 uses 30, you’d eventually need to decrement or reset the counter as activities age out. That’s where these workflows tend to become difficult to maintain and can drift from the actual CRM activity history.

For existing customers, I’d do a one-time historical backfill when implementing the model. Calculate the qualifying activity for the required lookback period, populate the initial health-score inputs, and then let the ongoing automation take over from there. I’d keep that initial backfill separate from the ongoing workflow rather than trying to recreate months of activity one event at a time.

One other thing I’d recommend is defining exactly what counts before building anything: for example, whether only completed meetings count, whether missed/cancelled meetings are excluded, what qualifies as a 1:1 email, and whether calls need to be logged as completed. Otherwise the score can become inconsistent pretty quickly.

If the portal has the required health-score/CRM functionality available, I’d lean toward using HubSpot’s native activity-based criteria/reporting where possible, with workflows only handling the pieces that genuinely need to be persisted as properties. I wouldn’t create separate increment/decrement workflows unless there’s a specific reason to store those numbers on the company.

So my architecture would be roughly:

Activity history → qualifying activity within tier’s lookback window → engagement component of health score → overall customer health.

That gives you a rolling calculation without having to constantly maintain a counter as old activities fall out of the window. The exact implementation does depend a bit on the HubSpot subscription and which health-score/reporting features are available in the portal, but I’d definitely start there before introducing an external tool.

You can do this in the custom report builder. Use Activities as the data source, filter activity date to last 90 days, then group by contact owner and activity type. That gives you calls, emails and meetings per rep. If you want it per deal, you can build it from the deals data source instead.