CommunityRédaction et éditiongithub.com

tfbecker/european-company-registers

Turn a company name into its financials & register data across Europe — Bundesanzeiger, Unternehmensregister, Handelsregister (DE), INPI (FR), KRS (PL), Companies House (UK). A CLI + Claude/LLM agent skill, no paid data API.

Qu'est-ce que european-company-registers ?

european-company-registers is a Claude Code agent skill that turn a company name into its financials & register data across Europe — Bundesanzeiger, Unternehmensregister, Handelsregister (DE), INPI (FR), KRS (PL), Companies House (UK). A CLI + Claude/LLM agent skill, no paid data API.

Compatible avecClaude Code~Codex CLI~Cursor
npx skills add tfbecker/european-company-registers

Installed? Explore more Rédaction et édition skills: steipete/notion, affaan-m/seo, affaan-m/brand-voice · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation


name: european-company-registers description: Search public company registers across Europe for financial data (revenue, assets, earnings) AND structured register data (managing directors, share capital, purpose, legal form). Use when researching company financials, verifying leads, or enriching B2B data. Germany combines the Unternehmensregister (unternehmensregister.de) AND the Bundesanzeiger in parallel for Jahresabschlüsse (GJ 2022+ post-DiRUG lives only in the Unternehmensregister), PLUS a Handelsregister (handelsregister.de) path for the structured register content, Geschäftsführer/Vorstand, Stammkapital, Sitz, Gegenstand, Prokura, Rechtsform, former names. France (free revenue + officers), Poland (KRS by name/number/NIP + filing history), UK. Trigger on: Unternehmensregister, Handelsregister, Bundesanzeiger, HRB, Geschäftsführer, Stammkapital, Gesellschafter, Jahresabschluss, Bilanz, Umsatz, KRS, SIREN, company financials.

European Company Registers

Find financial data (revenue, assets, earnings) and register metadata for European companies.

Running the scripts

Pure Node.js + Python, no build step. Point REG at this repo's scripts/ directory (works from any working directory):

REG="/path/to/european-company-registers/scripts"   # or ./scripts from the repo root

Germany, the main path (Unternehmensregister + Bundesanzeiger)

Both sources are queried in parallel; listing is CAPTCHA-free. Commands:

node "$REG/de-combined.js" search  "Pergolux"                 # newest report only  (~0.4 s, default)
node "$REG/de-combined.js" search  "Pergolux" --all-ur        # all UR reports      (~0.5 s)
node "$REG/de-combined.js" search  "Pergolux" --all           # + Bundesanzeiger    (~1 s)
node "$REG/de-combined.js" report  "Pergolux"                 # ONE search + extract every free year's figures
node "$REG/de-combined.js" analyze "Pergolux" --year 2021     # one year's figures

Pick the command by intent:

  • "which years / how much revenue / analyse over all years"report. It searches once, then extracts the figures for the newest N years (default 5) in one process, routing each year to its source automatically. This is the efficient path, don't loop analyze per year.
  • just the listingsearch (add --all-ur for all years, --all to also confirm via Bundesanzeiger).
  • one specific year's figuresanalyze --year YYYY.

Flags: --max-extract N (report: how many newest years to extract, default 5) · --years 2024,2023 (only these) · --no-ur (skip the slow browser step; GJ 2022+ then listed only) · --deep (paginate the UR, only for a fuzzy/surname search spanning many companies; a precise name is complete on 1 page) · --index N (pick the Nth company) · -v (keep raw payloads) · --text-dir <dir> / --inline-text / --no-save-text (full report text is saved to ./register-texts/ by default, see Full report text below).

Why two sources (DiRUG)

Publication of Jahresabschlüsse for fiscal years beginning after 31.12.2021 moved from the Bundesanzeiger to the Unternehmensregister. So GJ 2022+ lives only in the Unternehmensregister; a Bundesanzeiger-only scrape is ~3 years stale. The UR listing is a superset (both sources, tagged sources), so it drives the listing; the Bundesanzeiger adds the report URLs whose figures the CAPTCHA+LLM extractor reads for free.

Figure extraction, both sources, all years (no paywall)

  • Listing (search) never touches a CAPTCHA.
  • GJ ≤2021 (Bundesanzeiger), HTTP path; the report's image CAPTCHA is read by Claude Haiku (vision), the text extracted by Claude Sonnet. Fast-ish (~20 s/year).
  • GJ 2022+ (Unternehmensregister), the published Jahresabschluss is free but behind a "Ich bin ein Mensch" checkbox (Friendly-Captcha, no payment/login). ur_fetch_document.py drives a stealth browser to solve the checkbox and read the text, then the LLM extracts the figures. Slower (~15-20 s/year + one browser launch); report does all UR years in one browser session and extracts them concurrently. Use --no-ur to skip it.
  • Only deposited (hinterlegte) statements of tiny companies are fee-based, those stay listed-only.

Needs a logged-in claude CLI (auto-detected, or set CLAUDE_BIN) and, for GJ 2022+, a stealth browser (see Requirements in the README; override its location with COMPANY_REGISTERS_BROWSER and its Python with UR_PYTHON). Never exports ANTHROPIC_API_KEY / ANTHROPIC_BASE_URL. Model overrides: BA_CAPTCHA_MODEL, BA_EXTRACT_MODEL.

Per-year status in report: extracted · listed_only (beyond --max-extract) · gated_skipped (--no-ur) · extraction_failed.

Full report text, scraped AND saved by default

report/analyze don't just distill figures, they keep the full document text (the whole Jahresabschluss / Lagebericht / Anhang scraped from either source, the same text the extractor reads) so nothing has to be re-scraped later. By default each extracted year is written to one UTF-8 .txt file (with a short provenance header) under ./register-texts/:

