Growth & Marketing AI

A Dynamic ICP Model That Catches Its Own Drift

Result:

A live ICP model that re-weights each segment against real conversion and revenue data, catching drift like a dip in SME-segment conversion early enough to redirect spend and content before it shows up in the topline number.

Show page metadata
Target question
How do you build an ICP model that catches its own drift instead of going stale?
Answer summary
A dynamic ICP model treats an ideal customer profile as data with a feedback loop instead of a static CRM tag: store the authored hypothesis as a row, score every account against it continuously, blend that score with a weighted moving average of live conversion and revenue data so recent performance outweighs the original assumption, and rank emergent segments independent of the authored tiers to catch when a label disagrees with reality. Built in Postgres with pg_cron refreshing the scores hourly and daily, it caught a real dip in SME-segment conversion early enough to redirect spend before the quarter went soft.
Authority level
primary
Audience
practitioner, hiring-manager, bot
Topics
ICP modeling, weighted moving average, Postgres materialized views, pg_cron, segment drift detection

The same fields sitting in this page's target-question, answer-summary,authority-level, and audience meta tags and its JSON-LD — bot-facing metadata, made human-visible.

Problem

Most ICP definitions are authored once and trusted forever. Someone writes down “tier 1 = mid-market, 200–2000 employees, EMEA” (HubSpot even ships a field for it, hs_ideal_customer_profile), and that tag drives targeting, content, and spend for the next year regardless of whether accounts matching it actually convert or pay. An ICP is a hypothesis, not a fact. Nothing in a typical CRM checks it against outcomes, so drift is invisible until a quarter’s pipeline comes in soft and nobody can say which segment caused it.

Pattern

Treat the ICP as data with a feedback loop:

  1. Store the hypothesis as a row. An icp table holds the authored criteria (segment, size band, industry, region) as structured, queryable data.
  2. Score every account against it. A derived view scores each account 0–1 against each ICP’s criteria, turning “does this account fit tier 1” into a number that recalculates continuously as behavior changes.
  3. Blend the score with what’s actually happening. A weighted moving average pulls in live conversion and revenue data for the accounts matching each ICP, so recent performance counts for more than the original assumption. A segment that converted well a year ago but is slipping now gets re-weighted down even as its label stays the same.
  4. Surface the gap between the score and reality. For each authored ICP, show percent converting, percent generating revenue, and revenue itself, refreshed on a schedule (funnel-sensitive numbers hourly, revenue daily) so the “actual” side never goes stale.
  5. Rank the emergent segments too, independent of what was authored. The same conversion and revenue data, cut without regard to ICP tier, surfaces whichever accounts are winning right now, even ones nobody tagged as tier 1. When that ranking disagrees with the authored tiers, the definition is wrong and should move.

This is also why the model couldn’t live as a HubSpot workflow: hs_ideal_customer_profile is a static text field with no path back to conversion or revenue. Building it properly meant making ICP fitment a first-class part of the CRM’s own data model, one of the reasons the CRM itself got replaced with a homegrown, event-sourced system built for that requirement.

Data requirements

Before the pattern above produces anything real, three tables (or equivalent warehouse views) need to already exist and be populated:

  • Accounts: one row per company, with the firmographic fields the ICP hypothesis gets scored against (employee count, industry, region).
  • Conversion events: timestamped, tied to an account, at whatever stage the weighting cares about (opportunity created, closed-won, trial started).
  • Revenue: timestamped and tied to an account, not a lifetime total. The weighting needs freshness, so this has to be a series over time, not a single running number.

If any of the three lives in a system that isn’t queryable alongside the others, the join is the real blocker. Land the missing table before touching the scoring logic.

Example prompts

Feed these to Claude Code once the tables above exist, one per step of the pattern:

  1. “Write a Postgres migration for an icp table storing authored ICP hypotheses: segment name, size band (min/max employees), industry, region, one row per tier.”
  2. “Write a view icp_fit_score that joins accounts to icp and scores each account 0–1 against every ICP row’s criteria.”
  3. “Add a materialized view that blends icp_fit_score with a weighted moving average of conversion_events and revenue per account, weighting the last N days more heavily than older data.”
  4. “Set up two pg_cron jobs against that materialized view: hourly for the conversion numbers, daily for revenue.”
  5. “Write a query that ranks accounts by conversion and revenue alone, no ICP tier, and diffs it against the authored tiers to surface accounts winning without being tagged tier 1.”

Swap in your own table and column names. The shape of each prompt carries over even when the schema underneath doesn’t.

Real result

Blending each segment’s authored assumptions with live conversion and revenue data catches drift while it’s happening. That’s what caught a real dip in SME-segment conversion early enough to redirect spend and content toward the segments actually converting. Run the same loop against your own tiers and a segment quietly underperforming its label surfaces within weeks, in time to act before the quarter closes.

Variations

  • The match threshold for “does this account count toward this ICP’s score” is a tuning knob: tighter thresholds cut false positives but shrink the sample the scorecard is built on.
  • Swap in whatever conversion and revenue tables your own CRM already has: this is a re-weighting loop that works on top of any CRM, including HubSpot’s own objects, just without the ability to make the ICP field itself derived.
  • The same shape catches churn early: filter the scorecard to one segment and alert on week-over-week conversion drop, weeks before a quarterly review would surface it.

Nathaniel Stich writes Exit Velocities — recipes drawn from AI/growth systems actually shipped in production, not opinion pieces.

About the author