Skip to main content

Domain scanning

A vendor's customer hostnames show up in public Certificate Transparency logs. Scan an ERP or accounting apex, drop the vendor's own infrastructure names, then look up each remaining label until it resolves to a company. That company is a customer of the scanned vendor. It is not yet a Naologic prospect.

The hostname is an installed-base hypothesis. It is not proof of a problem, a buying process, or a system of record we may state on a call. Qualification against market, vertical, size, and sites still has to happen. Enrichment never becomes that proof. See Sales stack.

Context​

Use this page when the job is to build a list from who already runs a named system, not from NAICS alone. Certificate Transparency is one digital artifact for that job. It sits beside job-post system names (SG_016) and the audience systems_of_record dimension in variables.yaml.

Do not use this page as a generated GTM guide, a competitor profile, or a canonical signal record. A scan hit does not create an account in Salesforce until a person accepts the match.

The original working notes on this page were:

  • Query crt.name for an apex such as slack.com or salesforce.com
  • Get the domain, crawl the page, qualify it
  • Enumerate ERPs, including products that are winding down (QuickBooks Desktop)
  • Use our competitor list as seeds
  • Pin whatever else reveals installed base

Those notes are the seed. The rest of this page is the descent.

Guidance​

1. High altitude — why this works​

Multi-tenant vendors issue TLS certificates for hostnames of the form {tenant}.{vendor-apex}. Those names are logged in Certificate Transparency. The leftmost label is often the customer's brand, a slug of their name, or a vanity they chose at signup.

That gives us a question we can ask before a call: "this establishment appears on {vendor}'s certificate set." It does not give us the answer to "they have problem P." It does not give us the right to say they use that system today — certs linger, partners appear, and test tenants exist.

Three consequences follow:

  1. Scan vendors, not industries. The industry filter happens after lookup.
  2. The vendor is already a systems_of_record hypothesis. Record it as unverified until a website, job post, or the buyer confirms it.
  3. Slack and Salesforce in the notes are method examples. Their tenant sets are huge and mostly off ICP. Scan them to learn the API. Do not treat the dump as a manufacturing list.

2. Middle altitude — what to pin​

Build a vendor apex catalog before scanning. "Every ERP on earth" is a research backlog, not a one-shot extract. Prefer sources we already own, then widen.

Class A — displacement systems we already name. Map each catalog value in variables.yaml system_of_record to one or more public apexes we can query. The catalog order is the displacement priority. Hostnames are a hypothesis that the named class is present, not a completed systems_of_record list.

Catalog valueWhy it mattersCT scanNotes
spreadsheetsCommon with QuickBooks on M1 audiencesNoNo tenant hostname
quickbooksLedger many plants will not leavePartialOnline and hosted products may appear under Intuit / QuickBooks apexes. Desktop does not look like {shop}.quickbooks.com
industry_specificIncludes manufacturing ERPs such as Global ShopYes, per product apexConfirm the product's real SaaS hostname, not the marketing site only
sageAccounting / ERP displacementYes, per productMultiple products, multiple apexes
epicorManufacturing ERPYes, per cloud product
inforManufacturing ERPYes, per cloud product
dynamicsMicrosoft business appsYes, per cloud product
netsuiteUpper-middle displacementYes
sapUsually out of our size bandYesStill useful as a negative filter after lookup
custom_builtHomegrownNoUse job posts and the website
unknownNo system identity yetn/aDo not invent a value from a weak slug

Class B — deprecating products. A sunset (QuickBooks Desktop, an old on-prem SKU) is a reason they might move, not a CT shape. Confirm the vendor's current lifecycle page before anyone says "Desktop is going away" on a call. Pair the sunset with another artifact: job posts, community threads, or a buyer sentence. Do not use deprecation as urgency theater.

Class C — named competitors. Start from Competitors. Today that is Global Shop. Add an apex only when we know the product's customer-hostname pattern. Audience competitor_ids still require account or buyer confirmation before competitive language goes on a call.

Class D — adjacent SaaS, method and spillover. FreshBooks, Xero, and similar accounting hosts produce noisy tenant dumps. The working dump in f.md is a FreshBooks harvest: thousands of {label}.freshbooks.com names, mixed with vendor infrastructure (careers, status, support). Use it to test the parser. Do not confuse a FreshBooks tenant with a plastics plant.

