# Company Financials Scraper — Valuation & M\&A (Craft.co) (`foxlabs/craft-intelligence`) Actor

Scrape company financial intelligence from Craft.co — revenue, income statements, private valuations, market cap, M\&A, executives & competitors as clean JSON. Low-cost Crunchbase / PitchBook alternative for VC/PE deal sourcing, M\&A research, sales prospecting & CRM enrichment.

- **URL**: https://apify.com/foxlabs/craft-intelligence.md
- **Developed by:** [Berkan Kaplan](https://apify.com/foxlabs) (community)
- **Categories:** Business, Lead generation
- **Features:** Limited permissions
- **Stats:** 30 total users, 7 monthly users, 100.0% runs succeeded, 2 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $3.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 Intelligence — Craft 🏢

**foXLabs company-intelligence series:** [Company enrichment](https://apify.com/foxlabs/company-enrichment) · [Owler](https://apify.com/foxlabs/owler-intelligence) · [Built In](https://apify.com/foxlabs/builtin-intelligence) · [Free lookup](https://apify.com/foxlabs/company-lookup-free)

🎉 Turn Craft into clean, structured company intelligence — no login, no API key, one row per company, with firmographics, operating metrics and links.
Built for competitive intelligence, procurement and B2B research.

### 🔍 What is the Company Intelligence — and when should you use it?

Give this actor Craft.co URLs, company names or website domains and it returns each company's Craft.co profile — financials, valuation, executives, M\&A and competitors — as clean, deduplicated rows you can filter, export or feed to an AI agent. A name or domain is delivered only after it is verified against the profile (name or website must match). Every run reads the source live.

**Use it when you need:** a company list for outreach; a quick profile before a call; or a starting point for account research.

**Use something else when:** you need the official registry filing — this is an intelligence profile, not a government registry.

### 🤖 Use with AI agents

**Already on the Apify MCP server?** Ask for this Actor by name: `foxlabs/craft-intelligence`.

**Your agent can pay for its own runs.** This Actor is pay-per-event with agentic payments, so an agent can discover it, run it and settle the bill over **x402 (USDC on Base)** or **Skyfire** — no Apify account or API token of its own. Billing is the same either way: per delivered record, never for errors.

Otherwise paste this into Claude, ChatGPT, Cursor or any MCP-enabled assistant:

```
I want to pull company records using the Apify Actor `foxlabs/craft-intelligence`.
Input: `companyNames` (names, website domains or Craft.co slugs), `companyUrls` (exact Craft.co URLs — most precise), `preset` and more — see the Input table below. `maxResults` caps how many results are returned.
Start with: {"companyNames":["Stripe","Airbnb","Notion Labs"],"maxResults":100}
Ask me what to look up, run the Actor, then summarise the rows as a table.
```

The machine-readable API, MCP config and OpenAPI definition live at `apify.com/foxlabs/craft-intelligence.md`.

### 📋 Overview

Everything you need to turn Craft company-intelligence profiles into clean, structured data — in one actor, with no login, cookies or API key.

**Why teams pick this actor:**

- ✅ **One verified profile per company** — Craft.co URL, name or website domain in; a name or domain is delivered only when the profile's name or website matches it.
- 🧹 **No empty-promise columns** — only fields Craft.co actually fills; degenerate columns are removed.
- 🔗 **Stable identifiers** — every row carries its Craft.co URL and slug plus the company website, ready to join across runs and to other Fox Labs actors.
- 💰 **Per-row pricing** — a minimal price per delivered row, no subscription.
- 🤖 **Agent-ready** — MCP + x402 agentic payments.

### ✨ Features

- 🔍 **URL, name or domain input** — Craft.co URLs in any form (`craft.co/stripe`, `…/stripe/financials`); names and website domains are turned into likely Craft.co pages (Craft.co has no public search) and verified by name or website before delivery. Each row says how it was matched (`matchedBy`).
- 🏢 **Full company profile** — revenue and income statements, employee history, valuation / market cap / funding, executives, M\&A, competitors, headquarters and offices.
- 🧹 **Clean schema** — deduplicated camelCase rows, ready for CSV/Excel/JSON.

### 🎬 Quick Start

```bash
curl -X POST "https://api.apify.com/v2/acts/foxlabs~craft-intelligence/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"companyNames":["Stripe","Airbnb","Notion Labs"],"maxResults":100}'
```

### 🚀 Getting Started (3 steps)

1. **Choose your targets** — Craft.co URLs (most precise), company names or website domains.
2. **Set the cap** — `maxResults` limits how many results are returned.
3. **Run and export** — get a clean dataset as JSON, CSV or Excel.

### 📥 Input

```json
{"companyNames":["Stripe","Airbnb","Notion Labs"],"maxResults":100}
```

| Field | Type | Description |
|---|---|---|
| `preset` | string | Auto-fills well-known company anchors, then (with Discovery depth > 0) follows Craft.co's competitor graph. NOTE: the graph spans the broader tech/software space… |
| `companyNames` | array | One company per line: a name (`Procter & Gamble`), a website domain (`stripe.com`) or a Craft.co slug (`notion-labs`). Each becomes likely Craft.co pages; a page is delivered only if its name matches the name, or its website matches the domain. Unmatched entries go to FAILED_PAGES and are never billed. |
| `companyUrls` | array | Craft.co URLs in any form (most precise), company website URLs (treated as domains), or an uploaded .txt/.csv with one company per line (first column; header row skipped). |
| `includeCompetitors` | boolean | Each company's competitor list — name, Craft.co URL and revenue (competitor revenue is often null on Craft.co). |
| `includeAcquisitions` | boolean | Acquisition / subsidiary history — company, date, amount and Craft.co URL (date & amount are usually null on Craft.co). |
| `includeLeadership` | boolean | Executive team — name + title. |
| `maxResults` | integer | Hard cap on companies returned (also your cost cap). PPE $3.50/1K delivered + $0.50/1K looked up → 100 ≈ $0.40. |
| `maxConcurrency` | integer | Pages fetched in parallel (1-20). In our test on 2026-10-06 the share of blocked requests was the same at 1, 3, 6 and 8, so this mostly sets the speed. |
| `maxDepth` | integer | How far to follow Craft.co's competitor graph for a live, broad pool (not a static anchor list): • 0 = only the companies you list / preset anchors — no… |
| `industryKeywords` | array | Only applied when depth > 0. Discovered companies whose industry tags match none of these keywords are skipped — this stops drift into unrelated sectors (e.g.… |
| `industryBlocklist` | array | Only applied when depth > 0. Discovered companies whose industry tags match ANY of these keywords are dropped — even if they also match the whitelist. Keeps… |
| `enrichFromOwler` | boolean | OFF by default. When ON, companies whose revenue/employees are missing on Craft.co are looked up on Owler.com and backfilled ONLY when Owler's domain matches the… |
| `proxyConfiguration` | object | RESIDENTIAL proxy is the default, with exits in the United States unless you pick a country. Craft.co's bot protection answers part of all requests with a challenge (HTTP 403); such a request is retried on another session (up to 10 attempts for a company you asked for, 6 for a discovered competitor). The datacenter proxy was blocked on 23 of 24 requests on 2026-10-06 — keep RESIDENTIAL. |

### 📤 Output

One row per company, saved to the dataset. Every row carries `scrapedAt` and `matchedBy`. Inputs that cannot be matched to a Craft.co profile are listed in the run log and in the `FAILED_PAGES` record of the key-value store — never written to the dataset, so no record is billed for them (from 17 October 2026 a company you asked for that was looked up costs the $0.0005 lookup fee — see Pricing). If nothing at all can be delivered, the run ends as FAILED and its status message lists the inputs. Each `FAILED_PAGES` entry has a `category`: `not-found` (craft.co has no profile at the address(es) tried), `blocked` (bot protection on every attempt — run again), `name-mismatch` / `domain-mismatch` / `domain-unverifiable` (a profile was found but it is not the company you asked for; a `name-mismatch` entry with `viaRename: true` means craft.co redirected the address to a renamed profile), `invalid-input`, `not-reached` (the run reached "Maximum companies" first) or `error`.

| Field | Description |
|---|---|
| `url` | Url |
| `slug` | Slug |
| `name` | Name |
| `matchedBy` | How the row was matched to your input: `url`, `domain` (website verified) or `name` (name verified) |
| `description` | Description |
| `website` | Website |
| `crunchbase` | Crunchbase |
| `foundedYear` | Founded Year |
| `ownership` | Ownership |
| `stockTicker` | Stock Ticker |
| `headquarters` | Headquarters |
| `headquartersCity` | Headquarters City |
| `headquartersState` | Headquarters State |
| `headquartersCountry` | Headquarters Country |
| `employees` | Registered employee count |
| `employeeHistory` | Employee History |
| `revenue` | Revenue |
| `revenueFormatted` | Revenue Formatted |
| `revenueExact` | Revenue Exact |
| `revenueCurrency` | Revenue Currency |
| `netIncome` | Net Income |
| `financialPeriod` | Financial Period |
| `incomeStatements` | Income Statements |
| `valuation` | Valuation |
| `valuationFormatted` | Valuation Formatted |
| `valuationExact` | Valuation Exact |
| `valuationDate` | Valuation Date |
| `isStaleValuation` | Is Stale Valuation |
| `marketCap` | Market Cap |
| `marketCapFormatted` | Market Cap Formatted |
| `marketCapExact` | Market Cap Exact |
| `marketCapDate` | Market Cap Date |
| `sharePrice` | Share Price |
| `sharePriceDate` | Share Price Date |
| `totalFunding` | Total Funding |
| `totalFundingFormatted` | Total Funding Formatted |
| `totalFundingExact` | Total Funding Exact |
| `social` | Social |
| `industries` | Industries |
| `industriesText` | Industries Text |
| `acquisitions` | Acquisitions |
| `executives` | Executives |
| `competitors` | Competitors |
| `offices` | Offices |

### 💼 Use cases

**1. Competitive intelligence** — profile competitors and their metrics.
*Input:* company names. *Output:* firmographics + metrics. *Use:* a competitor brief.

**2. Supplier research** — research suppliers before engaging.
*Input:* company names. *Output:* company profiles. *Use:* a vendor shortlist.

**3. Account research** — brief sales on target accounts.
*Input:* company names. *Output:* company intelligence. *Use:* an account one-pager.

### 🔗 Integration

**JavaScript / Node.js**

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('foxlabs/craft-intelligence').call({"companyNames":["Stripe","Airbnb","Notion Labs"],"maxResults":100});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

**Python**

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('foxlabs/craft-intelligence').call(run_input={"companyNames":["Stripe","Airbnb","Notion Labs"],"maxResults":100})
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)
```

Written for `apify-client` 3 for Python, where `call()` returns a run object; with version 1 or 2 it returns a dict — write `run['defaultDatasetId']` there.

**Automation (n8n / Zapier / Make):** schedule or webhook → HTTP request to the actor API with your input → handle the JSON dataset → push to a sheet, CRM or dashboard.

### 📊 Pricing

Pay-per-event.

**In force since 17 October 2026 (15:00 UTC):** a delivered company costs **$0.004** — the same as before the change — split into a **$0.0005 `company-lookup`** and a **$0.0035 record**. That is **$3.50 per 1,000 companies delivered plus $0.50 per 1,000 looked up**: 100 delivered companies ≈ $0.40. [View current pricing.](https://apify.com/foxlabs/craft-intelligence) A company you asked for that we looked up and that certainly resolved to **another company** (name or website check) costs only the **$0.0005 lookup**: finding that out takes page requests. A company with **no Craft.co profile stays free**, and so does a company that stays blocked by Craft.co's bot protection through every retry (that is on our side). A name that craft.co itself redirects to a renamed profile with a different name (`viaRename` in `FAILED_PAGES`) is **free** too — the name you typed was a real address. A profile without a website (unverifiable), lines that are never looked up (not a name, domain or craft.co URL), preset anchors and discovered competitors that fail, and other errors on our side stay **free** as well.

### ❓ FAQ

**Do I need an account, login or API key?** No. This reads Craft company-intelligence profiles.

**What do I search by?** Craft.co URLs (most precise), company names or website domains. There is no fuzzy search: a name or domain is turned into likely Craft.co pages and delivered only if the profile's name or website matches.

**How current is the data?** Every run queries Craft.co live, so results are as fresh as its profiles.

**What does each profile include?** Firmographics, operating and company-intelligence attributes and links as published on Craft.

**Can I export to CSV / Excel / JSON?** Yes — directly from the Apify dataset.

### 🐛 Troubleshooting

- **Fewer rows than expected** — raise `maxResults`, or refine the input.
- **A name or domain was not delivered** (see `FAILED_PAGES`) — Craft.co has no public search, some companies use a different slug, and renamed companies keep their old slug (`Square` → Block). Open craft.co, find the company and paste its URL into `companyUrls`.
- **The row's name is longer than the name you typed** — craft.co renamed the profile and redirects the old address to it: `OpenAI` is delivered as Craft.co's current profile `OpenAI Foundation` (craft.co/openai-foundation). This happens only when craft.co itself redirects the address and the name you typed leads the new name.
- **Two companies share a name** — a name match cannot tell them apart: `Notion` is a small smart-home company, the well-known one is `Notion Labs` (craft.co/notion-labs). Use the Craft.co URL or the website domain.
- **The run ended with "No company could be delivered"** — the status message says, for each input, whether Craft.co has no profile at the address(es) tried, whether Craft.co's bot protection blocked every attempt, or whether the input resolved to a different company. The run is SUCCEEDED (with no rows) when every failure is the input's; it is FAILED when at least one failure is on our side — a block on every attempt, an error — so run it again. Exact Craft.co URLs avoid the guesswork.
- **A company is listed as `blocked` in `FAILED_PAGES`** — Craft.co's bot protection answered every attempt with a challenge (10 attempts for a company you asked for). The company may well exist; nothing is billed for it. Run it again.
- **A company is listed as `not-found`** — craft.co redirects that address to its home page, so there is no profile under that slug (`Snowflake` lives at craft.co/snowflake-computing). Find the company on craft.co and paste its URL.

### ⚖️ Is it legal to scrape this data?

This actor reads public company-intelligence profiles from Craft. Results can still contain personal data (e.g. a person’s name); personal data is protected by the GDPR and similar laws, so only process it with a legitimate basis. See Apify’s blog post on the legality of web scraping.

### 🤝 Support & contact

- 🌐 **Website:** [data.foxlabs.com.tr](https://data.foxlabs.com.tr)
- 📧 **Email:** info@foxlabs.com.tr
- 🐛 **Issues:** open a ticket in the Actor’s **Issues** tab
- 🧰 **More clean B2B data actors:** [Fox Labs on Apify](https://apify.com/foxlabs)

### Changelog

#### 0.4.17 — 2026-10-18 — the lookup fee is written as the price in force, and the input field no longer quotes the old $4/1K

- The **Pricing** section still announced the split lookup fee in the future tense ("From 17 October 2026", "Apify notifies users of the change in advance") although it has been in force since 17 October 2026, 15:00 UTC. It now states the live price and spells it out per thousand: **$3.50 per 1,000 companies delivered + $0.50 per 1,000 looked up** (a delivered company still costs $0.004 in total). Which cases stay free is unchanged.
- The **Max results** input field described the cost as "PPE $4/1K", the pre-17-October price — corrected to the split price, both in the input schema and in the README's input table, which repeats it.
- Documentation only: no input, output field, code or actual price change.

#### 0.4.16 — 2026-10-10 — a run that delivers nothing because of its input no longer fails

- **Behaviour change — run status.** When nothing could be delivered and every failure is the input's — no Craft.co profile at the address(es) tried, the input resolved to a different company, the profile lists no website, or a line that is not a company at all — the run now ends SUCCEEDED, with the same status message as before ("No company could be delivered — …") and the details in `FAILED_PAGES`. When at least one failure is on our side — Craft.co's bot protection on every attempt, an error, a requested company the run never reached — the run still ends FAILED, so a real breakage stays visible. Such a run is the user's to fix, not a broken Actor; in the 30 days to 2026-10-10, 8 of the 37 runs by users ended FAILED.
- Nothing is billed as a result in either case; the lookup fee announced for 17 October 2026 is unchanged. No output field or price changed.

#### 0.4.15 — 2026-10-08 — README: the Python example works with the current Apify client

- The README's Python example read the results with `run['defaultDatasetId']`. With the current Apify client for Python (version 3) `call()` returns a run object, not a dict, and that line raised `TypeError: 'Run' object is not subscriptable` — after the run itself had finished. The example now reads `run.default_dataset_id`; with client version 1 or 2, keep `run['defaultDatasetId']`. Checked with apify-client 3.2.1, 2.5.1 and 1.12.2.
- No code, output field or pricing change.

#### 0.4.14 — 2026-10-06 — fewer blocked pages; "no such profile" told apart from "blocked"

- **Fewer blocked pages.** Craft.co's bot protection (Cloudflare) answers part of all requests with a challenge (HTTP 403). Three changes, each measured on 2026-10-06: RESIDENTIAL exits default to the United States when you pick no country; a proxy session that fetched a page is re-used instead of a new one being opened for every request; a company you asked for gets 10 attempts instead of 6 (discovered competitors keep 6). The challenge itself is never solved or bypassed. Local test in the runtime the platform uses (Node 20), old and new code run in the same minutes: the prefill (`Stripe`, `Airbnb`, `Notion Labs`, depth 2) went from 12 and 26 rows with 1 of 3 requested companies to 93 rows with 3 of 3 (three runs); a single-company run failed 3 times out of 6 before and 0 out of 6 after. On the platform the country default alone (0.4.13 with the country set in the input) gave 77 rows and 3 of 3 against 8 rows and 1 of 3.
- **Behaviour change — "no such profile" is certain now and reported on its own.** craft.co redirects an address without a company profile to its home page. Until now the redirect was followed and the home page counted as a block, so the address was fetched 6 times and reported as "not found or blocked". It is now recognised on the first answer. `FAILED_PAGES` entries carry `category: "not-found"` (no profile at the address(es) tried) or `"blocked"` (bot protection on every attempt — run again) instead of the single `"not-found-or-blocked"`. Neither is billed — the lookup-fee terms announced for 17 October 2026 are unchanged.
- **Renamed profiles are followed.** craft.co/openai now redirects to craft.co/openai-foundation; the row is delivered with the new `url` and `slug`. This also works when you ask by name: `OpenAI` is delivered as Craft.co's current profile "OpenAI Foundation", because craft.co itself redirected the address and the name you typed leads the new name (before, it was reported as "resolved to another company"). A rename to a differently named company (`Square` → Block) is still not delivered for a name — use the craft.co URL — and such an entry is marked `viaRename` and will not be charged the lookup fee.
- **Requested companies keep their place under "Maximum companies".** Discovered competitors no longer fill the run while a requested company is still being fetched. When the maximum is reached the rest of the queue is not fetched any more. A requested company the run did not get to is listed in `FAILED_PAGES` (`not-reached`) instead of being dropped silently.
- A company that was delivered is not fetched a second time through a competitor link, and no longer shows up in `FAILED_PAGES` when that second fetch fails.
- **Status message.** A finished run now says how many companies were delivered and names the requested ones that were not, with the reason.
- **Presets.** `openai` → `openai-foundation`, `snowflake` → `snowflake-computing`, `scale-ai` → `scale`. Removed from the AI / ML preset because craft.co has no profile at these addresses: `cohere`, `midjourney`, `google-deepmind`.
- **Corrected in the README and input descriptions:** "Craft.co answers HTTP 403 for unknown company pages" was wrong — it redirects them; the 403 is the bot protection. Concurrency did not change the share of blocked requests in our test (1, 3, 6 and 8), so that advice is gone too.
- No pricing change and no change to the output fields. A run that delivers nothing still ends as FAILED.

#### 0.4.13 — 2026-10-02 — lookup fee narrowed before it starts: "no profile" stays free

- The lookup fee announced in 0.4.12 (from 17 October 2026) will **not** apply when no Craft.co profile is found, or when the profile lists no website: Craft.co answers 403 for unknown pages and for blocked requests alike, and a valid company (craft.co/stripe) stayed blocked through all 6 tries in our test. Charged: delivered companies, and inputs that certainly resolved to another company.

#### 0.4.12 — 2026-10-02 — lookup fee announced for 17 October 2026

- **Pricing change from 17 October 2026 (15:00 UTC):** every company looked up costs a $0.0005 `company-lookup`, and a delivered record drops from $0.004 to $0.0035 — **a delivered company costs $0.004 as before**. A company you asked for that resolves to another company or has no Craft.co profile costs only the $0.0005 lookup (a valid company that stays blocked after every retry is indistinguishable and is charged the same). Lines never looked up, preset anchors and discovered competitors that fail, and other errors on our side stay free. The code is live now and charges nothing extra until the new price takes effect (`src/billing.js`).

#### 0.4.11 — 2026-10-02 — Names and domains resolved and verified, every craft.co URL form, file upload, clearer failure message

- **Behaviour change — name inputs are now verified.** A name becomes likely Craft.co slugs (legal forms dropped: `Stripe Inc` → craft.co/stripe; `Goldman Sachs Group` → goldman-sachs-group, then goldman-sachs; `Procter & Gamble` → procter-gamble) and a profile is delivered only if its name matches the name you typed (legal-form, group and generic words such as Inc, Holdings or Technologies are ignored). Before, whatever company sat at craft.co/<name> was delivered and billed — `Meta` returned "Meta View", a 33-person company. Such entries now go to `FAILED_PAGES` and are not billed. Side effect: a renamed company is no longer returned for its old name (`Square` → Block); use its Craft.co URL.
- **Website domains work.** `stripe.com` or `https://www.stripe.com/…` → slug candidates, delivered only if the profile's website is on the same domain (craft.co/checkout is a different company at checkout.fi, so `checkout.com` resolves to craft.co/checkout-com). Before, a domain became craft.co/stripe.com and the run failed. Companies whose Craft.co website is another domain (PayPal → investor.pypl.com, Zoom → zoom.com) do not match by domain — use the Craft.co URL.
- **Every craft.co URL form works:** `craft.co/x`, `http://`, `www.`, sub-pages (`/stripe/financials` → the full profile), query strings, trailing slashes. Before, sub-pages returned partial rows and the other forms failed.
- **Uploaded .txt/.csv lists in `companyUrls` are read** (one company per line). Before, the file was ignored and the run failed with "No companies".
- **New field `matchedBy`** (`url` | `domain` | `name`) on every row.
- **Clearer failure message:** a run that delivers nothing lists the inputs that were not found or resolved to another company, explains that Craft.co answers HTTP 403 both for unknown pages and for blocked requests, and no longer tells users who already use the RESIDENTIAL proxy to switch to it.
- Two inputs that resolve to the same company give one row, billed once.
- README: removed claims of a "relevance-ranked name search", "registry-ID lookup" and "legal form / formation date" fields — this Actor never had them. Prefill and examples use `Notion Labs` (a bare `Notion` is a different company). Proxy wording now matches measurements.
- No pricing change. A run that delivers nothing still ends as FAILED.

#### 0.4.10 — 2026-09-20 — README examples corrected against the real input schema

- **The README's code examples did not match this Actor.** They used `queries` and `maxResultsPerQuery` — keys that do not exist in this Actor's input schema — with a placeholder value, and the input table listed those same phantom fields. Anyone who copied the AI-agent, cURL, JavaScript or Python example got a failing run. Every example now uses the real schema and matches the Console prefill: `{"companyNames":["Stripe","Airbnb","Notion"],"maxResults":100}`
- The input table is regenerated from `input_schema.json`, so it lists the fields the Actor actually accepts.
- Removed claims carried over from the same generator template where present: "formation / status monitoring", "a canonical registry record for KYB and due diligence", "every row carries `query`", and `industry` described as a NACE code.
- No code, output field or pricing change.

#### 0.4 — 2026-09-07

- **Enabled AI-agent payments (x402) + rebuilt the README to the full standard** (What-is / when, AI-agents + x402 agentic payments + MCP, Overview, Features, Use cases, Integration, FAQ, Troubleshooting, Support & contact).

#### 0.0

- Initial release.

# Changelog

This Actor's version history is a separate document: https://apify.com/foxlabs/craft-intelligence/changelog.md

# Actor input Schema

## `preset` (type: `string`):

Auto-fills well-known company anchors, then (with Discovery depth > 0) follows Craft.co's competitor graph. NOTE: the graph spans the broader tech/software space — a 'B2B Tech & Software' run also surfaces adjacent cloud, infra, dev-tools and large software vendors, not only narrow SaaS. A built-in blocklist drops pure hardware/semiconductor/telecom/electronics. Or leave blank and paste your own companies below.

## `companyNames` (type: `array`):

One company per line: a name (`Stripe`, `Procter & Gamble`, `Goldman Sachs Group`), a website domain (`stripe.com`) or a Craft.co slug (`notion-labs`). Craft.co has no public search, so each entry is turned into likely Craft.co pages (legal forms like Inc / Ltd / AG are dropped; `stripe.com` → craft.co/stripe) and a page is delivered only if it is the company you asked for: its name must match the name you typed, or its website must match the domain you gave. Entries that cannot be matched are listed in the log and in FAILED_PAGES and are never billed. ⚠ Two companies with exactly the same name cannot be told apart (`Notion` is a small smart-home company — the well-known one is `Notion Labs`), and renamed companies are not matched by their old name (`Square` → Block). When in doubt, paste the exact Craft.co URL in the field below.

## `companyUrls` (type: `array`):

Craft.co URLs are the most precise input — any form works (`craft.co/stripe`, `https://www.craft.co/stripe/financials` → https://craft.co/stripe). A company website URL is treated like a domain above. You can also upload a .txt or .csv file with one company per line (Craft.co URL, name or domain; for a .csv the first column is used, and a header row is skipped).

## `includeCompetitors` (type: `boolean`):

Each company's competitor list — name, Craft.co URL and revenue (competitor revenue is often null on Craft.co).

## `includeAcquisitions` (type: `boolean`):

Acquisition / subsidiary history — company, date, amount and Craft.co URL (date & amount are usually null on Craft.co).

## `includeLeadership` (type: `boolean`):

Executive team — name + title.

## `maxResults` (type: `integer`):

Hard cap on companies returned (also your cost cap). PPE $3.50/1K delivered + $0.50/1K looked up → 100 ≈ $0.40.

## `maxConcurrency` (type: `integer`):

Pages fetched in parallel (1-20). In our test on 2026-10-06 the share of blocked requests was the same at 1, 3, 6 and 8, so this mostly sets the speed. Proxy sessions that worked are re-used; the Actor keeps as many sessions as this number.

## `maxDepth` (type: `integer`):

How far to follow Craft.co's competitor graph for a live, broad pool (not a static anchor list):
• 0 = only the companies you list / preset anchors — no discovery
• 1 = + each company's direct competitors
• 2 = + competitors-of-competitors (DEFAULT for presets — densest live sweep)
• 3 = one hop further (market-wide)
• 4 = exhaustive crawl
With a preset, discovery is ON by default (depth 2) so every run reflects today's market. Set 0 to scrape only an exact company list. 'Maximum companies' is always your hard cost cap (raise it for more density).

## `industryKeywords` (type: `array`):

Only applied when depth > 0. Discovered companies whose industry tags match none of these keywords are skipped — this stops drift into unrelated sectors (e.g. fintech → e-commerce). Presets fill this automatically.

## `industryBlocklist` (type: `array`):

Only applied when depth > 0. Discovered companies whose industry tags match ANY of these keywords are dropped — even if they also match the whitelist. Keeps unwanted sectors (e.g. hardware, telecom, semiconductors) out of a competitor sweep. Merged with the preset's built-in blocklist.

## `enrichFromOwler` (type: `boolean`):

OFF by default. When ON, companies whose revenue/employees are missing on Craft.co are looked up on Owler.com and backfilled ONLY when Owler's domain matches the company's website (so a wrong-name match like 'linear' → Linear Technology is rejected, never merged). Backfilled values are tagged `revenueSource:"owler"` + `revenueIsEstimate:true` and a verified `owlerUrl` is added. Note: this fetches a second page per missing-data company, so it roughly doubles cost/time for those rows.

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

RESIDENTIAL proxy is the default, with exits in the United States unless you pick a country here. Craft.co's bot protection answers part of all requests with a challenge (HTTP 403); such a request is retried on another session (up to 10 attempts for a company you asked for, 6 for a discovered competitor) and a session that worked is re-used. Measured on 2026-10-06: the datacenter proxy was blocked on 23 of 24 requests (it worked in 2 small runs on 2026-10-02), so keep RESIDENTIAL.

## Actor input object example

```json
{
  "preset": "",
  "companyNames": [
    "Stripe",
    "Airbnb",
    "Notion Labs"
  ],
  "companyUrls": [],
  "includeCompetitors": true,
  "includeAcquisitions": true,
  "includeLeadership": true,
  "maxResults": 100,
  "maxConcurrency": 5,
  "maxDepth": 2,
  "industryKeywords": [],
  "industryBlocklist": [],
  "enrichFromOwler": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `dataset` (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 = {
    "companyNames": [
        "Stripe",
        "Airbnb",
        "Notion Labs"
    ],
    "companyUrls": [],
    "maxResults": 100,
    "maxConcurrency": 5,
    "maxDepth": 2,
    "industryKeywords": [],
    "industryBlocklist": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("foxlabs/craft-intelligence").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 = {
    "companyNames": [
        "Stripe",
        "Airbnb",
        "Notion Labs",
    ],
    "companyUrls": [],
    "maxResults": 100,
    "maxConcurrency": 5,
    "maxDepth": 2,
    "industryKeywords": [],
    "industryBlocklist": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("foxlabs/craft-intelligence").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 '{
  "companyNames": [
    "Stripe",
    "Airbnb",
    "Notion Labs"
  ],
  "companyUrls": [],
  "maxResults": 100,
  "maxConcurrency": 5,
  "maxDepth": 2,
  "industryKeywords": [],
  "industryBlocklist": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call foxlabs/craft-intelligence --silent --output-dataset

```

## MCP server setup

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

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/zeDIjCsRdWfBbrf0A/builds/Nhf0Y1ikvNAG6eQWS/openapi.json
