DOCUMENTATION

Evidence you can inspect.

Learn the CLI, understand every confidence level, and run careful public DNS research at scale.

These docs cover vendorprint 0.5.0 on npm, including the current signatures and package-version metadata. Use npx vendorprint@0.5.0 example.com to pin this release.

Get started

Quickstart

Node.js 20 or newer is the only runtime requirement. Run vendorprint directly from npm without installing it globally.

Terminal
npx vendorprint@latest example.com

Keep the command installed

Install vendorprint globally when you use it regularly. The default output shows only observed technologies and their evidence.

Terminal
npm install --global vendorprint
vendorprint example.com
DNS only

vendorprint queries the configured recursive DNS resolver. It does not request company websites, tracking endpoints, login pages, or application APIs.

Company research

Use vendorprint with your AI agent

Install a reusable skill for company technographics. It gives your agent a workflow for scanning public DNS and interpreting vendor evidence.

Use a compatible coding agent with shell access, such as Codex, Claude Code, or Cursor. The skill runs the published vendorprint@0.5.0 scanner locally without a VendorPrint account or API key.

Install the skill
npx skills add danahmadi/vendorprint_cli --skill vendorprint

Run this in your project and choose your agent in the installer. The skills CLI currently requires Node.js 22.20 or newer. The scanner itself requires Node.js 20 or newer and network access to public DNS; the first run downloads it from npm. Start a new agent session if the installed skill is not yet visible.

Prefer a manual setup? Copy the entire skill folder from GitHub, including its references, into your agent's supported skills directory.

Research a company

Example prompt
Use vendorprint to research example.com's software stack.
Show the evidence, confidence, and what remains unknown.

Replace example.com with the company domain. The agent returns the observed email and SaaS signals, their evidence, observation time, and any incomplete checks.

Enrich an account list

Example prompt
Use vendorprint to enrich the domains in accounts.txt with
DNS-visible technology signals. Save the results with their
evidence and flag partial scans.

Supply a text file with one domain per line. The skill includes guidance for JSON and NDJSON output, resuming interrupted batches, and using the Node.js library in your own application.

Keep the meaning of the evidence

The skill distinguishes ownership records, email authorization, and platform configuration. It preserves inferred findings and partial scans. A missing signal is inconclusive; a positive record does not prove active usage, paid seats, or subscriptions.

Read the skill instructions or see the skills CLI documentation.

CLI

Command reference

Use positional domains for quick scans, or file and stream inputs for larger jobs.

Input

--input <path>
Read newline, comma, or space-separated domains.
--stdin
Read domains from standard input.
--labels <a,b,c>
Add known candidate tracking labels.
--preserve-hostname
Scan the supplied hostname instead of its base domain.

Coverage and safety

--mode <value>
Choose full, balanced, or fast. Full is the default.
--dns-transport <kind>
Use native DNS (default), or https for Google DNS-over-HTTPS on restricted networks. Company websites are never requested.
--timeout <ms>
Set the DNS attempt timeout. Default: 1800.
--concurrency <n>
Set concurrent domains. Default: 4. Maximum: 12.
--max-inflight-dns <n>
Set the global attempt ceiling. Default: 32.
--qps <n>
Limit DNS attempt starts per second. Default: 100.
--ct
Add bounded, opt-in certificate-transparency labels before DNS validation.
--ct-cache <path>
Reuse and update a local certificate discovery cache.

Output

--full
Include raw DNS, searched labels, query budgets, and diagnostics.
--findings-only
Legacy alias for the default result-first output.
--format <value>
Choose JSON or streaming NDJSON.
--output <path>
Write to a new file instead of stdout.
--pretty
Retained for compatibility. Scan JSON is formatted by default.

Diagnostics and resume

--include-unclassified
Include generic verification-like TXT diagnostics.
--resume <path>
Append remaining results to an NDJSON checkpoint.
--help
Print usage, options, and exit codes.

Exit codes

0Scan completed. Individual domains may still contain DNS errors.
1The CLI input was invalid.
Normalization

Domain inputs

URLs and hostnames normalize to the registrable company domain using the Public Suffix List. Exact input hostnames are retained as prioritized CNAME candidates, alongside the base hostname and www.

Input https://www.example.co.uk/pricing
Scanned domain example.co.uk

Use --preserve-hostname when a delegated hostname is intentionally the scan target; its own CNAME is also queried. Invalid inputs are retained under invalidInputs instead of silently disappearing.

Bring discovered hostnames

Keep per-company hostname hints in a JSON file, for example {"example.com": ["try.example.com", "join.campaign.example.com"]}. Run vendorprint example.com --hostname-hints hosts.json, or pass the same map as hostnameHintsByDomain to the library.

Hints must belong to the specified scan domain and augment requested accounts. Nested names receive wildcard controls. All queries share the 80-attempt budget; skipped hostnames remain visible in completeness diagnostics. Start a new output file after changing hints or package version because resume skips already-completed domains.

JSON

Output model

Result-first output keeps observed technologies, confidence, evidence, and caveats. Reports and NDJSON metadata/summary events also retain packageVersion and signatureCatalogVersion for reproducibility. Each fresh result includes observedAt and scanCompleteness. Empty categories and detailed scan internals stay out of the way.

