Find Companies Using Node.js: Technographic API Guide

June 21, 2026 · 11 min read

Node.js powers a huge share of modern backends, from solo-founder SaaS products to the API tier of large engineering organizations. A company that ships a Node.js backend is telling you something specific: they have JavaScript engineers, they likely run a single-language stack across front end and back end, and they make deliberate runtime choices. That makes “built with Node.js” one of the more useful buying signals you can detect from the outside—if you can detect it reliably.

That “if” is the whole problem. Node.js is genuinely harder to fingerprint than a CMS, because it is a runtime, not a page generator. This guide explains exactly how Node.js detection works, why the X-Powered-By and Express headers matter so much, how to verify a single domain by hand, and how to turn a raw domain list into a Node.js-confirmed lead list with the DetectZeStack API.

Why Find Companies Using Node.js?

Technographic data—what technology a company runs—is a stronger qualifier than firmographics alone for many products. A confirmed Node.js backend tells you several things at once:

The same pipeline applies to any detectable technology. We have companion guides for finding companies using Nginx and finding companies using Stripe—the filter changes, the workflow stays the same.

How Node.js Is Detected on a Website

Detecting Node.js from the outside is an exercise in reading indirect evidence. The runtime does not introduce itself; the framework sitting on top of it usually does.

The X-Powered-By and Express Header Signals

The single most reliable Node.js signal is the X-Powered-By response header set by Express, the dominant Node.js web framework. By default Express adds:

X-Powered-By: Express

Express runs only on Node.js, so this header is a transitive confirmation of the runtime. DetectZeStack fingerprints Express from exactly this header and then adds Node.js by implication—Express in the technology list always brings Node.js with it. You can spot the raw header yourself with a single command:

$ curl -sI https://example.com | grep -i "^x-powered-by"
X-Powered-By: Express

A handful of other frameworks emit their own telltale headers (for example, some Sails.js and Koa setups), but Express is by far the most common header-level signal you will encounter in the wild.

Why Node.js Is Harder to Detect Than a CMS

A CMS makes detection easy by stamping fingerprints into every page it serves. WordPress leaves a meta generator tag, wp-content/ asset paths, and predictable theme files—see our guide on checking if a website uses WordPress. Node.js leaves none of that, because it does not generate markup on its own. It serves whatever the application code emits, which means there is no default HTML signature to match.

So detection leans on two indirect routes:

The honest limitation: if a site sets none of these—a bare Express app with app.disable('x-powered-by'), served as a pure JSON API behind a proxy that strips headers—there may be no external signal at all. Absence of a Node.js detection is not proof the company does not run Node.js; it is an unknown. We come back to how to handle those cleanly below.

SignalExampleWhat It Tells You
X-Powered-By header X-Powered-By: Express Express confirmed → Node.js implied
Next.js build markers /_next/static/… Next.js confirmed → Node.js implied
Nuxt.js markers __NUXT__ / /_nuxt/ Nuxt.js confirmed → Node.js implied
No Node signal (headers stripped) Unknown — not a confirmed miss

Manual Detection with curl Headers

For a single domain, header inspection takes one command. Fetch just the response headers and read them:

$ curl -sI https://example.com
HTTP/2 200
content-type: text/html; charset=utf-8
x-powered-by: Express
cache-control: public, max-age=0
etag: W/"1f9-..."
date: Sat, 21 Jun 2026 14:02:11 GMT

The x-powered-by: Express line is your confirmation. If you do not see it, check the page source for a framework marker before concluding anything—a quick way is to grep the HTML for Next.js or Nuxt.js fingerprints:

$ curl -s https://example.com | grep -o "/_next/static" | head -1
/_next/static

This works fine for one or two domains. It does not scale to a prospect list of hundreds, it does not resolve framework implications for you, and it makes you eyeball every response. That is what the API is for.

Building a Node.js Lead List at Scale with the DetectZeStack API

The DetectZeStack API runs the full detection pass—HTTP headers and body fingerprints, DNS records, and TLS certificates—in a single call and returns structured JSON you can filter in a script. Header-matched technologies like Express come back at confidence 100, and every implied technology (Node.js included) rides along in the same technologies array.

