# Company Discovery List Builder Market In Companies Out (`mambalabs/company-discovery-list-builder`) Actor

Market in, companies out. Give it job role keywords and a location and it returns companies currently hiring for that, built from a live index of public Greenhouse and Ashby job boards. Second mode finds US public companies whose SEC filings mention your phrase. No paid data source.

- **URL**: https://apify.com/mambalabs/company-discovery-list-builder.md
- **Developed by:** [Mamba Labs](https://apify.com/mambalabs) (community)
- **Categories:** Lead generation, Automation, Jobs
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.40 / 1,000 company 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 Company Discovery List Builder do?

Give it a **market definition** and it returns **the companies in that market**, one flat row
each. Every other company data tool takes a company and tells you something about it. This one
builds the list in the first place, with **no paid database behind it**.

Two ways to define a market. **Hiring**: job role keywords, optionally a location, and you get
companies with that role open right now. **Filings**: a phrase, and you get US SEC filers whose
filings contain it.

| 📦 What you get | ⚙️ Features and integrations |
|---|---|
| 🏢 **Companies, not enrichment**, one flat row each<br>🧾 **25 fields**, always all 25, `null` never missing<br>📏 **`universe_size` on every row**, your denominator<br>🔗 **`evidence_url`**, the posting or filing it came from | 🔍 **Hiring mode** over live Greenhouse and Ashby boards<br>🏛️ **Filings mode** over SEC EDGAR full text search<br>🧊 **30 day universe cache**, live job data on top<br>⬇️ **Export** to JSON, CSV, Excel, HTML or XML |

Bought by outbound teams building a target list from scratch, and by anyone who wants a market
defined by what companies are doing rather than by a vendor's static database.

> 🚫 **This is not a company database and it does not cover every company.** It enumerates a
> named, published universe and tells you how big it was. If you want fields about companies you
> already have, use [Company Firmographic Enricher](https://apify.com/mambalabs/company-firmographic-enricher).

### 💡 Why use Company Discovery List Builder?

| If you want | Read these fields |
|---|---|
| The company list itself | `company_name`, `company_domain` |
| To know why a company is on your list | `match_reason`, `evidence_url` |
| To judge the list's coverage | `universe_size`, `universe_source`, `universe_built_at` |
| Hiring intensity as a qualifier | `open_jobs_count`, `matched_job_count`, `matched_job_title` |
| Geography | `matched_job_location`, `locations_count` |
| The public filer identity | `ticker`, `cik`, `filing_form` |
| To tell empty from broken | `fetch_status`, `is_summary_row` |

#### 📏 Read `universe_size` before you read anything else

`universe_size` and `universe_source` ship on every single row, and they are the two most useful
fields in the output.

If the actor returns 40 companies, 40 on its own means nothing. **40 out of 9,266 candidates**
from three named Common Crawl collections is a number you can act on. A list builder that hides
its denominator is asking you to trust it, and you should not have to.

Measured on build 0.0.3: `universe_size` **9,266** cold and **9,266** warm from the same query,
with `universe_source` naming `common_crawl:CC-MAIN-2026-30+CC-MAIN-2026-25+CC-MAIN-2026-21`.

A company missing from your results is missing because it was not in that pool or did not match
your filter. It is not a statement that the company is not in your market.

### 📋 What data can Company Discovery List Builder extract?

**25 fields**, always all 25. A value that is not available comes back `null`, never missing.

| Field | What it holds |
|---|---|
| `company_name` | The name as the source publishes it |
| `company_domain` | Resolved website, when domain resolution is on and confident |
| `domain_status` | `resolved`, `low_confidence`, `not_found`, `not_attempted`, `search_failed` |
| `domain_confidence` | 0 to 100 |
| `match_reason` | Why this company is in your list, in plain words |
| `mode` | `hiring` or `filings` |
| `ats_provider`, `ats_slug`, `careers_url` | Which board, whose, and where |
| `open_jobs_count` | Live open roles on the board |
| `matched_job_count`, `matched_job_title` | How many matched your keywords, and the first one |
| `matched_job_location`, `locations_count` | Its location string, and how many distinct ones the board carries |
| `ticker`, `cik`, `filing_form` | Filings mode only |
| `evidence_url` | The job posting or SEC filing this row came from |
| `universe_source`, `universe_size`, `universe_built_at` | Where candidates came from, how many, and when |
| `fetch_status`, `fetch_error` | `ok`, `partial`, `universe_error`, `no_results` |
| `is_summary_row` | True only on the fallback row when a run finds nothing |
| `run_date` | When the run happened |

> ⚠️ **`universe_size` is `null`, never `0`, when the pool could not be loaded.** Zero would read
> as a real measurement of an empty market. A `universe_error` row means there was no honest
> denominator to report, which is a different thing from a market with nobody in it.

### 🛠️ How to build a company list from a market definition

1. Open the **Input** tab and pick a `mode`, `hiring` or `filings`.
2. For hiring, put comma separated job titles in `role_keywords`, and optionally a city or
   region in `location_contains`.
3. For filings, put the phrase in `filing_phrase` and pick `filing_forms`.
4. Set `max_companies` to cap the list.
5. Click **Start**, then read `universe_size` before you read the rows.

#### 🧪 Using it in Clay

Run it once to build the list, then export and import the rows as a Clay table. This actor
creates rows rather than enriching them, so it is the step before the rest of the suite, not a
column inside it.

Turn `resolve_domains` off for the first pass. It is on by default, looking up each company's
website, and a cleaner company name list is easier to resolve deliberately afterward.

#### 🎯 How role matching works

Keywords are comma separated and matched as **whole words** against live job titles. Lowercased,
no stemming, no fuzzy distance, no AI guessing.

`account executive` matches "Account Executive, Expansion" and "Enterprise Account Executive".
It does not match "Executive Assistant" or "Accounts Executive".

That is deliberate. You can predict exactly what it will do, which matters more on a list you are
going to email than a few extra rows you cannot audit. Leave the keywords empty to match any role.

### 💵 How much does it cost to build a company list?

You are billed **per company returned**, not per company examined. A query that matches nothing
costs one run, not thousands of charges.

| Plan | Price per company found |
|---|---|
| Free | $0.004 |
| Bronze | $0.0038 |
| Silver | $0.0036 |
| Gold | $0.0034 |

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

> 💳 **The summary row is never billed.** When a query legitimately matches nothing, the run emits
> one row with `is_summary_row: true` so you can see the query ran against the whole pool. That
> row carries no charge, and neither does a `universe_error` row.

### ⌨️ Input

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

| Field | Type | Default | What it does |
|---|---|---|---|
| `mode` | string | `hiring` | `hiring` or `filings`. |
| `role_keywords` | string | empty | Comma separated job titles. Empty matches any role. |
| `filing_phrase` | string | empty | Filings mode: the phrase to find in SEC filings. |
| `filing_forms` | string | `10-K` | Filings mode: which forms to search. |
| `location_contains` | string | empty | Plain substring match on the job's location string. |
| `min_open_jobs` | string | `1` | Skip boards with fewer open roles than this. |
| `max_companies` | string | `100` | Ceiling on the returned list. |
| `resolve_domains` | boolean | `true` | Try to resolve each company to a website. |
| `refresh_universe` | boolean | `false` | Rebuild the candidate pool instead of using the cache. |

### 📤 Output

One flat row per company, exportable as **JSON, CSV, Excel, HTML or XML**.

```json
{
  "company_name": "7shifts",
  "match_reason": "hiring: Account Executive, Expansion (Toronto, ON) and 3 more matching roles",
  "mode": "hiring",
  "ats_provider": "greenhouse",
  "ats_slug": "7shifts",
  "careers_url": "https://job-boards.greenhouse.io/7shifts",
  "open_jobs_count": 15,
  "matched_job_count": 4,
  "matched_job_title": "Account Executive, Expansion",
  "matched_job_location": "Toronto, ON",
  "locations_count": 6,
  "universe_source": "common_crawl:CC-MAIN-2026-30+CC-MAIN-2026-25+CC-MAIN-2026-21",
  "universe_size": 9266,
  "fetch_status": "ok",
  "is_summary_row": false
}
```

### 💡 Tips

- Read `universe_size` first, every time. It is the difference between a list and a number.
- `resolve_domains` is on by default and looks up each company's website; turn it off to start.
  Get the company list right, then resolve.
- `location_contains` is a substring match on free text. Try the shortest distinctive fragment,
  `London` rather than `London, UK`.
- Use `min_open_jobs` to drop companies with a single stale posting.
- Run it monthly. The universe refreshes about monthly and the job data underneath is live.

### ⚠️ Known limits

Read these before you buy a run. A list builder that hides its coverage bias is worse than one
that returns fewer companies.

**The hiring mode only sees companies with a public Greenhouse or Ashby job board.** That is
about 9,266 companies in the current index, skewed heavily toward venture-backed technology
companies in the US and Europe. If your market is manufacturing, professional services,
healthcare providers, or anyone on Workday, SuccessFactors, iCIMS or a custom careers page, this
mode will mostly miss them. That is a coverage limit, not a bug.

**Lever boards are not covered at all, and cannot be.** Lever's `robots.txt` tells Common Crawl's
crawler not to index the site, so no Lever board pages exist in the index to enumerate. The only
Lever records in the crawl are `robots.txt` itself. The actor still knows how to read a Lever
board and will use it the day that changes, but today Lever coverage through this route is zero.
Unioning older crawls does not help, because the exclusion applies to all of them.

**The universe refreshes about monthly, the job data is live.** A company that started hiring last
week may not be in the pool yet. Once it is in the pool, its job data is fetched fresh every day.

**Job locations are free text.** One company in the build sample published 13 different location
strings. "Remote", "Remote - US" and "US Remote" are three different strings, and matching one
does not match the others.

**Some companies in the pool are not what their board suggests.** A venture firm's board can carry
roles for its portfolio companies. In testing, a16z's board returned 15 roles including
portfolio-company positions. Read `match_reason` before you trust a match.

**Ashby publishes no company display name.** Greenhouse does, and it is often not the slug: the
slug `abnormalsecurity` returns the name "Abnormal". Ashby's public board API returns only the
jobs, so Ashby rows carry the board slug as the company name.

**The filings mode covers US SEC filers only.** No private companies at all. What you get in
exchange is very high precision: the company said the phrase in a filing, under signature. Note
that in filings mode `universe_size` is the number of matching filings, not the size of the
searchable filer universe.

**Domain resolution is imperfect.** Check `domain_status` and `domain_confidence`. A low
confidence match returns a null domain on purpose, because a domain you have to re-check is worse
than no domain.

**A retired board slug returns a 404 and is skipped.** That is normal monthly churn. It is counted
in the run log, never emitted as a row and never raised as an error.

### ❓ FAQ

##### Where do the companies actually come from?

The hiring mode's candidate pool is enumerated from the Common Crawl URL index, a free, openly
published index of the web. The actor reads only the URL index, never archived page content.
Every company running a public Greenhouse or Ashby board has board URLs in that index. The
filings mode queries SEC EDGAR full text search directly, and one request answers the whole query.

##### Why did I get exactly one row back?

Your query matched nothing. That row has `is_summary_row: true`, `fetch_status: "no_results"` and
a populated `universe_size`, so you can see the query ran against the whole pool and matched none
of it. It is not billed.

##### What does `universe_error` mean?

The candidate pool itself could not be loaded, so there is no honest denominator. `universe_size`
comes back `null` rather than `0`.

##### How often is the pool rebuilt?

Complete unions are cached 30 days, because Common Crawl publishes about monthly and rebuilding
faster just re-downloads the same index. Partial unions are held 24 hours so the next run retries
for the full union. Set `refresh_universe` to force a rebuild.

##### Does it read job descriptions?

No. Greenhouse job bodies are explicitly not requested, so that text never enters the process at
all. The actor cannot extract recruiter names or email addresses because it never sees them.

### 🧩 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) | 👥 [Team Page People Extractor](https://apify.com/mambalabs/team-page-people-extractor) |

> 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 market the actor covers badly? Open an issue on the **Issues** tab with the
input and the rows, and we will look at it.

> ℹ️ **Sourcing and legal.** The candidate pool comes from the Common Crawl URL index, which is
> openly published, and the job data from the companies' own public job board APIs. Filings come
> from SEC EDGAR. The actor emits company names, board slugs, job titles, location strings,
> tickers and CIKs. It does not read job descriptions and cannot extract recruiter names or email
> addresses. You are responsible for how you use the output.

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

# Actor input Schema

## `mode` (type: `string`):

hiring returns companies currently hiring for your role keywords, built from a live index of public Greenhouse and Ashby job boards. filings returns US SEC filers whose filings contain your phrase.

## `role_keywords` (type: `string`):

Comma separated. Matched as whole words against live job titles, so account executive matches Enterprise Account Executive and does not match Executive Assistant. Leave empty to match any role. Used in hiring mode.

## `filing_phrase` (type: `string`):

Exact phrase searched in SEC filings, for example agentic AI. Used in filings mode.

## `filing_forms` (type: `string`):

Comma separated SEC form types, for example 10-K,10-Q. Used in filings mode.

## `location_contains` (type: `string`):

Substring match against the job location string, for example London, Remote, New York. Locations are free text on every job board, so this is a plain substring test: Remote does not match US Remote.

## `min_open_jobs` (type: `string`):

Skip companies with fewer open roles than this. A rough size proxy. Sent as a string so it works from Clay.

## `max_companies` (type: `string`):

How many companies to return, 1 to 2000. Sent as a string so it works from Clay. You are billed per company returned, not per company examined.

## `resolve_domains` (type: `boolean`):

When on, looks up each company's website. On by default: it adds roughly a second per company and about two thirds of companies resolve. Check domain\_status and domain\_confidence before trusting a result.

## `refresh_universe` (type: `boolean`):

Force a fresh Common Crawl enumeration instead of the cached one. The cached universe is rebuilt about monthly on its own, so leave this off unless you need the newest crawl.

## Actor input object example

```json
{
  "mode": "hiring",
  "role_keywords": "account executive",
  "filing_forms": "10-K",
  "min_open_jobs": "1",
  "max_companies": "3",
  "resolve_domains": true,
  "refresh_universe": 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 = {
    "mode": "hiring",
    "role_keywords": "account executive",
    "filing_forms": "10-K",
    "min_open_jobs": "1",
    "max_companies": "3",
    "resolve_domains": false,
    "refresh_universe": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("mambalabs/company-discovery-list-builder").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 = {
    "mode": "hiring",
    "role_keywords": "account executive",
    "filing_forms": "10-K",
    "min_open_jobs": "1",
    "max_companies": "3",
    "resolve_domains": False,
    "refresh_universe": False,
}

# Run the Actor and wait for it to finish
run = client.actor("mambalabs/company-discovery-list-builder").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 '{
  "mode": "hiring",
  "role_keywords": "account executive",
  "filing_forms": "10-K",
  "min_open_jobs": "1",
  "max_companies": "3",
  "resolve_domains": false,
  "refresh_universe": false
}' |
apify call mambalabs/company-discovery-list-builder --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mambalabs/company-discovery-list-builder"
        }
    }
}

```

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/jch0HdaZnpbMqlcGS/builds/SW40mjKwdaf8PNP6R/openapi.json
