DEV Community

MikeL
MikeL

Posted on Originally published at detectzestack.com

Find Companies Using Java: Detection Signals and API

Java runs a large share of enterprise web backends: banks, retailers, airlines, telecoms, and most of the big content management platforms. If you sell Java tooling, application security, JVM monitoring, or migration services, a list of companies using Java is a list of prospects. The problem is that Java is not in the page. It runs on the server, and the HTML it produces looks like any other HTML.

This guide covers the signals that do leak out of a Java backend, exactly which of them DetectZeStack matches (and which it does not), and how to turn a domain list into a Java prospect list with a few API calls. The API responses and headers quoted below came from real requests made while writing this post.

Why Finding Companies Using Java Is Harder Than Front-End Tech

Front-end libraries announce themselves. A site that uses jQuery has a <script> tag pointing at a jQuery file, and anyone can read it. A site that uses Java has a JVM somewhere behind its load balancer, and the only trace in the response is whatever the application server, framework, or CMS happens to add to it.

Java Runs on the Server, So Detection Relies on Indirect Signals

Every Java detection is an inference from a side effect: a session cookie the servlet container sets, a header the application server stamps on responses, or a product that is known to be built on Java. That makes Java detection different in two ways. First, the signal is often in the headers, not the HTML. Second, it can disappear without the backend changing at all, because a proxy in front of the application stripped it.

Signals That a Website Runs on Java

These are the signals worth knowing, in rough order of how often you will see them. The table at the end of this section shows which ones DetectZeStack's HTTP scan actually matches.

JSESSIONID Session Cookies

JSESSIONID is the default session cookie name in the Java Servlet specification, so Tomcat, Jetty, WildFly, WebLogic, WebSphere and most other servlet containers use it unless the application renames it. It is the single most common Java signal. You can check for it with one command:

curl -s -o /dev/null -D - https://confluence.atlassian.com | grep -i '^set-cookie: jsessionid'
Enter fullscreen mode Exit fullscreen mode

When we ran it, Atlassian's Confluence site answered with set-cookie: JSESSIONID=AE599AB7...; Path=/; Secure; HttpOnly. Confluence is a Java application, and the cookie gives it away even though the Server header just says AtlassianEdge.

Server and X-Powered-By Headers (Apache Tomcat, Jetty, JBoss/WildFly, Servlet/JSP)

Application servers that are not hidden behind a proxy often identify themselves:

  • Server: Apache-Coyote/1.1 is Tomcat's HTTP connector.
  • Server: Jetty(9.4.51.v20230217) is Eclipse Jetty, with a version.
  • X-Powered-By: Servlet/3.0 JSP/2.2 is added by several Java EE servers and names the spec versions.
  • X-Powered-By: JBoss-7.1 and X-Powered-By: Undertow/1 come from JBoss and WildFly.
  • X-Application-Context is a header older Spring Boot versions added by default.

Check them with curl -sI https://example.com and read the server and x-powered-by lines.

URL Patterns (.jsp, .do, .action, ;jsessionid=)

Java web apps have recognizable URL habits. JavaServer Pages end in .jsp. Apache Struts 1 maps actions to .do and Struts 2 to .action. When a servlet container cannot set a cookie, it rewrites links to carry the session in the path, as in /cart;jsessionid=ABC123. These are good hints when you look at a site by hand, but they are weak on their own, because any server can be configured to serve a path ending in .do.

Framework Traces (Spring, Struts, JSF)

Frameworks leave their own marks. JavaServer Faces pages include a hidden form field named javax.faces.ViewState (or jakarta.faces.ViewState in newer versions). Spring shows up through the X-Application-Context header mentioned above. Vaadin apps load a vaadinBootstrap.js script. And a lot of Java reaches the web through products built on it: Adobe Experience Manager, Liferay, Magnolia CMS, Atlassian Confluence and Jira all run on the JVM.

What Doesn't Count as Java: JavaScript Is Unrelated

JavaScript and Java share four letters and nothing else. A site running React, Angular, or jQuery tells you about its front end, not its backend. When you filter scan results, match on the exact name Java in the Programming languages category. A substring match on "java" will also catch JavaScript libraries and JavaScript frameworks and flood your list with false positives.

Which Signals DetectZeStack Matches