Single-Domain Check with /demo

You can try it right now against the public demo endpoint, no API key required. The demo is IP-rate-limited, so use it for spot checks rather than bulk scans:

$ curl -s "https://detectzestack.com/demo?url=example.com" \
  | jq '.technologies[] | select(.name == "Express" or .name == "Node.js")'
{
  "name": "Express",
  "categories": ["Web frameworks", "Web servers"],
  "confidence": 100,
  "description": "Express is a web application framework for Node.js.",
  "website": "https://expressjs.com",
  "icon": "Express.svg",
  "source": "http",
  "version": "",
  "cpe": ""
}
{
  "name": "Node.js",
  "categories": ["Programming languages"],
  "confidence": 100,
  "description": "Node.js is an open-source, cross-platform JavaScript runtime environment.",
  "website": "https://nodejs.org",
  "icon": "Node.js.svg",
  "source": "http",
  "version": "",
  "cpe": ""
}

Two entries come back from one header. Express is matched directly off X-Powered-By and categorized as a web framework and web server; Node.js is added by implication under Programming languages. Both carry source: "http" because the evidence came from the HTTP response. The version fields are empty here—Express does not advertise its version in the default header, and Node.js is inferred rather than read off a version string.

Single-Domain Check with /analyze

When you want the full stack for a domain (not just a filtered slice), call /analyze with your API key. The complete response is shaped like this:

$ curl -s "https://detectzestack.p.rapidapi.com/analyze?url=example.com" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com"
{
  "url": "https://example.com",
  "domain": "example.com",
  "technologies": [
    {
      "name": "Express",
      "categories": ["Web frameworks", "Web servers"],
      "confidence": 100,
      "description": "Express is a web application framework for Node.js.",
      "website": "https://expressjs.com",
      "icon": "Express.svg",
      "source": "http",
      "version": "",
      "cpe": ""
    },
    {
      "name": "Node.js",
      "categories": ["Programming languages"],
      "confidence": 100,
      "description": "Node.js is an open-source, cross-platform JavaScript runtime environment.",
      "website": "https://nodejs.org",
      "icon": "Node.js.svg",
      "source": "http",
      "version": "",
      "cpe": ""
    }
  ],
  "categories": {
    "Web frameworks": ["Express"],
    "Web servers": ["Express"],
    "Programming languages": ["Node.js"]
  },
  "meta": { "status_code": 200, "tech_count": 2, "scan_depth": "full" },
  "cached": false,
  "response_ms": 1842
}

The top-level categories map groups every detection so you can pull all programming languages with .categories["Programming languages"] without iterating the array. The meta object carries the HTTP status_code, the tech_count, and the scan_depth; response_ms and cached sit at the top level.

One field to watch for list building is meta.scan_depth. A value of "full" means the HTTP fetch succeeded and header and body detection ran. A value of "partial" means the site blocked or timed out the HTTP request and only DNS and TLS layers completed—in that case an absent Express or Node.js entry tells you nothing, and the domain belongs in a retry queue rather than your rejects file.

Batch Scanning a Prospect List with /analyze/batch

For list building, POST /analyze/batch accepts up to 10 URLs per request and analyzes them concurrently. Each entry in the response carries either a full analysis result or an error for domains that could not be fetched:

$ curl -s -X POST "https://detectzestack.p.rapidapi.com/analyze/batch" \
  -H "X-RapidAPI-Key: YOUR_KEY" \
  -H "X-RapidAPI-Host: detectzestack.p.rapidapi.com" \
  -H "Content-Type: application/json" \
  -d '{"urls": ["example.com", "nextjs.org", "wordpress.org"]}'

The response wraps one result object per URL, each with the same shape as a single /analyze response:

{
  "results": [
    { "url": "example.com",   "result": { "...full analysis..." : "" } },
    { "url": "nextjs.org",     "result": { "...full analysis..." : "" } },
    { "url": "wordpress.org",  "result": { "...full analysis..." : "" } }
  ],
  "total_ms": 2341,
  "successful": 3,
  "failed": 0
}

