Lead triage: web form to HubSpot, scored on the way in

A working n8n workflow built against your brief. Ten sample submissions were put through it, scored by Claude against a four criteria rubric, written into a real HubSpot portal, and the hot ones announced in Slack. This page is the record of that run.

What ran

Not a mockup. An n8n instance, a published workflow on a live webhook, ten POSTs, and the results read back out of HubSpot afterwards.

3scored Hot, alert sent
1scored Warm
4scored Cold
1held for a human
1caught as duplicate

Every submission answered in about 3 seconds end to end. The duplicate and the malformed one answered in well under a second, because neither needs to call a model.

The ten submissions

The reason text below is what the model wrote at the time. It is stored on the contact record, so anyone looking at the lead later can see why it was scored that way.

RefWhoScoreWhyOutcome
SUB-1041 Dana Whitfield
North Harbor Outfitters
Hot Founder-led ecommerce replatforming with strong budget ($35-50K), clear timeline (September kickoff, holiday deadline), and in-scope work (migration, build, subscription integration). Written to HubSpot, Slack alert sent.
SUB-1042 Marcus Bell
Lattice Supply Co
Hot CEO of supply company with stated budget, hard deadline tied to trade show event, clear marketing site scope with CRM integration, and strong authority. Written to HubSpot, Slack alert sent.
SUB-1043 Priya Raman
Meridian Ops
Hot VP Marketing with approved budget in stated range, clear timeline within the month, in-scope marketing site rebuild project, and strong authority to decide. Written to HubSpot, Slack alert sent.
SUB-1044 Tom Ashby
Ashby Joinery
Cold In-scope fit but weak on budget (below minimum engagement), no timeline urgency, and while the owner has strong authority, only one of three commercial factors is strong. Written to HubSpot.
SUB-1045 Elena Kovac
Brightfold
Warm In-scope marketing site project with strong budget signal and middling authority, but timeline is vague and exploratory. Written to HubSpot.
SUB-1046 Jamie Ortiz
Cold Out of scope: student work with no budget and no commercial project. Written to HubSpot.
SUB-1047 Growth Partner Outreach
RankVelocity
Cold Out of scope: they are pitching their own SEO link services to us, not seeking our services for a project. Written to HubSpot.
SUB-1048 Chris Lam
Peakfield Consulting
Cold Out of scope: logo tweaks are not in our service offerings, and the prospect is an intern without budget authority. Written to HubSpot.
SUB-1049 (no name given)
Unnamed
review queue flagged Held for a human. Not scored.
SUB-1050 Priya Raman
Meridian Ops
duplicate The same person filling the form a second time, which is what actually happens when someone is not sure the first one went through. Identical content, different submission id. Recognised as SUB-1043 sent again. Nothing rewritten, no second alert.

The people and companies here are invented for this demo. The addresses use the reserved example.com domain, so nothing on this page belongs to anyone.

What happens to a submission

  1. The form posts to a webhook. Typeform, Google Forms or anything else that can send a POST. Nothing is polled and nothing is scheduled.
  2. The submission is checked and normalised. Fields are trimmed, the address is validated, and a fingerprint is taken of the answers that matter.
  3. HubSpot is asked whether this person is already there. If the same person has already been scored on the same answers, the run stops. No second write, no second alert.
  4. Claude scores it against the rubric. Temperature zero, and the rubric is passed in rather than baked into the workflow, so it can be edited without touching any wiring.
  5. The reply is checked before it is trusted. If it does not parse, or the score is not one of the three allowed values, the lead goes to the review queue rather than being written.
  6. The contact is created or updated in HubSpot. Score, reason, per criterion breakdown, rubric version and submission reference all land on the record.
  7. Hot leads raise a Slack notification. Everything else stops after the write.
The workflow open in n8n, showing all 20 nodes and both review paths

The workflow as it stands in n8n. 20 nodes, including both paths out to the review queue.

When a submission arrives broken

Your brief asked for documented handling of failed and malformed submissions. The rule here is that anything unscoreable is handed to a person, never guessed at and never silently dropped.

A form with no address and no description

Two of the four criteria cannot be assessed at all, so it is not sent to the model. This is the payload the review queue actually received during the run:

{
  "queue": "lead-review",
  "reason": "incomplete_submission",
  "detail": "no email address; no description of the work",
  "submission_id": "SUB-1049",
  "email": "",
  "received_at": "2026-07-28T12:40:27.321Z"
}