Class E — method drills. slack.com and salesforce.com on crt.name show the query shape. They are not M1 seeds.

What else to pin (only if it reveals installed base):

  • Job posts that name a system (SG_016)
  • Careers pages and integration directories on the company's site after lookup
  • Partner locators and "customer stories" on the vendor site (separate from CT; treat as marketing, not a cert)
  • DNS and MX that still point at a vendor after the company domain is known

Do not pin: employee personal blogs, parked slugs, or anything that requires logging into the vendor product.

3. Low altitude — the scanner​

The scanner is one machine. Vendor apexes go in. Company candidates come out. Nothing in the machine is allowed to mark qualification as list_candidate without the lookup and ICP steps.

3.1 Inputs​

  • seed_apexes[] — vendor hostnames, each with class (displacement | deprecating | competitor | adjacent | method) and optional system_of_record catalog value
  • vendor_label_denylist — leftmost labels that are the vendor, not a customer
  • rate_limit — wait between crt.name calls and between company crawls

3.2 Harvest​

For each apex in seed_apexes:

GET https://crt.name/v1/search?apex={apex}

Worked method URLs:

  • https://crt.name/v1/search?apex=slack.com
  • https://crt.name/v1/search?apex=salesforce.com

Parse every certificate name in the response into FQDNs. Keep names that are exactly {label}.{apex} or {label}.www.{apex} only if the extra label is empty of meaning. Drop wildcards that add no tenant (*.{apex} with no deeper name). Deduplicate case-insensitively.

If the HTTP body is HTML instead of a name list, stop and record the parse failure. Do not invent hostnames.

3.3 Split vendor from tenant​

Take the leftmost label. Drop it when it matches the denylist or a pattern that is almost never a company.

Always drop (vendor infrastructure): www, mail, email, api, app, apps, cdn, static, assets, img, images, m, mobile, go, login, sso, auth, secure, ssl, vpn, remote, admin, portal, status, health, monitor, dev, devel, developer, developers, docs, doc, help, support, kb, community, forum, blog, news, careers, jobs, partners, partner, sandbox, staging, stage, test, testing, qa, uat, demo, demos, trial, preview, beta, alpha, prod, production, internal, intranet, localhost.

Also drop: labels shorter than three characters; pure numerics; labels that are the vendor brand (freshbooks, salesforce, slack); hyphenated vendor product names you have listed (woodstitch-billing style only if you have confirmed they are vendor SKUs — when unsure, send them to lookup with match_confidence: guessed).

Everything left is a tenant candidate: {label, hostname, apex, class}.

The FreshBooks dump in f.md is this step's output before lookup. careers.freshbooks.com is vendor. lemonproductions.freshbooks.com is a tenant candidate.

3.4 Lookup — identify the customer of that vendor​

The harvest does not know the company's legal name or its own website. Lookup is a waterfall. Stop at the first website_confirmed or zoominfo_confirmed hit. Otherwise keep guessed and move on. Never skip to Salesforce on guessed alone.

Step A — tenant page (optional, shallow). GET https://{hostname}/ with a browser-like user agent, no login, no form post. Read title, og:site_name, visible company name. If the page is a generic vendor login with no customer name, record tenant_page: vendor_shell and continue. Do not follow into the authenticated app.

Step B — slug as a corporate domain. DNS lookup for {label}.com, then .net, .io, .co only if .com is empty. If an A/AAAA or CNAME exists, fetch the site home page. Compare the visible name to the label (normalized: strip llc, inc, hyphens). On a plausible match, set company_domain and match_confidence: website_confirmed.

Step C — search. Query the open web and, when available, ZoomInfo for the label as a company, plus the vendor name as context only in internal notes. Prefer a match that also shows manufacturing, plastics, or a plant — but do not require it yet. ZoomInfo is for identity, size, and phones. It is not proof of a problem.

Step D — crawl the company's own site (the domain from B or C, never the vendor apex). Collect: legal or trade name, locations, what they make or serve, any named systems on careers or integration pages. This is the "get the domain, crawl the page" line from the original notes.

Step E — identity record. Write one hit per tenant candidate:

