Tech Stack Guides

How to Find Out What Programming Language a Website Is Built In

Identify the server-side language behind any site — PHP, Node.js, Python, Ruby, ASP.NET or Java — from HTTP headers, cookies, URL extensions and errors.

StackOptic Research Team16 Apr 20268 min read
Identifying the server-side programming language behind a website

Trying to work out what server-side programming language a website is built in — PHP, Node.js, Python, Ruby, ASP.NET or Java? This is the hardest layer of the stack to detect, because the language runs on the server and never ships to your browser directly. But it still leaves fingerprints: HTTP response headers, session cookies, URL file extensions and error pages all leak clues. The fastest method is to read the response headers, where X-Powered-By and Server often name the language or framework outright. This guide covers every signal, plus the big reason detection sometimes fails: CDNs and reverse proxies that strip the evidence.

This is the back-end companion to how to find out what a website is built with; here we focus on the server-side language and framework rather than the visible front end.

Why identify the backend language?

The server-side language shapes how a site is built, hosted and maintained, so it is worth knowing for several reasons. Developers and architects assess a competitor's or acquisition target's stack and what supporting or migrating it would involve. Recruiters and job seekers verify the technology a company actually runs versus what its job ads claim. Security researchers note that an exposed, outdated framework is a larger attack surface. And technical sales teams qualify prospects by stack — a tool that integrates with .NET or Django cares which one a prospect runs. Because the language betrays itself through headers, cookies and behaviour, these questions are answerable from the outside, within the limits we will discuss.

The primary tell: HTTP response headers

The first place to look is the response headers, which the server sends with every page. Open DevTools (F12), go to the Network tab, reload, and click the first (document) request to see its Response Headers. Or fetch them from a terminal with curl -I https://example.com, which prints the headers without loading the page. The most informative headers:

  • X-Powered-By — the most direct signal. Common values include PHP/8.2.1, ASP.NET, and Express (which means Node.js). When present, it usually names the language or framework outright.
  • Server — names the web server. Microsoft-IIS/10.0 strongly suggests ASP.NET; Apache and nginx are general-purpose and run many languages, so they narrow rather than confirm.
  • X-AspNet-Version and X-AspNetMvc-Version — explicit ASP.NET tells, including the version.
  • X-Generator or framework-specific headers — some frameworks announce themselves here.

Headers are the highest-yield first move, but remember that security-conscious teams often remove X-Powered-By deliberately. Its absence means "look elsewhere", not "the language is hidden".

Session cookies are reliable fingerprints

When headers are stripped, cookies frequently give the language away, because most frameworks set a session cookie with a distinctive default name. Open the Application (Chrome) or Storage (Firefox) tab in DevTools and read the cookies the site sets:

  • PHPSESSID → PHP.
  • JSESSIONID → a Java application server (Tomcat, Jetty, JBoss).
  • ASP.NET_SessionId → ASP.NET.
  • csrftoken + sessionid → Django (Python).
  • _rails_session or a *_session cookie → Ruby on Rails.
  • laravel_session → Laravel (PHP).
  • connect.sid → an Express (Node.js) app using the common session middleware.

Cookies are valuable because applications need them to function, so they are harder to remove than a cosmetic header. A PHPSESSID alongside a clean front end is often the clinching clue.

A table of languages and their fingerprints

The signals above are easier to use side by side. This table maps the most common backends to their tells.

Language / frameworkHeader tellsCookie tellsURL / other
PHPX-Powered-By: PHP/8.xPHPSESSID, laravel_session.php extensions
ASP.NETX-AspNet-Version, Server: Microsoft-IISASP.NET_SessionId.aspx, __VIEWSTATE field
JavaServer (Tomcat/Jetty)JSESSIONID.jsp, .do
Python / Djangosometimes nonecsrftoken, sessionidclean URLs, /admin/
Python / FlaskServer: Werkzeug (dev)session cookie
Ruby on RailsX-Powered-By sometimes_<app>_sessionclean REST URLs, authenticity_token
Node.js / ExpressX-Powered-By: Expressconnect.sid

A single strong row — say ASP.NET_SessionId plus X-AspNet-Version — settles the question. Weaker signals like a generic nginx Server header narrow the field without confirming a language on their own.

URL file extensions and form markup

Some sites still wear their language in their URLs. A .php extension names PHP, .aspx names ASP.NET (and often appears with a hidden __VIEWSTATE form field, an unmistakable Web Forms tell), and .jsp or .do name Java. These extensions used to be everywhere, but modern routing increasingly hides them behind clean URLs like /products/123, so their absence is now common and uninformative. When you do see them, though, they are a quick, strong signal. The hidden __VIEWSTATE field in particular is one of the most reliable ASP.NET Web Forms fingerprints there is — search the page source for it.

Error pages and stack traces

A misconfigured or debug-mode site sometimes hands you the answer directly. Error pages and stack traces can reveal the framework and version: a "Whoops, looks like something went wrong" page is Laravel's default, a Django debug page is highly distinctive and even lists the framework version, and a Java stack trace names classes like org.apache.catalina. You should never try to induce errors on a site you do not own, but when an error page surfaces naturally it is rich evidence. Well-run production sites suppress these in favour of generic custom error pages precisely because they leak so much, so an exposed stack trace is itself a sign of a less hardened setup.

The big caveat: CDNs and reverse proxies