DetectZeStack's HTTP detection uses the open-source Wappalyzer fingerprint set. It fetches the page, reads the headers, cookies and HTML, and does not run JavaScript. We ran each signal above through the same fingerprint library the API uses:

Signal Reported as Also adds Java?
JSESSIONID cookie Java —
Server: Apache-Coyote Apache Tomcat Yes
X-Powered-By: Tomcat-9.0.83 Apache Tomcat 9.0.83 Yes
Server: Jetty(9.4.51...) Jetty 9.4.51 Yes
X-Powered-By: Servlet/3.0 JSP/2.2 Java Servlet 3.0, JavaServer Pages 2.2 Yes
X-Application-Context Spring Yes
Adobe Experience Manager paths (/etc.clientlibs/) Adobe Experience Manager Yes
X-Powered-By: JBoss-7.1 JBoss Application Server 7.1 No
X-Powered-By: Undertow / Server: WildFly not detected No
javax.faces.ViewState hidden field not detected No
.jsp / .do links, ;jsessionid= in URLs not detected No

Three things stand out. Java is usually reported as an implied technology: when the scan finds Tomcat, Jetty, Spring, GlassFish, Resin, Vaadin, Liferay, Magnolia CMS or Adobe Experience Manager, it adds a Java entry next to it. JBoss is the exception: its fingerprint does not imply Java, so check for JBoss Application Server separately. And the URL-pattern and JSF ViewState signals are manual checks only. JavaServer Faces is still detected when a server sends X-Powered-By: JSF/2.2.

Limits of Detecting Java from the Outside

Reverse Proxies, CDNs, and Stripped Headers Hide the Backend

The best illustration is Tomcat's own website. A scan of tomcat.apache.org returns Apache HTTP Server, HSTS, Let's Encrypt and Varnish, and no Java, because the project site is static pages served by Apache httpd. The server you see is whatever sits at the edge.

The same thing happens on the commercial side, where Java backends almost always sit behind Akamai, Cloudflare, Fastly, or an Nginx reverse proxy. The edge replaces the Server header, and home pages often come from a cache that never sets a session cookie. The data shows it. As of the September 24, 2026 snapshot of DetectZeStack's index, 134 domains had Java recorded. 101 of those got there through Adobe Experience Manager, 2 through Spring, and 1 through Jetty. Apache Tomcat, the most widely deployed Java server, appeared on zero indexed domains, because its Apache-Coyote header rarely survives the trip through a CDN.

Detection can also change between scans. American Airlines' www.aa.com is in the index with Java, but a scan while writing this post returned only Akamai, Akamai Bot Manager and HSTS. Bot protection and cache state change what a scanner receives. Treat a Java hit as strong evidence, and treat a miss as "nothing visible this time."

API Example: Detect Java with DetectZeStack

Start with the public /demo endpoint. It needs no API key and is rate-limited by IP:

curl -s "https://detectzestack.com/demo?url=https://www.homedepot.com" | python3 -m json.tool
Enter fullscreen mode Exit fullscreen mode

Full Stack Scan with GET /analyze

For production use, call /analyze with your RapidAPI key. This is the response for Home Depot, trimmed to the Java-related entries, with the categories map and meta block left intact. We had just scanned the site, so it came back from cache with "cached": true and a response_ms of 0. A fresh scan takes a few seconds:

curl -s "https://detectzestack.p.rapidapi.com/analyze?url=https://www.homedepot.com" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com"
Enter fullscreen mode Exit fullscreen mode
{
"url": "https://www.homedepot.com",
"domain": "www.homedepot.com",
"technologies": [
{
"name": "Java",
"categories": ["Programming languages"],
"confidence": 100,
"description": "Java is a class-based, object-oriented programming language that is designed to have as few implementation dependencies as possible.",
"website": "https://java.com",
"icon": "Java.svg",
"cpe": "cpe:2.3:a:oracle:jre:*:*:*:*:*:*:*:*",
"source": "http"
},
{
"name": "Spring",
"categories": ["Web frameworks"],
"confidence": 100,
"website": "https://spring.io/",
"icon": "Spring.png",
"source": "http"
}
],
"categories": {
"CDN": ["Akamai"],
"Caching": ["Varnish"],
"JavaScript frameworks": ["React"],
"Programming languages": ["Java"],
"Reverse proxies": ["Nginx"],
"SSL/TLS certificate authority": ["DigiCert"],
"Security": ["HSTS", "Akamai Bot Manager"],
"Web frameworks": ["Spring"],
"Web servers": ["Nginx"]
},
"meta": { "status_code": 200, "tech_count": 9, "scan_depth": "full" },
"cached": true,
"response_ms": 0
}
Enter fullscreen mode Exit fullscreen mode