Because each result matches the single-domain shape, the filtering logic is identical whether you scan one domain or a thousand. For a deeper treatment of batch throughput, retries, and a production Python scanner, see how to batch scan 1,000 websites.

From Domain List to Node.js-Confirmed Leads (Full Walkthrough)

Here is a complete, copy-pasteable pipeline using nothing but bash, curl, and jq. It reads domains.txt (one domain per line), sends batches of 10 to /analyze/batch, and appends every domain where Node.js is detected (directly or by implication) to nodejs_leads.csv, recording which framework triggered the match:

#!/usr/bin/env bash
# find-nodejs.sh — filter a domain list down to Node.js-confirmed leads
KEY="YOUR_KEY"
HOST="detectzestack.p.rapidapi.com"

echo "domain,node_framework,tech_count" > nodejs_leads.csv

# Process domains.txt in batches of 10 (the /analyze/batch maximum)
xargs -n 10 < domains.txt | while read -r batch; do
  urls=$(printf '%s\n' $batch | jq -R . | jq -s '{urls: .}')
  curl -s -X POST "https://$HOST/analyze/batch" \
    -H "X-RapidAPI-Key: $KEY" \
    -H "X-RapidAPI-Host: $HOST" \
    -H "Content-Type: application/json" \
    -d "$urls" |
  jq -r '.results[]
    | select(.result != null)
    | . as $r
    | select([$r.result.technologies[].name] | index("Node.js"))
    | ([$r.result.technologies[].name]
        | map(select(. == "Express" or . == "Next.js" or . == "Nuxt.js" or . == "Koa"))
        | (.[0] // "Node.js")) as $framework
    | [$r.result.domain, $framework, ($r.result.meta.tech_count | tostring)]
    | @csv' >> nodejs_leads.csv
done

wc -l nodejs_leads.csv

A 1,000-domain list becomes 100 batch calls. The index("Node.js") guard keeps a domain whenever Node.js appears—whether it was matched off the Express header or implied by a Next.js or Nuxt.js fingerprint—and the $framework expression records which technology drove the match, so your lead list segments cleanly into Express APIs versus Next.js front ends. Domains that failed to resolve appear with an error field instead of a result, and select(.result != null) skips them.

Filtering and Enriching Your Node.js Lead List

A raw “runs Node.js” flag is a starting point, not a finished lead. The framework that triggered the match is where the real segmentation lives, because each one implies a different buyer:

Framework DetectedImpliesLikely Profile
Express Node.js Custom backend / REST or JSON API tier
Next.js Node.js, React Modern full-stack React team, often product-led SaaS
Nuxt.js Node.js, Vue.js Vue-based full-stack team
Koa Node.js Smaller, opinionated backend team

Because frameworks like Next.js also imply their front-end library (React or Vue.js), a single scan often hands you the full stack in one shot. If you want to segment by the front-end layer specifically, our guide on detecting the JavaScript framework of a website covers reading those fingerprints, and how to detect a Next.js website goes deep on the Next.js markers in particular.

Two practical enrichment moves once the list is built:

Get Started

The free tier includes 100 requests per month with no credit card—enough to validate the pipeline on a sample of your prospect list before scaling up. Sign-up is instant through RapidAPI:

  1. Get a key at rapidapi.com/mlugoapx/api/detectzestack.
  2. Spot-check a domain you know: curl -s "https://detectzestack.com/demo?url=yourdomain.com" | jq '.technologies[].name'
  3. Run the batch script above against your first 100 domains.

Finding companies built with Node.js comes down to reading indirect evidence well: the X-Powered-By: Express header, the framework fingerprints that imply the runtime, and honest handling of the domains where nothing leaks. A single /analyze call answers the one-domain question; /analyze/batch turns a raw domain list into a Node.js-confirmed lead list with the triggering framework attached; and meta.scan_depth tells you which negatives are real and which are unknowns worth a retry. Swap the jq filter and the same pipeline segments by CMS, payment processor, or web server instead.

Related Reading

Try DetectZeStack Free

100 requests per month, no credit card required. Header, DNS, and TLS detection included on every plan.

Get Your Free API Key

Get API updates and tech detection tips

Join the mailing list. No spam, unsubscribe anytime.