# Team Page People Extractor Executives Names Titles Clay (`mambalabs/team-page-people-extractor`) Actor

Company domain in, the executives and staff published on that company's own team, leadership or about page out. Returns names, titles, and page URL, with the pages actually reached so you can tell a real absence from an unreadable site. No LinkedIn scraping.

- **URL**: https://apify.com/mambalabs/team-page-people-extractor.md
- **Developed by:** [Mamba Labs](https://apify.com/mambalabs) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.10 / 1,000 person founds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### 🔎 What can Team Page People Extractor do?

Give it a **company domain** and it returns **the people that company publishes about itself**
on its own team, leadership or about page: names, job titles, and the exact page each one came
from.

No profile network, no aggregator, no login, no third party database. Every row traces back to
a page the employer published.

| 📦 What you get | ⚙️ Features and integrations |
|---|---|
| 👥 **Names and published job titles**, exactly as written<br>🪜 **Normalized seniority and department** for filtering<br>🔗 **`source_url` on every row**, so any name is checkable<br>🧾 **31 flat fields**, `snake_case`, two output grains | 🌐 **Eleven team and leadership paths** probed at once<br>🧬 **Structured data path** as supporting evidence<br>🧊 **14 day cache**, with a `skipCache` override<br>⬇️ **Export** to JSON, CSV, Excel, HTML or XML |

Bought by outbound teams building contact lists from first-party sources, and by recruiters and
researchers who need an auditable trail back to the company's own page.

> 🚫 **This is not a contact database and it does not find email addresses.** It reads what a
> company publishes about its own staff. No email is ever attached to a named person, and no
> `first.last@domain` pattern is ever guessed. If you need a person level work email, use
> [Work Email Waterfall Finder](https://apify.com/mambalabs/email-waterfall-orchestrator).

### 💡 Why use Team Page People Extractor?

| If you need | Read these fields |
|---|---|
| A named executive to open with | `full_name`, `job_title`, `seniority` |
| Proof the person is really there | `source_url`, `affiliation_confidence` |
| To route by function | `department`, `seniority` |
| One row per company instead of per person | `people_json`, `person_1_name` through `person_5_title` |
| To tell "nobody there" from "could not read" | `company_people_count`, `fetch_status` |
| A dedupe key across runs | `person_key` |

#### 🧭 A dedicated team page beats a general about page, and the row says which you got

Dedicated team and leadership pages are preferred. A general about page is read only when no
dedicated page produced anybody, and everyone found on one is labeled `medium` confidence.

That distinction is load-bearing. In the build sample, one large company's about page returned
two real people with real titles who are almost certainly not its employees. `affiliation_confidence`
is how you keep them out of a sequence.

Pages that come back identical are collapsed before extraction. One company in the test set
served the same leadership page at three different paths, which is why `pages_reached` and
`pages_distinct` are separate fields.

### 📋 What data can Team Page People Extractor extract?

**31 fields** across the two grains. The ones buyers use:

| Field | What it holds |
|---|---|
| `full_name`, `first_name`, `last_name` | The published name, split |
| `job_title` | The title exactly as published, never rewritten |
| `seniority` | Fixed ladder: `founder`, `c_level`, `vp`, `director`, `head`, `manager`, `other` |
| `department` | Normalized function, read from the published title only |
| `source_url`, `source_path` | The page the person was published on |
| `affiliation_confidence` | `high` from a dedicated team page, `medium` from a general about page |
| `extraction_method` | Which path produced the person |
| `person_key` | Stable dedupe key, `domain:name` |
| `company_people_count` | How many people the company published |
| `pages_attempted`, `pages_reached`, `pages_distinct` | What was tried, what opened, what was unique |
| `fetch_status`, `fetch_error` | `ok`, `no_team_page`, `partial` or `unreachable` |
| `people_json`, `person_1_name` … `person_5_title` | Company grain only: everyone found, plus the five most senior flattened |

> ⚠️ **`0` and `null` are different answers.** `company_people_count: 0` means the pages were
> read and nobody was published. `null` means nothing was readable. This actor never collapses
> them. In the same spirit, a plain 404 is not an error: a company that does not publish
> `/people` has not blocked you.

### 🛠️ How to find a company's leadership team

1. Open the **Input** tab and put a bare domain in `domain`.
2. Leave `output_grain` on `person` for one row per person, which is what most Clay tables want.
3. Set `seniority_filter` if you only want decision makers.
4. Click **Start**.
5. Check `affiliation_confidence` and `source_url` before you use a row.

#### 🧪 Using it in Clay

Add it as an Apify enrichment and map your domain column to `domain`. Every input is accepted
as a string, which is what Clay sends.

If you are enriching a company table and want exactly one row back per row sent, set
`output_grain` to `company`. You get `people_json` holding everyone found plus the five most
senior names and titles flattened into columns.

#### 🎚️ Filtering by seniority

`seniority_filter` runs over the normalized `seniority` field, not the raw title. `job_title` is
always returned exactly as the company wrote it, so `CEO, Founder, Owner` stays intact while the
row still filters as `founder`. Founder is checked before C level on purpose, because a founder
is the more useful label to an outbound team.

### 💵 How much does it cost to extract a team page?

You pay per person found. A company with no readable team page costs nothing beyond the run.

| Plan | Price per person found |
|---|---|
| Free | $0.006 |
| Bronze | $0.0057 |
| Silver | $0.0054 |
| Gold | $0.0051 |

There is also an Actor start event at $0.00005, charged once per run per GB of memory.

> 💳 **In company grain the charge is once per person in the array, not once per row.** One
> returned row carrying seventeen people bills seventeen events. Set `max_people` if you want a
> ceiling; anything dropped is logged with the count.

### ⌨️ Input

Everything is on the **Input** tab. The options worth explaining:

| Field | Type | Default | What it does |
|---|---|---|---|
| `domain` | string | required | Bare company domain. |
| `output_grain` | string | `person` | `person` for one row per person, `company` for one row per company. |
| `seniority_filter` | string | `all` | Keep only people at or above a rung on the seniority ladder. |
| `max_people` | string | `50` | Ceiling per company. Dropped people are logged with a count. |
| `include_emails` | boolean | `false` | Return emails found on the page, attached to the company only. |
| `skipCache` | string | `false` | `true` forces a fresh crawl past the 14 day cache. |

### 📤 Output

Exportable as **JSON, CSV, Excel, HTML or XML**. One row per person by default:

```json
{
  "full_name": "Monty Deel",
  "first_name": "Monty",
  "last_name": "Deel",
  "job_title": "Chief Executive Officer",
  "seniority": "c_level",
  "department": "general",
  "source_url": "https://swishdata.com/about/leadership/",
  "source_path": "/about/leadership",
  "extraction_method": "markup_heuristic",
  "affiliation_confidence": "high",
  "company_domain": "swishdata.com",
  "company_people_count": 17,
  "pages_attempted": 11,
  "pages_reached": 5,
  "pages_distinct": 2,
  "fetch_status": "ok",
  "fetch_error": null,
  "person_key": "swishdata.com:monty deel",
  "run_date": "2026-08-09T21:24:42.972Z"
}
```

### 💡 Tips

- Filter on `affiliation_confidence: "high"` before you sequence anybody. It is the single
  cheapest quality gate on this actor.
- Use `person_key` to dedupe across runs and across domains.
- Leave `include_emails` off. See Known limits for what those addresses actually turn out to be.
- Use `company` grain when the actor is one column in a company table, and `person` grain when
  you are building a contact list.

### ⚠️ Known limits

**About 6 companies in 10 give us anybody at all.** Measured on eight real companies spanning
enterprise to small contractor: five returned at least one person, four returned a full
leadership list, three returned nothing. If a company does not publish a team page, this actor
cannot invent one.

**We only see what a company publishes about itself.** No profile network, no login, no third
party database. That is the point of this actor and it is also its ceiling: most companies
publish their executives and almost none publish their whole staff.

**Check `affiliation_confidence` before you trust a row.** People found on a general about page
are marked `medium`, because an about page can name customers, advisors and case study subjects
alongside employees.

**The same page often lives at several URLs.** One company in the sample served its leadership
page at three different paths. Those are collapsed to one before extraction.

**HTTP 200 is not always the page you asked for.** One large company returns 200 for
`/leadership`, `/about` and `/about-us` and serves the same generic marketing page on all three.
When that happens you get zero people from those paths rather than four invented ones.

**Emails are off by default and you should probably leave them off.** Across three domains that
published an email on a team page, we found one role mailbox, one placeholder in example
content, and one literal `user@domain.com` template string. Not one was a real person's address.

**Titles are returned exactly as published, and the seniority ladder reads that string.** A bare
`Partner` maps to `c_level`, which is right at a law firm or a fund and too senior at a company
that uses the word differently. When the rung matters, read `job_title` as well.

**You are billed per person, not per company.** A company with seventeen executives bills
seventeen times from one crawl. A company with none bills nothing.

**What this actor will not collect,** enforced in code and covered by tests: no email attached
to a named person, ever, not behind a flag. No guessed email patterns. No phone numbers,
photographs, image URLs or biographies. No inference of any personal attribute beyond the fixed
seniority and department maps, which read the published title and nothing else.

### ❓ FAQ

##### Can it get me email addresses for these people?

No, and that is a build rule rather than a missing feature. When `include_emails` is on,
addresses attach to the company row only, because nothing on these pages proves which address
belongs to whom.

##### Why did a company return nothing?

Either it does not publish a team page, or the pages were not readable. `fetch_status` tells you
which: `no_team_page` means pages were read and nobody was found, `unreachable` means nothing
opened.

##### Does it use a proxy?

No. It runs direct with full browser headers and reports blocks rather than routing around them.
The headers are required, not an optimization: two of the eight test domains return a challenge
page to a bare user agent and the real leadership page to the full header set.

##### How fresh is the data?

Cached for 14 days, keyed by domain, grain, seniority filter and the email flag. Leadership pages
change on a quarterly cycle. Set `skipCache` to `"true"` to force a fresh crawl.

##### How do I get a person removed?

Email privacy@mambamindsetgrowth.com with the person's name and the company domain. Records are
purged within 14 days.

### 🧩 Want other GTM data?

Mamba Labs builds custom actors for B2B go-to-market teams. The public versions
of that work live here on the Store, so our users get the same tooling we build
under contract.

| | |
|---|---|
| 🧑‍💼 [GTM Hiring Signal Scraper](https://apify.com/mambalabs/gtm-hiring-signal-scraper) | 🧱 [Tech Stack Detector](https://apify.com/mambalabs/gtm-tech-stack-signal-scraper) |
| 📡 [B2B Buying Signals Aggregator](https://apify.com/mambalabs/b2b-buying-signals-hiring-tech-stack-intent-for-clay) | 🔑 [Job Board Keyword Scanner](https://apify.com/mambalabs/job-board-keyword-signal-scanner) |
| 🔗 [Domain to LinkedIn URL Resolver](https://apify.com/mambalabs/domain-to-linkedin-url-resolver) | 🎯 [ICP Fit Scorer](https://apify.com/mambalabs/icp-account-lead-scoring-fit-scorer-0-100-for-clay) |
| 📋 [Job Posting Monitor](https://apify.com/mambalabs/gtm-job-discovery) | 📬 [Domain Deliverability Checker](https://apify.com/mambalabs/domain-deliverability-checker) |
| 🏢 [Company Firmographic Enricher](https://apify.com/mambalabs/company-firmographic-enricher) | 🌐 [Company Social Presence Mapper](https://apify.com/mambalabs/company-social-presence-mapper) |
| 🪪 [Company Identity Resolver](https://apify.com/mambalabs/company-identity-resolver) | 💰 [Funding and Press Signal Scanner](https://apify.com/mambalabs/funding-press-signal-scanner) |
| 🔄 [Company Change-Event Feed](https://apify.com/mambalabs/company-change-event-feed) | 👤 [People Finder and Email Verifier](https://apify.com/mambalabs/people-finder) |
| 🚀 [Prospect Engine](https://apify.com/mambalabs/b2b-prospect-engine) | 🤖 [AI Tooling Detector](https://apify.com/mambalabs/ai-tooling-detector) |
| 📮 [Outbound Stack Detector](https://apify.com/mambalabs/outbound-infrastructure-fingerprint) | 📝 [Publishing Frequency Tracker](https://apify.com/mambalabs/blog-publishing-frequency) |
| ✉️ [Work Email Waterfall Finder](https://apify.com/mambalabs/email-waterfall-orchestrator) | ⏩ [Sequencer Lead Push](https://apify.com/mambalabs/clay-to-instantly-smartlead-push) |
| 🏅 [Workplace Program Detector](https://apify.com/mambalabs/workplace-program-detector) | 🧭 [Company Discovery List Builder](https://apify.com/mambalabs/company-discovery-list-builder) |

> Every actor in the suite takes a domain or a company and returns one flat row,
> so they stack in the same Clay table without reshaping anything.

> 🛠️ **Need something custom built for you or your team?** Tell us what you are
> trying to find and we will build it. [Talk to Mamba Labs](https://mambabuilt.com/contact).

### 🆘 Support

Something wrong, or a company the actor reads incorrectly? Open an issue on the **Issues** tab
with the domain and the row, and we will look at it.

> ℹ️ **Personal data, sourcing and removal.** This actor returns names and job titles that
> companies publish about their own staff, read directly from the company's own website with
> `robots.txt` honored. That is personal data under GDPR. Mamba Labs processes it on your
> instruction; you decide what happens to it next and you are responsible for that use,
> including establishing your own lawful basis. To have a record removed, email
> privacy@mambamindsetgrowth.com with the person's name and the company domain. Records are
> purged within 14 days.

Built by [Mamba Labs](https://apify.com/mambalabs).

# Actor input Schema

## `domain` (type: `string`):

A single company domain, for example swishdata.com. Protocol and path are stripped.

## `output_grain` (type: `string`):

person returns one row per person, which is the default and what most Clay tables want. company returns one row per company with a people\_json array plus the first five names and titles flattened into columns.

## `seniority_filter` (type: `string`):

all keeps everyone the page published. executive keeps founders and C-level only. leadership adds VPs, directors and heads.

## `max_people` (type: `string`):

Sent as a string so Clay can map a column into it. Clamped to 1 to 200. People are ordered by seniority before the cap applies, and anything dropped is logged with the count.

## `include_emails` (type: `boolean`):

Off by default and you should probably leave it off. Across three domains that published an email on a team page we found one role mailbox, one placeholder in example content, and one literal user@domain.com template string. Not one was a real person's address. When on, emails come back on the COMPANY row only, never attached to a named person, because nothing on these pages proves which address belongs to whom.

## `skipCache` (type: `string`):

false uses the 14 day result cache. true re-crawls the company from scratch.

## Actor input object example

```json
{
  "domain": "swishdata.com",
  "output_grain": "person",
  "seniority_filter": "all",
  "max_people": "25",
  "include_emails": false,
  "skipCache": "false"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "domain": "swishdata.com",
    "output_grain": "person",
    "seniority_filter": "all",
    "max_people": "25",
    "include_emails": false,
    "skipCache": "false"
};

// Run the Actor and wait for it to finish
const run = await client.actor("mambalabs/team-page-people-extractor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "domain": "swishdata.com",
    "output_grain": "person",
    "seniority_filter": "all",
    "max_people": "25",
    "include_emails": False,
    "skipCache": "false",
}

# Run the Actor and wait for it to finish
run = client.actor("mambalabs/team-page-people-extractor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "domain": "swishdata.com",
  "output_grain": "person",
  "seniority_filter": "all",
  "max_people": "25",
  "include_emails": false,
  "skipCache": "false"
}' |
apify call mambalabs/team-page-people-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mambalabs/team-page-people-extractor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/j8a9zX0k4mNbvDbWK/builds/FfpeC8yJOrCvQOR6g/openapi.json