How to read it:

  • Spring was matched from the X-Application-Context header, the only Spring rule in the fingerprint set. Java was added because Spring implies it.
  • The stack in front of it is Akamai, Varnish, and Nginx. Java is detected here despite the proxies because the Spring header made it through all three.
  • React sits in JavaScript frameworks. That is the front end, and it is unrelated to the Java entry.
  • Empty fields are left out. Neither entry has a version, and Spring has no cpe, so those keys are missing. In jq, use .version // "".

Other sites show the other routes to a Java entry. www.cisco.com returns Adobe Experience Manager plus Java. bitbucket.org returns Magnolia CMS plus Java, matched from its x-magnolia-registration header. confluence.atlassian.com returns Java alone, from the JSESSIONID cookie.

Yes/No Check with GET /check?tech=Java

If you only need a yes or no, /check takes a tech parameter and returns a flat object with detected, confidence, version, and categories. The name match is case-insensitive:

curl -s "https://detectzestack.p.rapidapi.com/check?tech=Java&url=https://www.cisco.com" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com"
Enter fullscreen mode Exit fullscreen mode

Because JBoss does not imply Java, run a second check with tech=JBoss Application Server (URL-encoded as JBoss%20Application%20Server) if JBoss shops matter to you.

Scan a Prospect List with POST /analyze/batch

To start from domains already in the index, call /lookup?tech=Java. It returns matching domains with first_seen and last_seen timestamps, and the number of results per page depends on your plan:

curl -s "https://detectzestack.p.rapidapi.com/lookup?tech=Java&limit=50" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
| jq -r '.results[].domain'
Enter fullscreen mode Exit fullscreen mode

To check your own list, send up to 10 URLs per request to /analyze/batch. Each URL counts as one request against your quota. Each item nests its analysis under .result, or carries an error string instead:

curl -s -X POST "https://detectzestack.p.rapidapi.com/analyze/batch" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://www.homedepot.com", "https://www.cisco.com", "https://confluence.atlassian.com"]}' \
| jq -c '.results[] | {url: .url, java: ([.result.technologies[]? | select(.name == "Java")] | length > 0)}'
Enter fullscreen mode Exit fullscreen mode

This Python script scans domains.txt in chunks of 10 and writes a CSV that records not just whether Java was found but how, which is what makes the list useful for outreach. "Java via Adobe Experience Manager" and "Java via Spring" are different conversations:

import csv, json, os, urllib.request

KEY = os.environ["RAPIDAPI_KEY"]
URL = "https://detectzestack.p.rapidapi.com/analyze/batch"
JAVA_SOURCES = ["Apache Tomcat", "Jetty", "JBoss Application Server", "GlassFish",
"Spring", "JavaServer Pages", "JavaServer Faces", "Java Servlet",
"Resin", "Vaadin", "Apache Wicket", "Adobe Experience Manager",
"Liferay", "Magnolia CMS", "Atlassian Confluence", "Atlassian Jira"]

domains = [d.strip() for d in open("domains.txt") if d.strip()]
rows = []
for i in range(0, len(domains), 10):
chunk = [d if d.startswith("http") else "https://" + d for d in domains[i:i+10]]
req = urllib.request.Request(URL, data=json.dumps({"urls": chunk}).encode(), headers={
"x-rapidapi-key": KEY,
"x-rapidapi-host": "detectzestack.p.rapidapi.com",
"Content-Type": "application/json",
})
with urllib.request.urlopen(req, timeout=120) as resp:
data = json.load(resp)
for item in data["results"]:
techs = {t["name"]: t for t in (item.get("result") or {}).get("technologies", [])}
via = [n for n in JAVA_SOURCES if n in techs]
if "Java" in techs or via:
rows.append({
"url": item["url"],
"via": "; ".join(via) or "Java only",
"versions": "; ".join(f"{n} {techs[n]['version']}" for n in via if techs[n].get("version")),
"cdn": "; ".join(n for n, t in techs.items() if "CDN" in t.get("categories", [])),
})

