
Emma Foster
Machine Learning Engineer

Company registration data extraction becomes useful to AI due diligence only when records are current, traceable, and normalized across jurisdictions. The best architecture is API-first: query official registries, preserve the source response, map fields into a shared company schema, and use browser automation only when no suitable API or export exists. CAPTCHA challenges may interrupt public portal workflows, but they should be handled through an auditable recovery layer with strict authorization, rate limits, and data-minimization controls. This guide shows how to build that pipeline, including source selection, identity resolution, structured Python examples, evidence storage, change monitoring, and safe CapSolver integration. The result supports vendor onboarding, counterparty screening, portfolio monitoring, and research agents without allowing the model to make unsupported legal or risk determinations.
A useful record is more than a company name. It needs enough stable identifiers and provenance to distinguish similarly named entities and explain every conclusion.
from dataclasses import dataclass, field
from datetime import datetime
@dataclass
class CompanyRecord:
jurisdiction: str
registry_company_id: str
legal_name: str
previous_names: list[str] = field(default_factory=list)
company_status: str | None = None
incorporation_date: str | None = None
legal_form: str | None = None
registered_address: dict | None = None
officers: list[dict] = field(default_factory=list)
filing_history: list[dict] = field(default_factory=list)
industry_codes: list[str] = field(default_factory=list)
source_url: str | None = None
collected_at: str = field(default_factory=lambda: datetime.utcnow().isoformat())
The core fields vary by jurisdiction, but the record should always retain the official company identifier, source jurisdiction, source URL, and collection timestamp. The CapSolver web-scraping FAQ provides general guidance for reliable public-data collection, while the CapSolver automation blog covers workflow design.
Official APIs offer stable schemas, clearer licensing, and predictable rate limits. For example, the UK Companies House API provides live company information, while the SEC EDGAR APIs expose U.S. filing and submission data. The EU e-Justice business-register portal describes cross-border registry access through BRIS.
| Source path | Best use | Main advantage | Main limitation |
|---|---|---|---|
| Official REST API | Repeated verification and monitoring | Stable structured data | Authentication and rate limits |
| Official bulk dataset | Portfolio-scale analytics | Efficient high-volume processing | May not be real time |
| Public registry portal | One-off or unsupported fields | Human-readable source evidence | Session controls and CAPTCHA challenges |
| Licensed aggregator | Multi-jurisdiction coverage | Normalized schema | Cost and license restrictions |
A defensible AI due diligence workflow records which source path produced each field. It should never silently merge an aggregator value with an official record without provenance.
The following API-first example uses the documented Companies House company-profile endpoint. Store the API key outside the prompt and source code.
import os
import requests
COMPANIES_HOUSE_KEY = os.environ["COMPANIES_HOUSE_API_KEY"]
def fetch_uk_company(company_number: str) -> dict:
url = (
"https://api.company-information.service.gov.uk/"
f"company/{company_number}"
)
response = requests.get(
url,
auth=(COMPANIES_HOUSE_KEY, ""),
timeout=30,
headers={"Accept": "application/json"},
)
response.raise_for_status()
raw = response.json()
return {
"jurisdiction": "GB",
"registry_company_id": raw["company_number"],
"legal_name": raw["company_name"],
"company_status": raw.get("company_status"),
"incorporation_date": raw.get("date_of_creation"),
"legal_form": raw.get("type"),
"registered_address": raw.get("registered_office_address"),
"industry_codes": raw.get("sic_codes", []),
"source_url": url,
}
Use documented endpoints for officers, filing history, insolvency, and persons with significant control only when those fields are necessary for the approved use case. Do not collect entire profiles by default. The Companies House register guidance explains the public register and search policies.
Registry terms differ. One source may use “active,” another “registered,” and another a jurisdiction-specific label. Preserve the raw value and map it into a small normalized vocabulary.
STATUS_MAP = {
"active": "active",
"registered": "active",
"dissolved": "inactive",
"liquidation": "distress",
"administration": "distress",
"converted-closed": "inactive",
}
def normalize_status(raw_status: str | None) -> dict:
raw = (raw_status or "unknown").strip().lower()
return {
"raw_status": raw_status,
"normalized_status": STATUS_MAP.get(raw, "other"),
}
Normalization should never discard the source label. AI agents need the raw evidence to explain uncertainty and accommodate changes in registry terminology.
The CapSolver Python scraping guide offers practical collection patterns, and the CapSolver glossary helps teams standardize automation terminology.
Names alone are unreliable. Resolve entities by weighting stable identifiers and corroborating attributes.
from difflib import SequenceMatcher
def entity_match_score(query: dict, candidate: dict) -> float:
score = 0.0
if query.get("registry_company_id") == candidate.get("registry_company_id"):
score += 0.60
name_a = (query.get("legal_name") or "").lower()
name_b = (candidate.get("legal_name") or "").lower()
score += 0.25 * SequenceMatcher(None, name_a, name_b).ratio()
if query.get("postal_code") and (
query["postal_code"] == candidate.get("postal_code")
):
score += 0.15
return round(min(score, 1.0), 3)
Require human review below a conservative confidence threshold. An AI agent should summarize the match evidence, not declare two entities identical merely because their names are similar.
Some registries expose fields only through a public portal or add traffic validation after repeated searches. Use a browser fallback only when the terms permit automation and the organization has approved the workflow.
The user-provided CapSolver Agent documentation maps solve_on_page to the core browser method. A controlled Playwright recovery step can therefore remain outside the model's free-form reasoning:
from capsolver_core import Capsolver
cap = Capsolver(api_key=os.environ["CAPSOLVER_API_KEY"])
async def recover_authorized_registry_page(page):
detected = await cap.detect(page)
if not detected:
return {"solved": False, "reason": "No supported challenge detected"}
result = await cap.solve_on_page(page)
return {
"solved": True,
"result": result,
}
Keep the browser on the same session and apply bounded retry rules. The CapSolver CAPTCHA-solving FAQ explains the general lifecycle, and CapSolver's article on CAPTCHA handling during web scraping discusses practical recovery patterns.
Bonus Code: Use code WEBS at CapSolver Dashboard to get an extra 5% bonus on every recharge.
The AI agent should receive an evidence package rather than unrestricted raw pages. Include normalized fields, source snapshots or hashes, timestamps, and explicit data-quality warnings.
import hashlib
import json
from datetime import datetime, timezone
def build_evidence_package(record: dict, raw_response: dict) -> dict:
raw_json = json.dumps(raw_response, sort_keys=True).encode("utf-8")
return {
"record": record,
"provenance": {
"source_url": record["source_url"],
"collected_at": datetime.now(timezone.utc).isoformat(),
"raw_sha256": hashlib.sha256(raw_json).hexdigest(),
},
"warnings": [
"Registry information may be filed by the company and may require independent verification.",
"No legal or investment conclusion should be made without human review.",
],
}
This is especially important because a registry's publication of a fact does not prove that the fact is current, complete, or independently verified. AI output should distinguish “reported by the registry” from “confirmed by due diligence.”
Use event-driven checks where official webhooks or streaming products exist. Otherwise, calculate a hash of normalized fields and refetch on a risk-based schedule.
MONITORING_INTERVALS = {
"high_risk_counterparty": "daily",
"active_vendor": "weekly",
"prospect": "monthly",
"archived_relationship": "quarterly",
}
Track meaningful changes such as company status, registered office, directors, beneficial ownership filings, overdue accounts, and insolvency indicators. Avoid generating alerts for formatting-only changes.
Company registration data extraction must respect source licenses, terms of use, privacy law, and purpose limitation. Even public registries may contain personal information about officers or beneficial owners. Collect only what the approved diligence process needs, enforce retention periods, and restrict downstream model access.
The UK ICO data-protection principles provide a useful framework for lawfulness, minimization, accuracy, storage limitation, and security.
Company registration data extraction for AI due diligence works best as a provenance-first data pipeline. Use official APIs and bulk datasets whenever possible, normalize without erasing raw values, resolve entities conservatively, and provide the model with evidence rather than unchecked conclusions. When an authorized public registry portal presents a supported CAPTCHA challenge, CapSolver can act as a narrowly controlled recovery layer without changing the rest of the pipeline.
Start by testing CapSolver in a staging workflow, then add source licensing, privacy review, rate limits, and human approval before production use.
No. Availability varies by jurisdiction, record type, and access policy. Some registers publish basic company details but restrict personal, beneficial-ownership, historical, or document data.
Use the official API or bulk dataset first. Browser automation should be a fallback for permitted fields that are unavailable through structured access.
The agent can summarize evidence and flag inconsistencies, but material legal, compliance, lending, procurement, or investment decisions should remain subject to validated rules and qualified human review.
Use a risk-based schedule. High-risk counterparties may require daily checks, while low-risk or inactive relationships may need monthly or quarterly refreshes.
CapSolver is relevant only when an authorized public portal presents a supported challenge. It should not replace official APIs, permissions, identity controls, or compliance review.
Learn scalable Rust web scraping architecture with reqwest, scraper, async scraping, headless browser scraping, proxy rotation, and compliant CAPTCHA handling.

Learn the best techniques to scrape job listings without getting blocked. Master Indeed scraping, Google Jobs API, and web scraping API with CapSolver.