kind: domain_scan_hit
apex: freshbooks.com
hostname: lemonproductions.freshbooks.com
tenant_label: lemonproductions
vendor_class: adjacent
system_of_record_hypothesis: null
company_name: null
company_domain: null
match_confidence: guessed | website_confirmed | zoominfo_confirmed
tenant_page: vendor_shell | named | error | skipped
qualification: unevaluated
notes: []

system_of_record_hypothesis may be filled only with a variables.yaml system_of_record value, or left null. Do not invent a new catalog token because the apex was FreshBooks. Adjacent accounting hosts stay null until a person maps them (often still unknown on the audience, with the vendor name only in notes).

3.5 Qualify — still not a prospect​

Qualification is a separate pass over hits with match_confidence other than empty. Use the same gates list-building already uses, for the market you are filling. For the active vertical core that means the audience filters, not a vibe. Example from M1_V2-P1-A01: process (plastic injection molding), size bands, single site, spreadsheets and QuickBooks as systems holding part of the operating record.

For each identified company:

  1. Process / industry. Does the site describe a process we have a vertical for? NAICS in ZoomInfo is a list-building aid, not the result. See Market verticals.
  2. Size and sites. Headcount and location_footprint remain unknown until checked. Multi-site changes problem selection (SG_022).
  3. Age / operating debt. SG_025 still gates audiences that assume a system to displace.
  4. Systems. The scan is one artifact that a vendor relationship existed. Confirm or leave unknown. Job posts that name a system are a second artifact (SG_016).
  5. Set qualification. out_of_scope (wrong process, too small, SAP-only global, etc.), list_candidate (passes the audience filters you are filling), or leave unevaluated if lookup failed.

A FreshBooks designer shop and a 40-person molder can share a hostname shape. Only step 3.5 tells them apart.

3.6 Handoff​

For list_candidate only:

  • Create or match the account in Salesforce. Store the hostname and apex in internal notes, not in outbound copy.
  • Enrich contacts in ZoomInfo. Verify before outreach.
  • Do not write competitive or "you use X" language until the system is confirmed on the site, a job post, or the call.
  • Do not auto-bind competitor_ids or systems_of_record on the audience YAML from a scan.

4. Running the scanner (agent or person)​

Run in this order. Do not look up before the denylist. Do not qualify before identity.

  1. Load seed_apexes for this run (one class is enough; method drills stay off the production list).
  2. Harvest and write raw names next to the apex (a dump like f.md is acceptable as raw harvest, not as a target list).
  3. Apply the denylist. Count dropped vs kept.
  4. For each kept tenant, run lookup A→D until confirmed or the slug is exhausted.
  5. Qualify confirmed companies against one audience at a time.
  6. Hand off list_candidate rows. Leave guessed and unevaluated in the scan file.

Rate-limit crt.name and company sites. Prefer public pages. Never use a customer login, a stolen cookie, or a product exploit to expand a tenant list. Certificate Transparency is the allowed source for names.

5. What this is not​

  • Proof that the company has P_00010 or any other canonical problem.
  • Permission to say on a call that they run Global Shop, QuickBooks, or Salesforce.
  • A complete ERP encyclopedia. Class A–C are the working seed; "all ERPs on earth" is ongoing catalog work.
  • A substitute for ZoomInfo phone numbers or Salesforce ownership rules.
  • Urgent outreach because a product is "deprecated." Confirm lifecycle, then speak plainly.

Evidence and sources​

  • Method. crt.name Certificate Transparency search by apex. Example queries in the original notes: apex=slack.com, apex=salesforce.com.
  • Raw harvest example. f.md — FreshBooks leftmost labels, mixed vendor infrastructure and tenant candidates. Not a qualified list.
  • System vocabulary. variables.yaml system_of_record.
  • Signal vocabulary. SG_016 (named system in job posts), SG_022 (multi-site), SG_025 (age / operating debt).
  • Enrichment rule. Sales stack — do not treat enrichment as proof of a buyer problem.
  • Competitor seed. C_00001_GLOBAL_SHOP.

Change log​

  • 2026-08-31 — Linked Research for non-CT customer and vendor URL methods.
  • 2026-08-22 — Expanded from working notes into a high-to-low scanner: vendor seeds, crt.name harvest, tenant denylist, company lookup waterfall, ICP qualification, Salesforce handoff. Original crt.name URLs kept as method examples.