register-texts/<Court>_<Register>_GJ<Year>_<source>.txt
# e.g. Bad-Oeynhausen_HRB-7371_GJ2024_unternehmensregister.txt

Each extracted year in the JSON then carries report_chars and report_text_file; the top level of a report result adds text_dir and saved_text_count.

  • --text-dir <dir>, where to write (default ./register-texts; env REGISTER_TEXT_DIR).
  • --inline-text, also embed the full text in the JSON as report_text (heavy; off by default).
  • --no-save-text, figures only, don't write files.

The saved text carries the qualitative content the figures can't: Lagebericht (strategy, outlook, risks, only larger companies file one), Anhang (Beteiligungen/ownership, related parties, a Gewinnabführungsvertrag, contingent liabilities). For Kleinstkapitalgesellschaften it's essentially just the bare balance sheet. search never fetches documents, so it writes nothing.

Output

search → companies with euid, register/register_number (HRB), court, state, and reports[] of {fiscal_year, report_name, date, sources, free_extract} (encrypted payloads stripped unless -v). report/analyze → per year financial_data: revenue, total_assets, earnings, equity, liabilities, inventory, receivables, cash, fixed_assets, gross_profit, material_expenses, personnel_expenses, operating_result, employees, fiscal_year, is_group_report, currency. Plus, per extracted year, report_chars + report_text_file (and report_text with --inline-text); see Full report text above.

Germany, Handelsregister (structured register content)

Separate from the Jahresabschluss path above. Gives the register content, not financials: Rechtsform, Sitz + Geschäftsanschrift, Gegenstand, Stamm-/Grundkapital, Vertretungsregelung, Geschäftsführer / Vorstand, Prokura, and former names. Free since the DiRUG reform (AD).

node "$REG/de-handelsregister.js" search  "Holz-Richter"                       # register entries: name, HRB, court, seat, status, former names
node "$REG/de-handelsregister.js" details "Holz-Richter GmbH" --hrb 37497 --court Köln   # AD → structured JSON
  • search drives handelsregister.de (stealth browser; the site is a stateful JSF app, no bot-protection) and returns the matching register rows, always match a company by its HRB, never a fixed position (the result order isn't stable).
  • details downloads the AD ("Aktueller Abdruck"), runs pdftotext, and parses the standard numbered sections into JSON (share_capital, managing_directors[] with birth dates, prokura[], legal_form, purpose, seat, …).
  • Rate limit: handelsregister.de throttles document retrieval, after a few AD downloads in a short window it routes to an error page (the helper retries, then returns reason:"throttled"). search is not throttled. Retry details after a short cooldown.
  • Needs the stealth browser (override its Python with CLOAK_PYTHON) and pdftotext (poppler).

Other countries

node "$REG/gb-companies-house.js" search "Tesco"        # UK , company / filings <number> also (needs key)
node "$REG/fr-inpi.js"            analyze "Carrefour"   # FR , analyze accepts a name OR a <siren>
node "$REG/pl-krs.js"             search  "CD PROJEKT"  # PL , company <krs> · nip <nip> · analyze <krs|nip>
# Or the unified dispatcher (de routes to de-combined.js):
node "$REG/search.js" --country fr --name "Carrefour"
  • France (INPI/RNE), recherche-entreprises.api.gouv.fr, free, no key. Returns real revenue (ca) + earnings (resultat_net) per year and the officers (dirigeants) for the many companies in the open financial-ratios dataset, plus full metadata. analyze takes a name (picks the best-matching real entity) or a SIREN. An optional free INPI_API_TOKEN adds balance-sheet depth (total assets/equity); revenue works without it.
  • Poland (KRS), the official Ministry-of-Justice API by KRS number is the reliable core (company <krs> / analyze <krs>): name, legal form, NIP/REGON, seat, share capital, purpose (PKD), management board (names GDPR-masked), and the filed annual-statement list (periods + dates). nip <nip> resolves a tax id → KRS via the MF whitelist. search "name" uses the stealth browser (the portal is Incapsula-protected) and returns tagged {krs, name, city, register} candidates → then analyze <krs>. Figure extraction from the e-sprawozdania (JPK XML) is session-gated and not implemented; the filing list + repository link are returned.
  • UK (Companies House), free API, balance-sheet metadata; needs COMPANIES_HOUSE_API_KEY. Parsed financial figures require XBRL (not implemented, see ROADMAP.md).

Not supported (paid only): Austria, Spain, Netherlands.

Setup (non-German keys)

Keys are read from environment variables, or a local config/keys.json (git-ignored). Never hardcode.

{ "COMPANIES_HOUSE_API_KEY": "…",   // UK, free at developer.company-information.service.gov.uk
  "INPI_API_TOKEN": "…" }           // France, optional (basic search works without)

Poland needs no key. Germany needs no key beyond the logged-in claude CLI.

Skills associés

steipete/notion

Notion CLI/API for pages, Markdown content, data sources, files, comments, search, Workers, and raw API calls.

community

affaan-m/seo

Audit, plan, and implement SEO improvements across technical SEO, on-page optimization, structured data, Core Web Vitals, and content strategy. Use when the user wants better search visibility, SEO remediation, schema markup, sitemap/robots work, or keyword mapping.

community

affaan-m/brand-voice

Build a source-derived writing style profile from real posts, essays, launch notes, docs, or site copy, then reuse that profile across content, outreach, and social workflows. Use when the user wants voice consistency without generic AI writing tropes.

community

affaan-m/crosspost

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

community

affaan-m/x-api

X/Twitter API integration for posting tweets, threads, reading timelines, search, and analytics. Covers OAuth auth patterns, rate limits, and platform-native content posting. Use when the user wants to interact with X programmatically.

community

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

community