Here is why backend detection is genuinely hard, and harder every year. Most serious sites now sit behind a CDN or reverse proxy — Cloudflare, Fastly, Akamai, or an Nginx layer the team runs themselves. That front layer terminates the request and serves its own headers, so the Server header reads cloudflare and the origin's X-Powered-By never reaches you. The CDN effectively masks the real backend. To see through it:

  1. Read the cookies, which usually originate from the application and pass through the proxy unchanged.
  2. Look for framework behaviour — a __VIEWSTATE field, a Django admin login at /admin/, a Rails authenticity_token.
  3. Separate the CDN from the origin conceptually; identifying Cloudflare tells you about delivery, not the language. The hosting and CDN questions are their own topic — see how to find out where a website is hosted.

When the proxy is opaque and the cookies are generic, the honest answer is sometimes "masked behind a CDN" — and recognising that is more useful than guessing.

Reading the HTTP layer properly

Because so much of this rests on headers, it pays to be fluent in reading them. The Network tab and curl -I both expose the full response, and learning to interpret each line — which headers come from the origin, which from the proxy, which from a security layer — is a skill that powers this and many other detections. The dedicated walkthrough is how to read a website's HTTP headers, and it is worth internalising, because headers underpin not just language detection but hosting, CDN and security analysis too. The same curl -I that reveals X-Powered-By: PHP/8.2 also shows you the caching, the security headers and the server software in one go.

Front end versus back end

It is important not to confuse the layers. The back-end language (PHP, Python, Node, Ruby) generates the HTML on the server; the client-side libraries and frameworks (jQuery, React, Vue) run in the browser afterwards. They are detected completely differently — the back end through headers and cookies, the front end through runtime globals and bundles, covered in how to check what JavaScript libraries a website uses. Note too that Node.js blurs the line: it is JavaScript on the server, so a site can be "JavaScript end to end" with React on the front and an Express or Next.js server on the back. Keeping the two layers distinct in your mind prevents the common mistake of reporting a front-end framework as if it were the server language.

Common mistakes when detecting the language

A few errors are routine. Reading the CDN's Server header as the backendcloudflare or nginx is the delivery layer, not the language. Treating a missing X-Powered-By as a hidden or custom stack — it is usually just stripped for security. Assuming clean URLs mean a modern non-PHP framework — plenty of PHP frameworks (Laravel, Symfony) use clean URLs too. And ignoring cookies — they are often the most reliable tell left once headers are gone, yet people forget to open the Application tab. As always, corroborate: a header plus a cookie plus a behavioural fingerprint is a confident read; one ambiguous header is not.

How accurate is language detection?

Be realistic: this is the least reliable layer of technology detection, by design. When headers and cookies are intact, you can be confident — PHPSESSID with X-Powered-By: PHP is conclusive. But the server side is the easiest layer to hide, and modern infrastructure hides it well: CDNs strip origin headers, security teams remove X-Powered-By, and clean URLs erase extensions. In those cases you may only narrow the language to two or three candidates, or correctly conclude that it is masked behind a proxy. That is a valid, honest result. The discipline is the same as everywhere else in detection — stack independent signals, and never overstate certainty the evidence does not support.

The fast, reliable workflow

  1. Read the response headers (curl -I or the Network tab): X-Powered-By, Server, X-AspNet-Version.
  2. Check the cookies in the Application tab: PHPSESSID, JSESSIONID, csrftoken, _rails_session.
  3. Note URL extensions (.php, .aspx, .jsp) and search the source for __VIEWSTATE.
  4. Watch for framework behaviour — error pages, admin paths, CSRF tokens.
  5. Account for the CDN — identify the proxy and look through it via cookies.
  6. Corroborate two or three signals, and accept "masked behind a proxy" as a valid answer.

Go deeper

Want the language, framework, hosting and full stack inferred in one pass? Analyse any website with StackOptic — one report, free, no sign-up.

Frequently asked questions

How do I find out what programming language a website uses?

Inspect the HTTP response headers with DevTools' Network tab or curl -I. Look at Server, X-Powered-By and X-AspNet-Version, which often name PHP, ASP.NET or a Node framework. Then check the cookies — PHPSESSID, JSESSIONID, csrftoken or _rails_session each point to a specific language — and any .php/.aspx/.jsp file extensions in URLs. Combine the signals, because a CDN can hide the origin's headers.

Which header reveals the backend language?

X-Powered-By is the most direct: it frequently reads PHP/8.x, ASP.NET, or Express (Node.js). The Server header can also help — values like Microsoft-IIS often accompany ASP.NET, while Apache or Nginx are web servers that run many languages and so are less conclusive on their own. Many sites remove X-Powered-By for security, so its absence does not mean the language is hidden, just that you check other signals.

Can a session cookie tell me the language?

Yes, session cookies are among the most reliable tells because frameworks set distinctive names by default. PHPSESSID is PHP, JSESSIONID is a Java application server, ASP.NET_SessionId is ASP.NET, csrftoken plus sessionid is Django (Python), and _rails_session (or a *_session cookie) indicates Ruby on Rails. Open the Application or Storage tab in DevTools to read the cookies a site sets.

Why is the backend language often hard to detect?

Modern sites sit behind CDNs and reverse proxies such as Cloudflare, Fastly or Nginx, which terminate the request and serve their own headers, masking the origin server entirely. Security-conscious teams also deliberately strip X-Powered-By and custom error pages. And clean-URL routing removes the .php or .aspx extensions that used to give the game away. When the front layer is opaque, you fall back to cookies and framework-specific behaviour.

Is detecting the programming language reliable?

It is less reliable than detecting a CMS or a client-side framework, because the server side is the easiest layer to hide. When headers and cookies are intact, you can be confident; when a CDN strips them and URLs are clean, you may only narrow it to a few candidates. Corroborating a header with a cookie and any framework fingerprint gives the most dependable answer, and sometimes the honest result is 'masked behind a proxy'.

Analyse any website with StackOptic

Get the full technology stack, performance, security and SEO report in seconds — free.

Analyse a website

Related articles