Business People Enrichment - Role Holders and Contacts
Pricing
$20.00 / 1,000 person founds
Business People Enrichment - Role Holders and Contacts
Find the owners, managers and other role holders inside an identified business, with the published evidence for each role and the professional contact details that are attributable to them. Not an employee directory.
Pricing
$20.00 / 1,000 person founds
Rating
0.0
(0)
Developer
Lead Proof
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Give it businesses you have already identified and the roles you care about. It finds the people who hold those roles, shows the published evidence for each role, and returns only the professional contact details a source attributes to that person.
Built for a list of businesses (from Google Maps, a supplier list, a CRM export) where you need to know who to talk to inside each one.
This is not an employee directory. It looks for the role holders you asked about. A business where nobody was found is not a business with no staff, and every row says which of the two it is.
What you get
- People in the roles you asked for - owner, executive, purchasing, operations and more - each with the title exactly as the business published it and the page that says so.
- Only attributable contacts. An email or phone is returned for a person only when the business
publishes it against that person. No guessed addresses: nothing like
first.last@domainis ever built and offered as found. - Business channels kept apart: main lines and function mailboxes (
info@,sales@) are listed as company contacts, never as somebody's direct line. - An explicit account of what was not seen: pages that could not be read, limits reached, sources not consulted. An empty result is never presented as proof that nobody holds a role.
- Ranking you can check: every person carries the comparisons that placed them. There is no opaque score.
- One output row per input business, in input order, so your export lines up with your list.
- Pay per person returned. Businesses where nobody was found are free from this Actor (see Pricing: the page reads are still billed by the reader it calls).
How to use it
- Put your businesses in
businesses. Each needs a website, or a name together with a city, region or country. - Choose
targetRoles, for example["owner", "executive", "purchasing"]. - Keep
maxPeoplePerBusinessat 5 or raise it (up to 25). - Set a maximum charge in the run options and
maxDependencyChargeUsdfor the pages and searches this Actor starts (see Pricing). - Run it on a few rows first, then read
people,candidatesandcoverage.gaps.
Input
{"businesses": [{"inputId": "acct-1", "name": "Example Accountants", "website": "https://accountants.example.co.uk/", "city": "Shrewsbury", "country": "GB"},{"inputId": "dist-1", "name": "Example Industrial Supply", "city": "Salt Lake City", "region": "UT", "country": "US"}],"targetRoles": ["owner", "executive", "purchasing"],"maxPeoplePerBusiness": 5,"renderMode": "http","maxDependencyChargeUsd": 0.5}
| Field | Meaning |
|---|---|
businesses | One object per business: inputId, name, website, city, region, country, mapsUrl, linkedinCompanyUrl. Up to 200 per run. |
targetRoles | Role families to look for. Empty means owner, founder, executive. |
maxPeoplePerBusiness | Default 5, up to 25. Supported people past the limit are listed as candidates. |
renderMode | http (default, cheapest), auto or browser. Use browser for sites whose team page is built by JavaScript. |
verifyEmails | Default off. On checks the direct addresses being returned for deliverability. |
includeFormer | Default off, so relationships a source describes as past are excluded. |
useLinkedIn | Not available in this release. Leave it off. |
maxDependencyChargeUsd | Ceiling, in dollars and cents, on what the page reads and searches this run starts may charge in total. |
Other limits you can lower: maxPagesPerBusiness (8), maxSearchesPerBusiness (3),
maxSecondsPerBusiness (180), and the same per run.
A row needs enough to identify a business. A website, a company profile URL, or a name
together with a place. A bare name is refused for that row before anything is fetched. With a
name and a place but no website, the official site is searched for; if several companies carry
that name, none is picked and the row returns them as businessCandidates with no people.
Roles it understands: owner, founder, executive, partner, purchasing,
operations, finance, marketing, sales, hr, it, clinical, advisor, and synonyms
such as procurement, buyer, supply chain, practice manager and leadership. A role name
it does not model is reported in coverage.unrecognizedRequestedRoles, not approximated.
Output
One row per input business. Main fields:
| Field | Meaning |
|---|---|
status | succeeded, partial (a limit, a timeout or an unreadable source cut it short), failed or skipped. |
outcome | Why people looks the way it does: people_found, no_supported_role_holder_published, sources_were_inaccessible, stopped_at_a_limit, business_not_identified or no_source_could_be_read. |
business | The resolved company, how sure the match is, and why. |
people[] | fullName, associations (published rawTitle, relationship type, current or former, evidence with URL and quote), contacts with attribution and deliverability, matchedRoles, rankingReasons. |
candidates[] | People found but not returned, each with the reason (a role you did not ask for, the per-business limit, a contested identity, another location). |
possibleDuplicateOf | On a person or candidate: other records with the same name and a compatible title that may be the same person. Nothing on the pages ties them together or tells them apart, so they are neither merged nor presented as different people. |
businessContacts[] | Company channels with no person attached. |
coverage | rolesFound, unresolvedRoles, limitsReached and gaps, each gap with a plain sentence saying what it means. |
billedPeople | How many person-found events this row was charged for. |
The run page offers the full JSON, an overview CSV, and a run summary with the dependency spend.
How people are chosen and ordered
- The business is resolved from what you supplied. The home page is read, then the pages it links to about its people: team, about, leadership, contact, locations.
- People come from structured data, from person cards and from plain text, in that order of support. Only for roles the site did not answer, a bounded search runs. A search snippet is never treated as evidence of employment.
- Every requested role gets one person before any role gets a second; spare places then follow
the order of your
targetRoles. - Inside a role: how directly the title names the role, then the strength of the evidence, then the seniority the title itself states (chief executive or owner, chair, other chief officers, vice presidents, directors, managers), then the name. Evidence always comes before seniority.
Seniority orders people and claims nothing more. A purchasing title is not purchase authority, and "Founder" is not read as owner or chief executive.
Contact scopes
| Scope | Meaning |
|---|---|
person_professional | The business published this address against that person, inside their own entry. A mailbox that merely looks built from their name is never this. |
branch | Published for one location. |
business_general | A function mailbox or a main line. |
unknown | Published, but not attributable: for example on a domain the business does not own. |
Attribution and deliverability are separate fields. A mailbox that accepts mail is not proof of who reads it.
Coverage gaps
| Gap | Means |
|---|---|
source_unreadable | A source was blocked, timed out or failed. Nobody being found in it is not evidence that nobody is in it. |
limit_reached | The run stopped at one of its limits before the sources were exhausted. |
people_withheld_by_charge_limit | People were found but not returned because the run's maximum charge did not cover them. They were not charged. |
page_needs_rendering | A page is built by JavaScript, so its people were not in what was read. Re-run that business with renderMode: "browser". |
page_empty_after_rendering | A page was read in a browser, finished loading and was still empty, typically a guessed address such as /team that the site does not have. |
no_page_about_the_people | The site was read and publishes no team or about page. |
names_found_without_published_titles | People were named with no title, so they are candidates, not role holders. |
no_official_site_identified | The company's own site was not found. |
search_coverage_reduced | The search returned less than was asked of it. |
profile_sources_not_used | No professional-profile source was consulted. |
coverage.absenceIsBounded is true when any gap could be hiding a role holder: on such a row,
an empty people list is not a statement that nobody holds the role.
For JavaScript sites prefer renderMode: "browser" over auto: auto has been seen reading such
a page over HTTP without switching to the browser.
Pricing
This Actor
$0.02 per person returned in people (event person-found). It is the only event this Actor
charges. Two records that may be the same person (flagged possible_duplicate) take one place and
are charged once.
Free from this Actor: candidates, company contacts, businesses where nobody was found, businesses that could not be identified, and rows that failed.
Your run's maximum charge is respected at every step:
- A business is not started unless the remaining maximum still covers at least one more person, so no page is read and no search is run for an answer that could not be returned.
- If a business has more people than the remaining maximum covers, the row returns only the people
that were charged (the first places filled, one per requested role first), stays in the dataset
as
partialwithcharge_limitincoverage.limitsReached, and says how many were withheld. Withheld people are not charged and not listed. The run stops after that row. - If a run is interrupted and resumed, a row is never charged twice. A row interrupted during the charge itself is returned without being charged.
Actors this Actor calls, billed to you separately
Pages and searches are read by other Actors that run on your account and bill you at their own Store prices, in addition to the $0.02 per person:
| Called Actor | When | Its price |
|---|---|---|
| Search & Read | Every page read and every search | $0.002 per page read over HTTP, $0.006 per page that needed a browser, $0.005 per search, plus $0.00005 per run start |
| Bulk Email Verifier | Only with verifyEmails: true | $0.0049 per address checked |
A business where nobody is found can still cost money. Its pages and searches are read and billed by Search & Read whether or not a role holder turns up. Only this Actor's $0.02 depends on people being found.
What bounds your cost
There is no typical cost to quote: it depends on how many pages each site has, whether they need
a browser, how many searches run, and how many people each business publishes. The limits give
hard ceilings instead, enforced in the code. Per business, the Actor never hands the reader more
than maxPagesPerBusiness pages or maxSearchesPerBusiness searches, each read is asked for once,
searches read no pages, and returned people never exceed maxPeoplePerBusiness. The reader
charges each page and each search at most once, including its own retries and restarts, and
nothing for a failed read. With the defaults, at today's prices:
| Per business | Upper bound |
|---|---|
| This Actor, 5 people x $0.02 | $0.10 |
| Search & Read over HTTP, 8 pages x $0.002 + 3 searches x $0.005 | $0.031 |
| Search & Read in browser mode, 8 pages x $0.006 + 3 searches x $0.005 | $0.063 |
| Run starts of the called Actors, at most one per page or search, 11 x $0.00005 | $0.00055 |
Email verification, when on, adds $0.0049 per address returned. Lower maxPagesPerBusiness,
maxSearchesPerBusiness or maxPeoplePerBusiness to lower these. Set maxDependencyChargeUsd to
cap what the called Actors may charge across the whole run; each is started with only what is left
of it. Your run's maximum charge caps this Actor's own events and does not cover the called
Actors. Start with a few rows and check the run summary.
What it will not tell you
- A decision maker for every business. Many companies publish nobody. That returns
no_supported_role_holder_published, with the gaps that bound it. - Who approves a purchase. A purchasing title names a function, not an approver.
- That an unknown recency is current. A person on a live staff page is
current; anywhere else recency staysunknown. - One person from two records by name alone. Two records merge only when something outside
the name, such as a personal mailbox or a profile address published for exactly them, ties them
together. Records whose own contacts differ are two people. The same name and title with nothing
either way is flagged
possible_duplicate: listed separately, one place, charged once. "Jane Q Smith" and "Jane Smith" follow the same rule. - A branch contact from a group page. If nothing ties a person to the location you asked
about,
branchRelevancestaysunknown.
Fair use
Only public pages are read, with no login and nothing bypassed. The output is professional information a business chose to publish about its own staff. You are responsible for how you contact the people in it and for following the privacy and marketing rules that apply to you, such as GDPR and CAN-SPAM.
Related
- Business Enrichment - company website, published emails and phones from a business name.
- Search & Read - the search and page reader this Actor uses.
- Bulk Email Verifier - deliverability checks.
- Verified local-business lead lists: leadproof.co.
Development
Python 3.13, Apify SDK 4.0.2. python3 -m unittest discover -s test from this folder. The
person and organization model is a shared library bundled at build time. The project records
(HANDOFF.md, DEPLOYMENT.md, STORE_LISTING.md) are in this folder and are not part of the
store page.