Detect intent signals
Hiring, funding, technology and job changes.

A signal is a dated change at an account that makes your offer more relevant this month than it was last month. Four families cover most B2B needs: hiring, funding, technology and job changes. Collect only the ones you can tie to a specific buying reason, store each one as a dated event, and let its value expire.
By this stage your accounts carry a fit score from the scoring chapter. Fit says who could buy, and signals decide who moves to the top of this week’s queue. Throughout this chapter, say you sell payroll software to French SMEs with 20 to 249 employees. The points, durations and volumes below are illustrative.
Write the buying reason before you collect anything
Each signal needs a sentence that starts with “because”. If you can’t finish the sentence, you are collecting noise with a date on it.
| Signal | Because | Where it shows | Usable for (starting guess) |
|---|---|---|---|
| Job ad for a payroll or HR administrator | Payroll workload is growing, or the person running it is leaving | LinkedIn Jobs, job boards, careers page | 45 days |
| New HR director or CFO | New owners review their tools in their first months | LinkedIn, press | 90 days |
| Funding round | Hiring follows, and payslip volume with it | Press, company news | 120 days |
| Headcount moving up a band | More payslips and more complexity than the current setup was chosen for | Registry bands, LinkedIn staff count | 90 days |
| Past customer or champion changes company | Someone who knows your product now sits in a new account | Your CRM contacts, re-enriched | 90 days |
| HR or accounting tool added or dropped | An integration need, or a replacement project under way | Website detection, job ads naming the tool | 60 days |
Those durations are where I would start. After one quarter, your own reply data replaces them.
How to collect each family
Hiring
Job ads tend to be the most useful signal because the title tells you which team is getting budget.
Derrick does this step with Company Hiring Signal (I co-founded Derrick, so read this with that in mind). You give it a column of LinkedIn company URLs and can narrow by country, posting date or keywords, here “paie” and “RH” with a recent posting date. It writes back isHiring, openPositions, topJobTitles and jobsUrl, for 1 credit per company checked, from the web app, Google Sheets, the API or an MCP client.
It has two limits worth knowing. It reads LinkedIn Jobs, so an SME that only publishes on its own careers page or a regional job board looks like it isn’t hiring. And openPositions shows “10+” once the first page is full, so it can’t size a large recruitment drive. Without a tool, open LinkedIn Jobs by hand for your top accounts, or keep saved keyword searches on job boards and match the company names against your table.
Funding
Announcements surface in the press and in company news. In Derrick, Google News Scraper takes a column of company names and a lookback from 24 hours to 12 months. It returns the most relevant recent article for each company (title, url, publisher, published), at 1 credit per news found. To sort the headlines, run Ask Claude on the title column, 2 credits per row, with a closed list of answers:
Headline: {title}
Answer with one word from this list:
funding, acquisition, new_executive, expansion, layoffs, other.
One article per company means a funding story can lose to a louder headline, and many small rounds never reach the press at all. The manual route is alerts on your Tier A company names plus a weekly read of the trade press in your sector.
Technology
Website Technologies takes a column of URLs and returns cms, technologies and urlStatus, for 2 credits per call. Any detector of this kind only sees what the public site loads: CMS, analytics, chat and marketing tags.
For our payroll example that is close to useless, since payroll software leaves no trace on a homepage. Job ads asking for experience on a named payroll suite will tell you more. Use website detection when your product sits next to something the site loads.
One run gives you a state, and the signal is the change between two runs. Keep dated snapshots and compare them:
SELECT cur.account_domain, cur.technology AS added, cur.seen_at
FROM tech_snapshots cur
LEFT JOIN tech_snapshots prev
ON prev.account_domain = cur.account_domain
AND prev.technology = cur.technology
AND prev.run_id = 41
WHERE cur.run_id = 42
AND prev.technology IS NULL;
Job changes
If you have past customers or champions, this is the signal I would set up first, because the person already knows what your product does.
Signal watches a list of leads or accounts daily in the background and alerts you on the types you toggle on, such as job change, funding round or tech-stack move. It costs 1 credit per signal triggered, needs a paid plan and runs from Google Sheets today. It only watches what you put in, so it won’t find accounts missing from your list. The manual version: every month, re-run Enrich Leads (1 credit per profile) on your champions, or check them by hand, and compare the current company with the one you stored. That list holds personal data, so it falls under the rules in the maintenance chapter.
Set a cadence by tier
Periodic checks cost money every time, so spend them where a reply is worth the most. With 300 Tier A accounts checked weekly and 900 Tier B accounts checked monthly, the hiring check comes to about 2,100 credits a month (300 × 4 + 900). Tier C waits until it moves up.
Store signals as events, one row each
Keep signals in their own table. Writing “hiring: yes” on the account row erases the date, and the date is what gives a signal its value.
| Column | Example | Note |
|---|---|---|
signal_id |
18342 | Unique |
account_domain |
example-pme.fr | Same key as the accounts table |
signal_type |
hiring_payroll | From a closed list |
signal_value |
Gestionnaire de paie | The raw evidence, reused in the message |
source |
linkedin_jobs | Where it came from |
event_date |
2026-10-28 | When it happened, or your best estimate |
detected_at |
2026-11-02 | When you saw it |
used_in_campaign |
outbound_q4_b | Blank until someone acts on it |
Score signals with an expiry date
Fit acts as the gate and the signal sets the order inside it. A signal on an account outside your fit tiers stays in the table and gets no action.
signal_type |
points |
useful_days |
|---|---|---|
| champion_moved | 40 | 90 |
| hiring_payroll | 30 | 45 |
| new_executive | 25 | 90 |
| headcount_band_up | 20 | 90 |
| funding | 20 | 120 |
| tech_change | 15 | 60 |
The value decays in a straight line until it reaches zero. In a sheet, with points in C, the event date in D and useful days in E:
=MAX(0, C2 * (1 - (TODAY() - D2) / E2))
In a database, per account:
SELECT s.account_domain,
ROUND(SUM(r.points * (1 - (CURRENT_DATE - s.event_date)::numeric / r.useful_days))) AS signal_score
FROM signals s
JOIN signal_rules r USING (signal_type)
WHERE CURRENT_DATE - s.event_date < r.useful_days
GROUP BY s.account_domain
ORDER BY signal_score DESC;
The output is a ranked list per tier, refreshed weekly. Each rep starts the week from the top of it, with the signal_value ready to quote in the first line of the message. The outbound chapter covers how to build those sequences.
Test each signal against your own replies
A signal earns its points when accounts showing it answer more often than similar accounts without it. Take one tier, send the same offer to both groups in the same period, and compare positive replies.
| Signal | Accounts with | Positive replies | Accounts without | Positive replies | Decision |
|---|---|---|---|---|---|
| hiring_payroll | |||||
| funding | |||||
| champion_moved |
Wait for at least a hundred accounts per group, because below that you are mostly reading chance. Raise the points on what clearly beats its control group, cut what doesn’t, and shorten the useful days when old signals stop getting answers.
Your next step: write the “because” sentence for each signal you are considering, keep the three you can defend, and run one on your Tier A accounts this week. Log every result as a dated row, then move on to sizing the market.