A model reply that cannot be read

If the reply does not parse, or carries a score outside Hot, Warm and Cold, the same review path is taken. It would have been easier to default those to Cold. That is exactly the wrong default, because Cold is where a mis-read hot lead would quietly go to die.

The same form sent twice

People resubmit when they are not sure the first one went through. The fingerprint of the answers is stored on the contact, so a repeat is recognised and ignored rather than overwriting a good score and firing a second alert. In the run above, SUB-1050 was SUB-1043 sent again, and it was caught.

The hot lead notification

Each of the three Hot leads raised a notification in Slack. This is the channel afterwards, not a mockup of one.

Two Hot lead notifications in a Slack channel, each showing name, company, email, budget and the reason it scored Hot

Posted through a Slack incoming webhook as a Block Kit message, so the fields stay readable on a phone. The submission reference and rubric version sit in the footer of each message, which means a notification can always be traced back to the record it came from.

The point of putting the reason in the notification is that a score on its own is not actionable. Whoever picks the lead up can see what the score was based on without opening the CRM, and can tell immediately when the model has read something the wrong way.

What landed in HubSpot

Read back from the portal through the API after the run, not captured on the way in. This is the first lead's contact record as HubSpot holds it.

{
  "email": "dana.whitfield [at] northharbor.example.com",
  "firstname": "Dana",
  "lastname": "Whitfield",
  "company": "North Harbor Outfitters",
  "jobtitle": "Founder",
  "lead_score": "Hot",
  "lead_score_reason": "Founder-led ecommerce replatforming with strong budget ($35-50K), clear timeline (September kickoff, holiday deadline), and in-scope work (migration, build, subscription integration).",
  "lead_score_criteria": "{\"budget\":\"strong\",\"timeline\":\"strong\",\"fit\":\"in_scope\",\"authority\":\"strong\"}",
  "lead_rubric_version": "v1.2",
  "lead_submission_id": "SUB-1041",
  "lead_scored_at": "2026-07-28T12:39:56.914Z"
}

Writes went to a HubSpot developer test portal. On your side the same nodes point at your portal through your own private app token, and the seven lead fields are created once.

Two things the run turned up

Both of these are the sort of thing worth knowing before a build rather than after, which is why the run happened first.

1. The same lead scores the same way every time

An automated score that moves when you re-run it is not worth having. Three submissions were scored five times each at temperature zero:

RefRunsScores returnedResult
SUB-10415Hot, Hot, Hot, Hot, Hotidentical every time
SUB-10445Cold, Cold, Cold, Cold, Coldidentical every time
SUB-10455Warm, Warm, Warm, Warm, Warmidentical every time

2. A gap in the rubric, found by running it

SUB-1044 is a small but real project from an owner with a stated budget. It came back Cold. The rubric said a budget below the minimum engagement is weak, but never said what the minimum was, so the model picked one:

In-scope fit but weak on budget (below minimum engagement), no timeline urgency, and while the owner has strong authority, only one of three commercial factors is strong.

Adding one sentence to the rubric moved it to Warm, where it belongs:

The minimum engagement is $5,000. Anything at or above that is not weak on budget.

In-scope fit with strong budget and authority, but timeline is weak and vague.

Nothing in the workflow changed. That is the point of keeping the rubric as a document the workflow reads rather than logic buried in a node: the criteria stay yours to edit.

The rubric

A stand in written for this demo, in the shape the real one would take. Yours would replace it.

Budget signal. A stated range at or above the minimum engagement, an existing vendor being replaced, or a funded project counts as strong.

Timeline. A named date or an event they are working backwards from is strong. Just exploring is weak. Silence is neutral, not weak.

Fit. The work is either the kind of work being sold or it is not. One off graphics, link packages, student work and inbound vendor pitches are not.

Authority. Founder, owner and VP are strong. Manager is middling. Intern or no stated role is weak.

Hot means strong on fit and at least two of the other three. Warm means in scope with one strong signal. Cold means out of scope, or in scope and weak everywhere else. Fit is the gate, so a vendor pitch quoting a large number is still a vendor pitch. That rule is why SUB-1047 scored Cold despite naming the largest budget of the ten.

What is real here and what is stood in for

The workflow itself

The export below is taken from the running instance after the run, so it is the same workflow that produced everything on this page. It carries no credentials.

Download the workflow JSON

Import it into any n8n instance. It expects two credentials, a HubSpot private app token and an API key for the model, and the seven lead fields on the contact record.