Shape
{
  "findings": [{
    "domain": "example.com",
    "status": "ok",
    "observedAt": "2026-10-15T12:00:00.000Z",
    "scanCompleteness": {
      "status": "partial",
      "scope": "bounded_checks",
      "reasons": ["query_budget"],
      "queryAttempts": 80,
      "queryLimit": 80,
      "skippedHostnames": 2,
      "queriesSkippedDueToBudget": 1,
      "dnsErrors": [],
      "interpretation": "Completeness describes the bounded scan plan, not all possible DNS names or vendor usage. Absence remains inconclusive."
    },
    "email": {
      "provider": "Google Workspace",
      "confidence": "high"
    },
    "technologyProfile": {
      "crm": [{
        "provider": "Salesforce",
        "confidence": "high",
        "relationshipLevel": "platform_configuration",
        "evidence": [{
          "type": "cname",
          "hostname": "support.example.com",
          "target": "tenant.force.com"
        }],
        "caveat": "Configuration does not prove active seats."
      }]
    }
  }]
}
Completeness and confidence answer different questions

status: "ok" describes DNS response availability. scanCompleteness.status reports whether the bounded plan finished. Partial scans expose query-budget limits, DNS errors, SPF lookup limits, CNAME depth limits, or optional discovery errors. A partial scan can still contain high-confidence positive evidence. Even a complete bounded scan cannot prove a vendor is absent.

Identity

domain, status, and normalized input diagnostics.

Observed technology

Mail routing, ownership proofs, sending authorization, CNAME services, and sales engagement.

Derived technology

Normalized categories include explicit inferred findings. Add --full to inspect unresolved candidate sets.

Operational evidence

Add --full for query budgets, searched labels, retries, raw DNS, and wildcard diagnostics.

Catalog

Signature maintenance

Inspect the versioned catalog, find recurring unknown records offline, and compare two scan snapshots.

Terminal
vendorprint --input accounts.txt --full --include-unclassified --format ndjson --output findings.ndjson
vendorprint signatures --pretty
vendorprint signatures audit findings.ndjson --pretty
vendorprint diff before.json after.json --pretty

Use full output with --include-unclassified for complete audits. Audit schema 1.1 counts distinct domains and includes unknown MX, nested SPF targets, CNAME targets, and redacted TXT keys. Audit output contains aggregate unknown prefixes and target domains only. It excludes account domains and verification tokens, and it performs no network requests.

What the catalog covers

Browse the searchable signature catalog and benchmarks for GTM tools, trust centers, identity providers, and business software. Vanta, SafeBase, and Drata signals identify trust-center hosting. Fireflies and Read AI TXT records identify published domain relationships. Gong Engage link tracking does not identify general call recording. Snowflake domain verification does not establish warehouse usage. Smartsheet, Dynatrace, TeamViewer, and Adobe Acrobat Sign TXT rules identify domain relationships, not active subscriptions or completed verification.

Every mode checks the base CNAME, supplied hostnames, and www, then additional labels as the budget permits. Full mode has 50 additional labels. Fast has 11, including trust; balanced has 27, including trust, security, and trustcenter. All modes retain the 80-attempt cap. More labels can leave less budget for adaptive follow-ups.

Confidence

Evidence and inference

vendorprint separates direct observations from derived relationships and unresolved candidates.

DirectObserved in DNS

A vendor-owned MX or CNAME target, or a self-identifying ownership proof.

InferredDerived by a named rule

A product dependency or suite relationship, with rationale and caveats attached.

CandidatePossible, not asserted

A non-exhaustive set that may be prioritized by independent corroborating evidence.

Relationship levels

platform_configuration

An attributable custom hostname points to vendor infrastructure.

domain_relationship

A vendor-specific TXT record proves that domain ownership was configured.

sending_authorization

SPF authorizes a service to send mail but does not prove broader product use.

Absence is not proof

DNS cannot list arbitrary subdomains. Proxies, disabled branded tracking, and customer-selected labels can hide an otherwise active product.

Streaming

Batch scanning

Use NDJSON for long-running jobs. Each completed domain is appended immediately and becomes a durable checkpoint.

Terminal
vendorprint --input accounts.txt \
  --format ndjson \
  --output findings.ndjson

Resume after interruption

Terminal
vendorprint --input accounts.txt \
  --resume findings.ndjson

Resume skips normalized domains already present, tolerates one partial final line, and appends only remaining results. New output files are created without overwriting an existing file.

Node.js

Library API

Import the scanner without invoking the CLI, or consume completion-order events as an async iterator.

JavaScript
import { scanDomains } from "vendorprint";

const report = await scanDomains(["example.com"], {
  concurrency: 4,
  maxInflightDns: 32,
  qps: 100,
});
Streaming JavaScript
import { scanDomainEvents } from "vendorprint";

for await (const event of scanDomainEvents(domains)) {
  process.stdout.write(`${JSON.stringify(event)}\n`);
}
Operating policy

Responsible use

Keep the evidence attached, preserve unknown values, and use the built-in DNS limits.

What it does

  • Queries public DNS through the configured recursive resolver.
  • Checks a bounded set of records and candidate hostnames.
  • Redacts ownership tokens while retaining provider identity.
  • Reports confidence, evidence, and caveats together.

What it does not do

  • Request company websites or vendor tracking endpoints.
  • Attempt DNS zone transfers or arbitrary subdomain brute force.
  • Bypass authentication, access controls, or rate limits.
  • Prove that a subscription or employee seat is active.

Only research domains you are permitted to process. Follow applicable law, provider terms, data-governance rules, and retention policies.

Boundaries

Limits and caveats

These constraints protect the resolver and keep downstream decisions honest.

80 DNS attempts maximum per domain
4 Logical queries in flight per domain
32 Global in-flight attempts by default
100 DNS attempt starts per second by default

Stale records

A configured record can remain after a tool is no longer actively used.

Hidden targets

Cloudflare and other proxies can hide the vendor-owned CNAME target.

Wildcard DNS

Wildcard-like answers are collapsed so repeated guesses do not inflate evidence.

Product scope

A platform relationship does not prove a specific module, plan, seat, or recent activity.

Ready to inspect a domain?

Open the interactive demo