Technical Guide

How to Detect What Framework a Website Uses Programmatically

Published March 28, 2026 · 6 min read

You're building a competitive intelligence tool, a lead generation pipeline, or just curious about what powers a particular website. You want to know programmatically — not by opening DevTools and guessing — whether a site runs React, Vue, Angular, Next.js, Nuxt, Svelte, or something else entirely.

This guide covers the four main techniques for detecting website frameworks in code, along with their tradeoffs. Then we'll show how StackPeek combines all of them into a single API call.

1. HTTP Header Fingerprinting

The simplest detection method requires nothing more than reading HTTP response headers. Many frameworks and hosting platforms leak identifying information before you even parse the HTML body.

Here's what to look for:

import requests

resp = requests.head("https://example.com", allow_redirects=True)

for header in ["x-powered-by", "server", "x-generator"]:
    val = resp.headers.get(header)
    if val:
        print(f"{header}: {val}")

Pros: Fast, lightweight — a HEAD request is all you need. Cons: Easily stripped by production configs. Many sites remove X-Powered-By for security. You'll miss frameworks that don't set custom headers.

2. HTML Pattern Matching

Parsing the HTML source reveals framework-specific patterns that are much harder to remove. Every framework leaves fingerprints in the DOM structure it generates.

Framework HTML Fingerprint
Next.js __next div, _next/static script paths
Nuxt.js __nuxt div, _nuxt/ asset paths
Gatsby ___gatsby div, /page-data/ paths
Angular ng-version attribute, ng- prefixed attributes
Vue.js data-v- scoped style attributes
Svelte svelte- class prefixes, __svelte comments
WordPress wp-content/ paths, wp-json links
import re, requests

html = requests.get("https://example.com").text

patterns = {
    "Next.js": [r'id="__next"', r'/_next/static'],
    "Nuxt.js": [r'id="__nuxt"', r'/_nuxt/'],
    "Angular": [r'ng-version=', r'ng-\w+='],
    "Vue.js":  [r'data-v-[a-f0-9]'],
    "Gatsby": [r'id="___gatsby"'],
}

for fw, rules in patterns.items():
    if any(re.search(r, html) for r in rules):
        print(f"Detected: {fw}")

Pros: Reliable — these patterns are structural to how frameworks render. Cons: Requires fetching the full HTML body. Won't work on sites behind JavaScript rendering (SPAs that serve an empty shell).

3. JavaScript Global Detection

Many frameworks attach globals to the window object. If you're running a headless browser (Puppeteer, Playwright), you can check for them directly:

const { chromium } = require('playwright');

(async () => {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');

  const frameworks = await page.evaluate(() => ({
    react: !!document.querySelector('[data-reactroot]'),
    vue: !!window.__VUE__,
    angular: !!window.ng,
    jquery: !!window.jQuery
  }));

  console.log(frameworks);
  await browser.close();
})();

Pros: Can detect frameworks on fully client-rendered SPAs. Cons: Requires a headless browser — slow (2-10 seconds per page), resource-heavy, and expensive to scale. Production builds often strip dev-mode globals.

4. Script and Asset Path Analysis

The URLs of JavaScript bundles and static assets contain telltale patterns. Webpack chunk hashes, Vite module paths, and framework-specific directory structures are reliable signals even on heavily optimized production builds.

Combining script path analysis with HTML patterns gives you high confidence without needing a headless browser. But maintaining a detection rule database across framework versions is a full-time job.

The Easier Way: One API Call with StackPeek

StackPeek combines all four techniques — header fingerprinting, HTML pattern matching, script analysis, and meta tag parsing — into a single API call that returns results in under 500ms. No headless browser needed.

curl "https://stackpeek.web.app/api/v1/detect?url=https://linear.app"

Response:

{
  "url": "https://linear.app",
  "technologies": [
    { "name": "React", "category": "framework", "confidence": 0.97 },
    { "name": "Next.js", "category": "framework", "confidence": 0.94 },
    { "name": "Vercel", "category": "hosting", "confidence": 0.99 },
    { "name": "Cloudflare", "category": "cdn", "confidence": 0.91 }
  ],
  "scanTime": 287
}

Instead of maintaining your own detection rules, parsing HTML, and running headless browsers, you get structured JSON with confidence scores and categorized results. The free tier gives you 100 scans per day — no API key required.

Try StackPeek free

Detect any website's framework in under 500ms. 100 scans/day, no API key required.

Try the live scanner →

When to Build Your Own vs. Use an API

Build your own if: You only need to detect 2-3 specific frameworks, you're already running a headless browser for other reasons, or you need to work entirely offline. The code snippets above are a solid starting point.

Use StackPeek if: You need broad framework coverage (120+ technologies), you care about speed and reliability, you don't want to maintain detection rules as frameworks evolve, or you're scanning at any kind of volume. At $9/month for 5,000 scans, it's cheaper than running your own Puppeteer infrastructure.

Framework detection is a solved problem — the question is whether you want to solve it yourself every time a framework ships a new version, or let an API handle it. Try StackPeek free →

More developer APIs from the Peek Suite