with open("java_prospects.csv", "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=["url", "via", "versions", "cdn"])
w.writeheader()
w.writerows(rows)
print(f"{len(rows)} of {len(domains)} domains show a Java signal")
Enter fullscreen mode Exit fullscreen mode

A row labelled Java only has a Java entry with none of the named sources next to it. That is almost always the JSESSIONID cookie, which is the one rule that reports Java directly instead of implying it. For lists in the thousands, see Batch Scan 1,000 Websites for Tech Stack for concurrency, retries, and quota planning.

Compare Java and Non-Java Stacks with POST /compare

/compare takes 2 to 10 URLs and returns each domain's technologies, a unique list per domain, and a top-level shared list. It is a quick way to see whether a competitor set splits between Java and other backends:

curl -s -X POST "https://detectzestack.p.rapidapi.com/compare" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com" \
-H "Content-Type: application/json" \
-d '{"urls": ["https://www.homedepot.com", "https://www.lowes.com"]}' \
| jq '{shared: .shared, unique: [.domains[] | {domain, unique}]}'
Enter fullscreen mode Exit fullscreen mode

If Java is in shared, every site you compared showed a Java signal. If it appears in one domain's unique list, only that one did, which may reflect a real difference or just a proxy hiding the other backend.

Using Java Detection for Lead Lists and Security Audits

For sales, the "via" column above is the segmenting field. Adobe Experience Manager sites are large enterprises with a marketing platform budget. Spring and Tomcat hits point to in-house engineering teams running their own Java services. Liferay and Magnolia point to portal and content teams. Pair any of them with the CDN column and you know what sits between the application and its users. For a complete enrichment flow into a CRM, see Build a Lead Enrichment Pipeline with Tech Detection. For comparison with other backends, see Find Companies Using Node.js and Find Companies Using MySQL.

Mapping Detected Versions to CPE Identifiers for Vulnerability Checks

Several Java entries carry a cpe field: Java itself (cpe:2.3:a:oracle:jre), Apache Tomcat, JBoss Application Server, GlassFish, Liferay, Magnolia CMS, and Adobe Experience Manager. DetectZeStack's /vulnerability endpoint looks up CVEs only for technologies that have both a CPE and a detected version. The Java entry never has a version, since no HTTP signal reveals the JRE release, so it is never checked. A Tomcat version from X-Powered-By: Tomcat-9.0.83, or a JBoss or Liferay version from their headers, is checked:

curl -s "https://detectzestack.p.rapidapi.com/vulnerability?url=https://example.com" \
-H "x-rapidapi-key: $RAPIDAPI_KEY" \
-H "x-rapidapi-host: detectzestack.p.rapidapi.com"
Enter fullscreen mode Exit fullscreen mode

In practice, a Java server that publishes its exact version in a header is also a server whose headers were never hardened, which is a finding on its own. Detect Vulnerable Technologies with CPE explains how the CPE matching works and how to read the results.

FAQ

How can I tell if a website runs on Java?

Run curl -sI against the site and look for a JSESSIONID cookie, a Server header starting with Apache-Coyote or Jetty, or an X-Powered-By header naming Servlet, JSP, JSF, or Tomcat. .jsp or .do URLs are further hints.

How do I find a list of companies using Java?

Use /lookup?tech=Java for domains already in the index, then check your own list 10 URLs at a time with POST /analyze/batch, keeping results with an entry named Java.

Is JavaScript the same as Java for tech detection?

No. Java appears under Programming languages. JavaScript libraries and frameworks are front-end code and say nothing about the backend.

Why does a Java website not show Java in the scan?

A CDN or reverse proxy usually replaced the headers and served a cached page with no session cookie. A missing entry means no Java signal was visible, not that the backend is something else.

Conclusion: Get Your Free API Key on RapidAPI

Finding companies using Java comes down to catching the side effects of a Java backend: the JSESSIONID cookie, application server headers, the Spring header, and Java-based products like Adobe Experience Manager and Liferay. DetectZeStack matches those and adds a Java entry whenever one of them implies it. It does not match URL patterns or JSF form fields, and it cannot see through a proxy that strips everything, so treat hits as strong evidence and misses as unknown.

The workflow: one /demo call to see the response shape, /lookup?tech=Java for indexed domains, /analyze/batch for your own list, and the script above to record how each Java signal was found. Each scan also returns the CDN, CMS, and front-end stack from the same request.

Related Reading

Top comments (0)