You can build intent signals of your own from dated company events. A role a company opens, a technology it adds or removes, a funding filing and an announcement each carry a date, and a score that weights them, fades them and adds them up per account and topic is a few queries long. This guide shows which events to count as a buying signal, how to date each one and how to test the result against the deals you won. The queries read four Fokals datasets: Job Postings, Technology Changes, Company Funding and Company News.
Fokals also delivers a ready-made weekly score in its intent dataset: Intent Scores gives a score from 0 to 100 for one company, topic and closed week, with a surge flag and the dated evidence behind it. This page is for the team that wants to define its own topics and scoring.
Which signals indicate a company is about to buy new software?
The signals that indicate a company is about to buy new software are dated actions that commit people or money: a role opened to select, implement or run a tool, a technology added to or removed from the website, a domain verified with a software vendor, a capital raise, and an announced expansion or leadership change.
The table sets each event beside what it records and where to read it. Every row of these datasets carries a stable company ID and a date, so the events of all four join on one key.
| Public event | What it records | Where to read it |
|---|---|---|
| A posting names a tool, or the role selects tools | An intention to staff work on a tool, or to choose one | Job Postings: technologies, and the selects tools flag in labels |
| A new initiative, a team being built or a budget owner hired | A new line of work or a function being staffed | Job Postings: the role flags in labels |
| A technology appears on the website | An adoption now live | Technology Changes: category of technology, change of added |
| A technology leaves the website, or the platform is replaced | A product taken off the site, or a migration | Technology Changes: change of removed, or category of platform |
| A domain verification with a software vendor | A product being set up on the domain | Technology Changes: category of dns |
| A new market, language, currency or app | Expansion, or a new sales motion | Technology Changes: category of market, language, currency or app |
| A private capital raise | New money raised | Company Funding: filed_at and amount_sold |
| An announcement with an event type | The company's statement of a raise, expansion, acquisition or leadership change | Company News: event_types and roles |
One event is thin evidence. Two or three of different kinds on one subject within weeks are what your score should reward, so the query below counts kinds as well as points. The guide to trigger events for outbound sales reads announcements by event type and role.
Implementation job postings, technology changes, procurement and RFPs as B2B software buying signals
A B2B software purchase can be read at three public points. A procurement notice or RFP states the requirement before a vendor is chosen. A job posting for an implementation or administration role records an intention to staff the project. A technology change on the website shows the new product in place, or the old one gone.
Procurement notices are often public where the buyer is a public body. In the United States, the Federal Acquisition Regulation has contracting officers publicise, with exceptions, a proposed contract action expected to exceed $25,000 by a synopsis in the governmentwide point of entry, which is reached at SAM.gov. In the European Union, tenders for public contracts that fall under EU rules must as a general rule be published on Tenders Electronic Daily.
For a company that buys privately, the score on this page reads the two later points from Fokals datasets. Each record of Job Postings carries ten role flags, among them selects tools, new initiative, replaces vendor and budget owner, and lists the tools the posting names. Technology Changes dates every technology added to or removed from the website.
Hiring activity and technology changes as B2B buying signals for sales
Hiring activity and technology changes work as B2B buying signals for sales because both are dated acts of the company. A posting records an intention to hire and can name the tools the role will use. A technology change records what a website started or stopped running. Together they give a seller a subject and a date.
- A posting records an intention to hire. A role built around a tool says more than a tool named in passing, so read the title as well as the tools listed.
- A technology change shows what the website runs. A removed tool has left the site, which can mean a cancelled contract or a moved tag. The guide to competitor displacement tells a swap from a flicker.
- A first observation is a baseline. The stack already running and the roles already open when a company is first observed are its starting state. In Fokals datasets a first observation sets a baseline and is never counted as a change, and a feed you collect yourself needs the same rule.
- Volume needs a denominator. Three roles naming a tool mean more among five open roles than among five hundred. Hiring Activity gives open, new and closed postings per company and day.
For sales, the subject of a signal chooses the team to approach and its date sets the urgency. Timing outreach with hiring signals turns single postings into plays.
DIY B2B intent data sources: job postings, SEC filings and website changes
The sources for DIY B2B intent data are public and first-party: job postings on a company's careers page or board, SEC filings such as Form D and Form 8-K, and changes to the company's website and DNS records. Reading them is the small part. The work is collecting each source on a schedule and dating every change.
| Source | What it says about dates | What to respect when you collect it |
|---|---|---|
| Job postings | Job posting markup has a datePosted property, defined by schema.org as the publication date of the listing. Google's guidelines require the property and say a job no longer open must be expired, by a validThrough date in the past or by removing the page or its markup. | Where a posting states no date, the dates you saw it are all you have: record first seen and last seen. |
| SEC filings | A company that has sold securities under Rule 504 or 506 of Regulation D must file a Form D notice within 15 days after the first sale, so a notice filed on time trails the first sale by up to 15 days, longer when the due date falls on a weekend or holiday. A reporting company files current reports on Form 8-K for certain specified events, often within four business days. | EDGAR is free to read, and its data APIs need no key. The SEC asks for a declared user agent and caps requests at 10 a second. |
| Website and DNS changes | The source states no date. A change exists only between two of your own readings and is dated by the later one. | The Robots Exclusion Protocol, RFC 9309, specifies the rules in /robots.txt that crawlers are requested to honour. |
DNS records show a vendor being set up. Google Search Console lets a site owner prove ownership by adding a TXT or CNAME record at the domain provider, and Microsoft 365 email requires an MX record, which specifies where the domain's email should go.
A home build adds three things: entity resolution, which ties a careers board, a filer and a domain to one company; a stored copy of every reading; and a baseline rule for the first one. Building crawlers vs licensing company data weighs that work.
Fokals datasets deliver such events dated and tied to one stable company ID, refreshed daily. The steps below run on them and apply unchanged to events you collect yourself.
How to build an intent signal from public company data, step by step
To build an intent signal from public company data, take every dated event for an account inside a window you choose, keep the events that match a topic you define, multiply each by a weight you set, fade it by its age and add the results per account and topic. Five choices define your score.
- Topics. Write each topic of yours as rules: an event read from one of the four datasets, and the weight it carries for the topic. A CRM topic might take postings that name a CRM tool, a CRM tool added to or removed from the website, and a raise.
- Dates. Use the event's own date: the first-seen date of a posting, the filing date of a raise, the date of an announcement, and the observation time of a website change.
- Weights. Give each event a weight, its strength before fading. A scale of 1 to 5 is enough: the top for an event that commits money or people to your subject, the bottom for context.
- Fade. Choose a half-life in days and multiply each weight by 0.5 ^ (age in days / half-life). Start with a window as long as your sales cycle and a half-life a third of it: 40 days over 120 for a cycle of four months.
- Sum. Add the faded weights per account and topic, and keep the number of signals and of distinct kinds beside the sum.
The rules are a table of your own with one row per topic and event, so an event is counted once per topic.
create table my_rules (
my_topic text, -- your name for the topic
event_key text, -- an event, as the query below names it
weight numeric, -- its strength before fading
primary key (my_topic, event_key)
);The query first puts the events of the four datasets into one list, each with a company ID, a date and a key, then scores every account and topic as of a time you set. It assumes Postgres, with technologies, labels and event_types loaded as jsonb.
with params as (
select cast(:as_of as timestamptz) as as_of,
cast(:window_days as int) as window_days,
cast(:half_life_days as numeric) as half_life_days
),
events as (
-- a technology or a DNS record added or removed, such as 'removed:salesforce'
select company_id, observed_at as at, change || ':' || key as event_key
from company_tech_events
where category in ('technology', 'dns')
union all
-- a role that names a tool, such as 'names:hubspot'
select p.company_id, p.first_seen_at, 'names:' || t.tool
from job_postings p
cross join lateral jsonb_array_elements_text(p.technologies) as t(tool)
where not p.found_on_first_read
union all
-- a role flag set on the posting, such as 'flag:selects_tools'
select p.company_id, p.first_seen_at, 'flag:' || f.key
from job_postings p
cross join lateral jsonb_each_text(p.labels) as f(key, value)
where f.value = 'true'
and not p.found_on_first_read
union all
-- a private capital raise
select company_id, cast(filed_at as timestamptz), 'raise'
from company_funding
where company_id is not null
union all
-- an announcement by event type, such as 'news:funding_round'
select n.company_id, n.at, 'news:' || e.value
from company_news n
cross join lateral jsonb_array_elements_text(n.event_types) as e(value)
),
matched as (
select e.company_id,
r.my_topic,
split_part(e.event_key, ':', 1) as kind,
e.at,
r.weight as w,
extract(epoch from p.as_of - e.at) / 86400.0 as age_days,
p.half_life_days
from events e
cross join params p
join my_rules r on r.event_key = e.event_key
where e.at <= p.as_of
and e.at > p.as_of - p.window_days * interval '1 day'
)
select company_id,
my_topic,
round(sum(w * power(0.5, age_days / half_life_days))::numeric, 2) as raw_score,
count(*) as signals,
count(distinct kind) as kinds,
max(at) as latest
from matched
group by company_id, my_topic
order by raw_score desc;- Duplicates. One posting can match several rules: a tool it names and a flag it carries. To count it once, keep the match with the highest weight per account, topic, dataset and day before you sum. A raise can arrive as a filing and as an announcement: count it once.
- Storage. Run the query when each week closes and append the result to a table that is never rewritten. An event dated by the act itself can arrive after that date, so a score recomputed later for a past week can hold evidence nobody had then, which is look-ahead bias.
- Scale. For a bounded number, map the raw sum with a curve that flattens, such as 100 × (1 − 0.5 ^ (raw / k)), where k is the raw sum to read as 50. To flag a change, compare this week's stored sum with the account's own average over earlier weeks.
A worked example: Acme Robotics on one topic
The example is illustrative. Acme Robotics is an invented company, and every weight, age and result below is invented.
Assumptions:
- You sell CRM implementation, and your topic is a CRM replacement project.
- The score is taken at the end of a week, over a 120-day window, with a half-life of 40 days.
- Your rules give 3 to a posting that names a CRM tool, 2 to a CRM tool removed from the website, 2 to a domain verification with a software vendor and 1 to a private capital raise.
- Points are the weight × 0.5 ^ (age in days / 40).
| Event at Acme Robotics | Dataset | Age in days | Weight | Fade | Points |
|---|---|---|---|---|---|
| A posting names a CRM tool in its title | Job Postings | 10 | 3 | 0.841 | 2.52 |
| A CRM tool leaves the website | Technology Changes | 30 | 2 | 0.595 | 1.19 |
| The domain is verified with a software vendor | Technology Changes | 45 | 2 | 0.459 | 0.92 |
| A private capital raise is filed | Company Funding | 60 | 1 | 0.354 | 0.35 |
| A language is added to the website | Technology Changes | 5 | No rule | Not counted | 0 |
| An earlier posting names a CRM tool | Job Postings | 130 | 3 | Outside the window | 0 |
Acme's raw score is 2.52 + 1.19 + 0.92 + 0.35 = 4.98, from four signals of four kinds. The posting supplies 51% of it. On a scale where a raw sum of 4 reads as 50, the score is 100 × (1 − 0.5 ^ (4.98 / 4)) = 58.
With a half-life of 14 days the same four signals give 1.83 + 0.45 + 0.22 + 0.05 = 2.55, and the posting supplies 72% of it. A short half-life ranks by recency and a long one by accumulated activity. The test below settles which your market needs.
Test the signal against won deals
Test the score on values stored before the outcome was known. The question is whether accounts that scored high went on to buy more often than the rest.
- Freeze the rules, the weights and the half-life, and store the score of every target account each week.
- Choose a scoring week and an outcome, such as a won opportunity opened within 90 days of it.
- Split the accounts at a cut-off into a top band and the rest, and take the win rate of each.
- Compute lift: the top band's rate over the rate of all accounts.
- Check the gap against chance with the statistic for two proportions in the NIST handbook: z = (p1 − p2) / √(p × (1 − p) × (1/n1 + 1/n2)), where p is the rate of both groups pooled. With reasonably large samples, compare the size of z with the normal table value for your significance level: for a two-sided test at 5%, 1.960 at the 0.975 point.
- Change one choice, such as the half-life, and repeat on a later period you kept aside.
-- target_accounts, my_scores and my_wins are tables of your own.
with params as (
select cast(:week_end as timestamptz) as week_end,
cast(:outcome_days as int) as outcome_days
)
select coalesce(s.raw_score, 0) >= :cut_off as top_band,
count(*) as accounts,
count(w.company_id) as won,
round(count(w.company_id)::numeric / count(*), 3) as win_rate
from target_accounts a
cross join params p
left join my_scores s
on s.company_id = a.company_id
and s.my_topic = :my_topic
and s.week_end = p.week_end
left join lateral (
select o.company_id
from my_wins o
where o.company_id = a.company_id
and o.opened_at > p.week_end
and o.opened_at <= p.week_end + p.outcome_days * interval '1 day'
limit 1
) w on true
group by 1;Example: the test on illustrative figures
Assumptions: 400 target accounts were scored in one week, the cut-off puts 80 of them in the top band, an outcome is a won opportunity opened within 90 days, and 20 of the top band and 32 of the other 320 reached it. Every figure is invented.
- Top band: 20 / 80 = 25%. The rest: 32 / 320 = 10%. All accounts: 52 / 400 = 13%.
- Lift of the top band: 25% / 13% = 1.92.
- z = (0.25 − 0.10) / √(0.13 × 0.87 × (1/80 + 1/320)) = 0.15 / 0.0420 = 3.57, above 1.960.
On these figures the top band wins more often than chance explains. Had z stayed under 1.960, the next step would be more weeks of data, not new weights.
The choices, and what moves each one
| Choice | A place to start | What should move it |
|---|---|---|
| Window | As long as your sales cycle, such as 90 days | A change in the length of your sales cycle |
| Half-life | A third of the window, such as 40 days | The test: lengthen it if older evidence converts as well as fresh |
| Weights and rules | 1 to 5 by event, three to five kinds of event per topic | Lift by kind of event in your won deals: a kind that never precedes a win comes out |
| Cut-off | The top tenth of accounts | The number of accounts your team can work in a week |
Fit comes first: rank only the accounts that match your ideal customer profile. Where a Fokals topic already describes what you sell, prioritising accounts with intent scores puts the ready-made weekly score to work. The data dictionary defines every field used here.
Frequently asked questions
Are hiring signals and technographic signals alternatives to intent data?
Yes. Like third-party intent data, they rank accounts by evidence of a coming purchase. The source differs, as company signals vs third-party intent data sets out. Bombora describes intent data as showing when buyers research topics across the internet, based on the content they consume. Hiring and technographic signals come from what the company publishes, each dated and checkable.
Can you build B2B intent data from free public sources?
Yes. Job postings, regulatory filings and company websites are public. The cost is in the engineering: reading every source on a schedule, storing each reading so that a change can be dated, tying a careers board, a filer and a domain to one company, and mapping tools and titles to topics. Licensed datasets of dated company events replace the collection and leave the scoring to you.
What half-life should a home-built intent signal use?
Start with a window as long as your sales cycle and a half-life a third of it, such as 40 days over 120, then let your outcomes decide. Score the same accounts with a shorter and a longer half-life, and keep the one whose top band wins more often on a period you held back. A long sales cycle is a reason to test a longer half-life first.
How many buying signals should an account show before sales acts?
Set the bar from your own test, and start with two signals of different kinds on one topic inside the window. One signal can be noise: a tag that moved, a role posted again. A posting that names a tool and a change in the stack on the same subject can be separate traces of one decision, and a score that counts distinct kinds rewards exactly that.
What is the difference between a buying signal and an intent score?
A buying signal is one dated event, such as a role opened or a tool removed. An intent score is a summary per account and topic: the one built on this page adds up the signals of a window, each weighted and faded by age. Fokals Intent Scores deliver a ready-made score per company, topic and closed week, with the dated evidence behind it. The signal is the evidence a rep quotes, and the score is how a long list of signals becomes a ranked list.
How do you test an intent signal against closed-won deals?
Store scores weekly, before outcomes are known. Then split accounts at a cut-off, compare the share of each band that went on to a won deal, and compute lift against the rate for all accounts. A two-proportion z statistic says whether the gap is larger than chance. Use the score stored for the week before each opportunity opened, never one recomputed afterwards.
The queries and code on this page are examples to adapt. Test them in your own environment before you rely on them.
What this page says about the products it names was checked against their public documentation on 7 October 2026. Product and company names are trademarks of their owners. Fokals is not affiliated with them or endorsed by them.