# Company Research (`rational_opaque/company-research`) Actor

Domain in, evidence-backed company profile out. Firmographics, HTTP/DNS tech stack, GLEIF/SEC/Companies House, plus hiring, product velocity, and news signals — every field has a source URL.

- **URL**: https://apify.com/rational_opaque/company-research.md
- **Developed by:** [Rational Opaque](https://apify.com/rational_opaque) (community)
- **Security:** Limited permissions
- **Stats:** 1 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 1,000 company profileds

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Company Research

**Support & feedback.** Questions and bugs go in the Actor Issues tab. We reply within 48 hours.

Domain in, evidence-backed company profile and buying signals out. Identity, tech stack, public registries, and signals each cite the page or API they came from. Unknown stays `null`. Nothing here is a guessed email, a revenue estimate, or a headcount.

**Who uses this.** SDR, RevOps, ABM, and VC teams, starting from a domain.

| Who | What they run |
| --- | --- |
| SDR | Account list in, profile and open roles out |
| RevOps | Same `companyId` joined to hiring and event datasets |
| ABM | Tech stack and buying signals on target domains |
| VC / PE | Legal name, LEI, filings, and product velocity |

It uses the same `domain` and `companyId` as [Hiring Intent Scorer](https://apify.com/rational_opaque/hiring-intent-scorer) and [Event Discovery Feed](https://apify.com/rational_opaque/event-discovery-feed), so the three datasets join. `companyId` is the first 12 hex characters of `sha1` of the registrable domain.

**Pay-per-event only.** 1,000 companies with profile, tech, a registry match, and signals, and no LLM brief, is about **$12** plus the platform start event. A full row with a brief is about $0.024.

### What you get

| Piece | Detail |
| --- | --- |
| Identity | Name, legal name, description, logo, founded year, HQ, switchboard phone, published generic inboxes (`info@`, `sales@`, `press@`). Each value is `{ value, sourceUrl, fetchedAt }`. |
| Tech stack | HTTP headers, script URLs, cookies, and DNS (MX, SPF, TXT, NS), with confidence and evidence. |
| Registries | GLEIF, SEC EDGAR including Form D, and UK Companies House when you pass a key. Weak matches come back as up to three candidates. |
| Signals | Greenhouse, Lever, or Ashby open roles; event mentions on the company site; changelog or blog posts in the last 90 days; public GitHub org; own newsroom. |
| Change tracking | Named store `company-research-state`, key `stateKey`. `onlyChanges` pushes new and updated rows. |

Public logged-out pages only. No LinkedIn. No CAPTCHA or Cloudflare bypass. No Playwright.

### Quick start

```json
{
  "domains": ["stripe.com"],
  "maxCompanies": 1,
  "maxPagesPerCompany": 6,
  "detectTechStack": true,
  "lookupRegistries": true,
  "enrichSignals": false,
  "extractTeam": false,
  "generateAccountBrief": false,
  "onlyChanges": false,
  "stateKey": "default"
}
```

Import domains from a Hiring Intent or Event Discovery dataset:

```json
{
  "fromDatasetId": "DATASET_ID",
  "eventsDatasetId": "EVENTS_DATASET_ID",
  "onlyChanges": true,
  "stateKey": "accounts-weekly"
}
```

Weekly change watch: schedule the actor with the same `stateKey` and `onlyChanges: true`. The second identical run pushes nothing and does not charge `change-detected`.

### Input

| Field | Default | Notes |
| --- | --- | --- |
| `domains` | — | Domain or URL. Required unless `fromDatasetId` is set. |
| `fromDatasetId` | — | Reads `domain`, `companyDomain`, or `website`. Keeps `intentScore` / `openRoles` when those columns exist. |
| `eventsDatasetId` | — | Matches organizer, sponsor, exhibitor, and speaker company URLs. |
| `maxCompanies` | 100 | Cap for the run. |
| `maxPagesPerCompany` | 12 | Home, about, team, contact, careers, blog, news, changelog, events, sitemap. |
| `detectTechStack` | true | Charged as `tech-stack-detected` when at least one technology matches. |
| `lookupRegistries` | true | GLEIF and SEC always; Companies House only with `companiesHouseKey`. |
| `companiesHouseKey` | — | Secret. Free key from developer.company-information.service.gov.uk. |
| `includeOfficers` | false | Officer names stay off unless you turn this on. Counts can still be present. |
| `registryMatchThreshold` | 0.85 | Below this, candidates only. |
| `enrichSignals` | true | Hiring, events, velocity, newsroom. |
| `githubToken` | — | Optional. Public data only. |
| `extractTeam` | false | Names and titles from the company's own team page. No emails. |
| `generateAccountBrief` | false | Needs `llmApiKey`. Uses only fields on the row. |
| `stateKey` | `default` | Same key across scheduled runs. |
| `onlyChanges` | false | Push new and updated companies only. |

### Sample row

Excerpt of a local run of `stripe.com` on 28 Oct 2026. Every value below is from that run. Omitted: null identity fields, the hreflang list, social profiles other than GitHub, DNS TXT and NS records, GLEIF and SEC candidate lists, news items, and pages fetched. SEC did not match. Companies House was skipped because no key was set.

```json
{
  "companyId": "4920be936201",
  "domain": "stripe.com",
  "inputValue": "stripe.com",
  "websiteUrl": "https://stripe.com/in",
  "status": "ok",
  "identity": {
    "name": { "value": "Stripe", "sourceUrl": "https://stripe.com/in", "fetchedAt": "2026-10-28T10:56:32.408Z", "method": "jsonld", "confidence": 0.9 },
    "legalName": { "value": "Stripe, LLC", "sourceUrl": "https://stripe.com/in", "fetchedAt": "2026-10-28T10:56:32.408Z", "method": "jsonld", "confidence": 0.9 },
    "description": { "value": "Stripe powers online and in-person payment processing and financial solutions for businesses of all sizes.", "sourceUrl": "https://stripe.com/in", "fetchedAt": "2026-10-28T10:56:32.408Z", "method": "jsonld", "confidence": 0.85 },
    "genericEmails": { "value": ["sales@stripe.com"], "sourceUrl": "https://stripe.com/in", "fetchedAt": "2026-10-28T10:56:32.408Z", "method": "html", "confidence": 0.7 }
  },
  "socials": {
    "github": { "value": "https://github.com/stripe", "sourceUrl": "https://stripe.com/in", "fetchedAt": "2026-10-28T10:56:32.408Z", "method": "html", "confidence": 0.7 }
  },
  "techStack": {
    "items": [
      { "name": "Google Workspace", "category": "email_provider", "confidence": 0.95, "evidence": ["MX aspmx3.googlemail.com"], "sourceUrl": "dns:stripe.com", "fetchedAt": "2026-10-28T10:56:32.408Z" },
      { "name": "Next.js", "category": "framework", "confidence": 0.85, "evidence": ["script https://b.stripecdn.com/mkt-ssr-statics/assets/_next/static/chunks/polyfills-42372ed130431b0a.js"], "sourceUrl": "https://stripe.com/in", "fetchedAt": "2026-10-28T10:56:32.408Z" }
    ]
  },
  "registries": {
    "gleif": {
      "matched": true,
      "confidence": 1,
      "record": { "lei": "549300CLHGIPTCYHQ143", "legalName": "STRIPE, LLC", "jurisdiction": "US-DE", "status": "ACTIVE", "legalAddressCountry": "US" },
      "sourceUrl": "https://api.gleif.org/api/v1/lei-records?filter[fulltext]=Stripe%2C%20LLC&page[size]=10",
      "fetchedAt": "2026-10-28T10:56:32.408Z"
    },
    "sec": { "matched": false, "confidence": 0.933, "record": null, "sourceUrl": "https://www.sec.gov/files/company_tickers.json", "fetchedAt": "2026-10-28T10:56:32.408Z" },
    "companiesHouse": { "skipped": "no_key" }
  },
  "signals": {
    "hiring": {
      "atsProvider": "greenhouse",
      "careersUrl": "https://stripe.com/in/careers",
      "openRoles": 716,
      "departments": [],
      "topLocations": ["Singapore", "Dublin", "Bengaluru", "London", "Mexico City", "N/A", "Chicago", "Toronto"],
      "newestPostedAt": "2026-10-28T09:19:59.000Z",
      "source": "ats",
      "sourceUrl": "https://boards-api.greenhouse.io/v1/boards/stripe/jobs",
      "fetchedAt": "2026-10-28T10:56:32.408Z"
    },
    "productVelocity": {
      "changelogUrl": "https://docs.stripe.com/changelog",
      "postsLast90d": 0,
      "latestPostAt": "2025-10-07T07:00:00.000Z",
      "github": { "org": "stripe", "url": "https://github.com/stripe", "publicRepos": 101, "totalStars": 45509, "reposPushedLast90d": 59, "fetchedAt": "2026-10-28T10:56:32.408Z" }
    }
  },
  "changeType": "new",
  "scrapedAt": "2026-10-28T10:56:32.408Z",
  "chargedEvents": ["company-profiled", "tech-stack-detected", "registry-matched", "signals-enriched"]
}
```

`companyId` `4920be936201` is `sha1("stripe.com")` truncated to 12 hex characters.

### Pricing

Configured in Console under Actor → Monetization. The code charges these names and no others. `apify-default-dataset-item` is not enabled.

| Event | Price | When |
| --- | --- | --- |
| `apify-actor-start` | platform | Run start |
| `company-profiled` | $0.004 | Status `ok` or `partial` and a name or description was found |
| `tech-stack-detected` | $0.002 | At least one technology |
| `registry-matched` | $0.003 | At least one registry matched |
| `signals-enriched` | $0.003 | Hiring, an event, velocity, or news |
| `account-brief-generated` | $0.01 | Brief written |
| `change-detected` | $0.002 | `onlyChanges` and the row is new or updated |

Invalid domains are pushed and not charged. An unreachable site with no data is not charged. The run stops cleanly when the charge limit is hit.

Worked example, 1,000 companies, no brief, every optional block hits: 1,000 × ($0.004 + $0.002 + $0.003 + $0.003) = **$12**. With briefs: about **$22**.

### FAQ

**Why not an opaque database (ZoomInfo, Apollo, Crunchbase)?** This actor reads the live site, DNS, and public registries and links every key field to a source. There is no stale vendor row and no LinkedIn graph. The trade-off is no revenue figure and no headcount guess.

**A site is behind Cloudflare.** Status is `blocked`. DNS and registries can still fill in. The actor does not try to get past the challenge.

**Companies House is empty.** The UK lookup is skipped unless `companiesHouseKey` is set. US filers still go through SEC. GLEIF runs either way.

### GDPR

Team-page extraction is off by default. When it is on, the actor keeps names and titles the company itself published on its own site. It does not collect or guess email addresses for those people. Officer names from Companies House are off by default. You are responsible for a lawful basis under GDPR, UK GDPR, and India's DPDP, and for honoring opt-outs.

### Legal

Public logged-out data and public APIs only. Not affiliated with the SEC, Companies House, GLEIF, GitHub, or any ATS vendor.

### Limits

No LinkedIn, Crunchbase, Owler, or Apollo. No personal emails, revenue, or headcount. Registries in v1 are GLEIF, SEC EDGAR (including Form D), and UK Companies House. India MCA is later. A browser is not used in v1. Sibling actors are not started as sub-runs; pass their dataset IDs instead.

# Actor input Schema

## `domains` (type: `array`):

Company website domains or URLs, e.g. stripe.com, https://linear.app. Normalized to the registrable domain (eTLD+1). Required unless fromDatasetId is set.

## `fromDatasetId` (type: `string`):

Optional Apify dataset ID (e.g. from Hiring Intent Scorer or Event Discovery Feed). Reads domain/companyId fields and merges hiring signals when present.

## `eventsDatasetId` (type: `string`):

Optional Event Discovery Feed dataset ID. Companies appearing as organizer, sponsor, exhibitor or speaker company get an events signal.

## `maxCompanies` (type: `integer`):

Hard cap on companies processed in this run.

## `maxPagesPerCompany` (type: `integer`):

Maximum website pages fetched per company (home, about, team, contact, careers, blog, sitemap).

## `detectTechStack` (type: `boolean`):

Detect technologies from HTTP headers, scripts and DNS (MX/SPF/TXT). Charged as tech-stack-detected.

## `lookupRegistries` (type: `boolean`):

Match the company in GLEIF, SEC EDGAR (incl. Form D) and UK Companies House (if key provided). Charged as registry-matched when a match is found.

## `companiesHouseKey` (type: `string`):

Optional free API key from developer.company-information.service.gov.uk. Without it, UK registry lookup is skipped.

## `includeOfficers` (type: `boolean`):

Include officer/director names from public registries. Off by default for GDPR minimization.

## `registryMatchThreshold` (type: `number`):

Minimum name-match confidence (0.5–1) to accept a registry record. Below it, up to 3 candidates are returned unmatched.

## `enrichSignals` (type: `boolean`):

Hiring (Greenhouse/Lever/Ashby), events, product velocity (changelog/blog/GitHub) and newsroom. Charged as signals-enriched.

## `githubToken` (type: `string`):

Optional GitHub token to raise API rate limits for org/repo activity. Public data only.

## `extractTeam` (type: `boolean`):

Extract names and titles listed on the company's own public team/leadership page. No emails are collected or guessed.

## `generateAccountBrief` (type: `boolean`):

Write a short sales account brief from the collected fields only. Requires llmApiKey. Charged as account-brief-generated.

## `icpDescription` (type: `string`):

Optional description of what you sell and to whom. Used only for the account brief's fit and talking points.

## `llmApiKey` (type: `string`):

OpenAI-compatible API key used only when generateAccountBrief is on.

## `llmModel` (type: `string`):

Model name for the OpenAI-compatible endpoint.

## `llmBaseUrl` (type: `string`):

OpenAI-compatible base URL.

## `stateKey` (type: `string`):

Key in the named key-value store company-research-state. Use the same key across scheduled runs to track changes.

## `onlyChanges` (type: `boolean`):

Push only companies that are new or changed since the last run with this stateKey. Charged as change-detected.

## `proxyConfiguration` (type: `object`):

Proxy for website requests. Registry and DNS lookups go direct.

## Actor input object example

```json
{
  "domains": [
    "stripe.com"
  ],
  "maxCompanies": 1,
  "maxPagesPerCompany": 6,
  "detectTechStack": true,
  "lookupRegistries": true,
  "includeOfficers": false,
  "registryMatchThreshold": 0.85,
  "enrichSignals": false,
  "extractTeam": false,
  "generateAccountBrief": false,
  "llmModel": "gpt-4o-mini",
  "llmBaseUrl": "https://api.openai.com/v1",
  "stateKey": "default",
  "onlyChanges": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `companies` (type: `string`):

Company profiles with provenance, tech stack, public registries, buying signals, and change tracking.

# 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 = {
    "domains": [
        "stripe.com"
    ],
    "maxCompanies": 1,
    "maxPagesPerCompany": 6,
    "enrichSignals": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("rational_opaque/company-research").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 = {
    "domains": ["stripe.com"],
    "maxCompanies": 1,
    "maxPagesPerCompany": 6,
    "enrichSignals": False,
}

# Run the Actor and wait for it to finish
run = client.actor("rational_opaque/company-research").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 '{
  "domains": [
    "stripe.com"
  ],
  "maxCompanies": 1,
  "maxPagesPerCompany": 6,
  "enrichSignals": false
}' |
apify call rational_opaque/company-research --silent --output-dataset

```

## MCP server setup

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

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/smw6M6H6aSwhgyPGT/builds/5gBzMT1fs7kSpv2N7/openapi.json
