How to Score and Route New Leads from Gmail into Monday and Klaviyo
Build a Spojit workflow that watches a connected Gmail mailbox for inbound lead emails, scores each one from 0 to 100 with an Agent-mode Connector node, then routes hot leads to a Monday.com CRM board and adds them to a Klaviyo nurture list.
What This Integration Does
Inbound leads arrive as email all day: contact-form notifications, "request a quote" replies, demo signups. Triaging them by hand is slow and inconsistent, so good leads sit cold while someone reads their inbox. This workflow reads each new lead email, asks the agent to grade it against a short rubric, and splits the result into two paths: hot leads land on a Monday.com board as a CRM row your sales team can pick up immediately, and every qualified lead is enrolled in a Klaviyo nurture list so marketing keeps the relationship warm.
The workflow runs on an Email trigger that polls a Gmail mailbox on a fixed interval (read-only by default). Each new message that passes your From allowlist and Subject regex starts one run. A Connector node in Agent mode returns a structured score and tier through a Response Schema, a Condition node compares the score against your threshold, and a Parallel node fans the qualified lead out to Monday.com and Klaviyo at the same time. Runs are independent and stateless: re-polling never reprocesses a message already handled, and a failed run for one email does not block the next.
Prerequisites
- A Gmail (trigger) connection, added under Connections > Add connection > Gmail (trigger) via OAuth (read-only is enough for this workflow).
- A Monday.com connection (API token) and a board for leads. Note its
board_idand the column IDs you want to populate (for example a status column and a long-text column). - A Klaviyo connection (private API key) and an audience list for nurture. Note the
listIdof that list. - Optionally a Slack connection if you want a hot-lead ping in a sales channel.
- A rough scoring rubric in mind (what makes a lead hot versus nurture) so the agent prompt has something concrete to ground on.
Step 1: Poll Gmail with an Email trigger
Add the Trigger node and set its type to Email. Pick your Gmail (trigger) connection, choose the folder to watch (usually INBOX), and set a poll interval (1 to 60 minutes, default 2). To keep the workflow focused on real leads, set the optional Subject regex, for example (?i)(new lead|quote request|demo request|contact form), and add a From allowlist if your leads always come from one notifier address such as your web form. Leave after-processing off unless you want messages marked read, which requires a read-and-modify scope.
Each new message exposes fields you reference downstream with handlebars: {{ input.subject }}, {{ input.from }}, {{ input.textBody }}, and {{ input.receivedAt }}.
Step 2: Score the lead with a Connector node in Agent mode
Add a Connector node and switch it to Agent mode. Agent mode lets the agent read the raw email and reason about it instead of you mapping fixed fields. In the prompt, paste the lead and give it a short, explicit rubric so the score is grounded rather than guessed:
Score this inbound sales lead from 0 to 100 and assign a tier.
Subject: {{ input.subject }}
From: {{ input.from }}
Body:
{{ input.textBody }}
Rubric:
- Buying intent (asks for pricing, demo, timeline): up to 40 points
- Company fit (business email domain, named company, team size): up to 30 points
- Urgency (mentions a deadline, "ASAP", budget approved): up to 20 points
- Completeness (name, phone, real message vs. one line): up to 10 points
Tier rules: score >= 70 is "hot", 40 to 69 is "nurture", below 40 is "cold".
Extract the lead's name, email, and company if present.
Under the node's Response Schema, force structured JSON so the downstream nodes can rely on the shape:
{
"type": "object",
"properties": {
"score": { "type": "integer", "minimum": 0, "maximum": 100 },
"tier": { "type": "string", "enum": ["hot", "nurture", "cold"] },
"name": { "type": "string" },
"email": { "type": "string" },
"company": { "type": "string" },
"reason": { "type": "string" }
},
"required": ["score", "tier", "email"]
}
Set the node's output variable to lead. You can now read {{ lead.score }}, {{ lead.tier }}, {{ lead.email }}, and the rest in later steps.
Step 3: Split hot from nurture with a Condition node
Add a Condition node after the agent. Set the test to compare {{ lead.score }} against your hot threshold, for example {{ lead.score }} is greater than or equal to 70. You can also branch on {{ lead.tier }} equals hot if you prefer the tier label. The true branch is your hot-lead path (immediate CRM row plus nurture enrollment); the false branch handles nurture-only leads. Leads the agent scored as cold can be left to end the run with no further action.
Step 4: Fan out to Monday and Klaviyo with a Parallel node
On the Condition node's true branch, add a Parallel node so the CRM write and the marketing enrollment run concurrently instead of one waiting on the other. Create two branches: branch A writes the Monday.com CRM row, branch B handles the Klaviyo profile and list. Both run from the same lead data and neither blocks the other.
Step 5: Create the CRM row in Monday (branch A)
In branch A, add a Connector node on the Monday.com connector in Direct mode and select the create-item tool. Map the fields:
board_id: your leads board ID.item_name: the lead identity, for example{{ lead.name }} - {{ lead.company }}.column_values: a JSON string that fills your board columns by column ID. Use the score, tier, email, and the agent's reason.
{
"status": { "label": "{{ lead.tier }}" },
"numbers": "{{ lead.score }}",
"email": { "email": "{{ lead.email }}", "text": "{{ lead.email }}" },
"long_text": "{{ lead.reason }}"
}
Replace status, numbers, email, and long_text with the real column IDs from your board (use get-board once to read them). If you also want a sales ping, add a Slack Connector node in Direct mode using send-message to your sales channel with text like New hot lead: {{ lead.name }} ({{ lead.score }}/100).
Step 6: Enroll the lead in Klaviyo (branch B)
In branch B, add a Connector node on the Klaviyo connector in Direct mode and select create-profile. Map the profile attributes from the agent output:
{
"email": "{{ lead.email }}",
"first_name": "{{ lead.name }}",
"properties": {
"lead_score": "{{ lead.score }}",
"lead_tier": "{{ lead.tier }}",
"company": "{{ lead.company }}",
"source": "gmail-inbound"
}
}
Set this node's output variable to profile. Then add a second Klaviyo Connector node in Direct mode with add-profiles-to-list, mapping listId to your nurture list ID and profileIds to an array holding the new profile ID, for example ["{{ profile.id }}"]. This places the lead into the nurture list so your Klaviyo flow can begin emailing them. For nurture-only leads from the Condition node's false branch, repeat this create-profile then add-profiles-to-list pair (skipping the Monday row) so every qualified lead still gets nurtured.
Tips
- Keep the rubric in Step 2 short and concrete. A few weighted criteria with explicit point ceilings produce far more consistent scores than a vague "rate this lead" prompt.
- Use
{{ lead.tier }}from the Response Schema for routing labels and{{ lead.score }}for the numeric threshold. Having both lets you change the cutoff without re-prompting the agent. - If your board needs a date, format
{{ input.receivedAt }}with the date connector'sformattool before mapping it intocolumn_values. - Tighten the Subject regex over time. The narrower it is, the fewer non-lead emails reach the paid Agent-mode step, which lowers AI cost.
Common Pitfalls
- The Email trigger is read-only by default. If you turn on "mark read" or "move" after processing, the Gmail connection needs the read-and-modify scope or polling will fail.
- Monday's
column_valuesmust use real column IDs, not the human column titles shown on the board. Runget-boardonce to capture the IDs, or the values silently land in the wrong columns. add-profiles-to-listneeds the Klaviyo profile ID, not the email. Capture thecreate-profileresult in a variable first and pass{{ profile.id }}, otherwise the enrollment call has nothing to add.- Without a Response Schema, the agent may return prose instead of JSON and
{{ lead.score }}resolves empty, breaking the Condition test. Always set the schema in Agent mode here. - If a lead already exists in Klaviyo,
create-profilecan error on the duplicate. Choose Continue anyway on that node, or look the profile up first, so a returning lead does not fail the whole run.
Testing
Before enabling the trigger, validate on a tiny scope. Set the From allowlist to your own address, send yourself one test "lead" email that clearly should score hot and another that should score nurture, then watch the executions to confirm the agent returns a sensible score and tier, the Condition routes correctly, and one Monday row plus one Klaviyo enrollment appear. Point the test runs at a throwaway Monday group and a test Klaviyo list so you are not polluting real CRM and marketing data. Once the scores and routing look right, widen the allowlist and Subject regex and enable the workflow.