Use case

How to build your own intent signals from public company data

A role opened, a technology added or removed, a funding filing, an announcement. How to turn dated company events into your own intent signal per account and topic, with queries, a worked example and a test against won deals.

Updated 27 October 202612 min read

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 eventWhat it recordsWhere to read it
A posting names a tool, or the role selects toolsAn intention to staff work on a tool, or to choose oneJob Postings: technologies, and the selects tools flag in labels
A new initiative, a team being built or a budget owner hiredA new line of work or a function being staffedJob Postings: the role flags in labels
A technology appears on the websiteAn adoption now liveTechnology Changes: category of technology, change of added
A technology leaves the website, or the platform is replacedA product taken off the site, or a migrationTechnology Changes: change of removed, or category of platform
A domain verification with a software vendorA product being set up on the domainTechnology Changes: category of dns
A new market, language, currency or appExpansion, or a new sales motionTechnology Changes: category of market, language, currency or app
A private capital raiseNew money raisedCompany Funding: filed_at and amount_sold
An announcement with an event typeThe company's statement of a raise, expansion, acquisition or leadership changeCompany 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.

SourceWhat it says about datesWhat to respect when you collect it
Job postingsJob 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 filingsA 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 changesThe 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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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 RoboticsDatasetAge in daysWeightFadePoints
A posting names a CRM tool in its titleJob Postings1030.8412.52
A CRM tool leaves the websiteTechnology Changes3020.5951.19
The domain is verified with a software vendorTechnology Changes4520.4590.92
A private capital raise is filedCompany Funding6010.3540.35
A language is added to the websiteTechnology Changes5No ruleNot counted0
An earlier posting names a CRM toolJob Postings1303Outside the window0

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.

  1. Freeze the rules, the weights and the half-life, and store the score of every target account each week.
  2. Choose a scoring week and an outcome, such as a won opportunity opened within 90 days of it.
  3. Split the accounts at a cut-off into a top band and the rest, and take the win rate of each.
  4. Compute lift: the top band's rate over the rate of all accounts.
  5. 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.
  6. 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

ChoiceA place to startWhat should move it
WindowAs long as your sales cycle, such as 90 daysA change in the length of your sales cycle
Half-lifeA third of the window, such as 40 daysThe test: lengthen it if older evidence converts as well as fresh
Weights and rules1 to 5 by event, three to five kinds of event per topicLift by kind of event in your won deals: a kind that never precedes a win comes out
Cut-offThe top tenth of accountsThe 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.