Six dimensions in the pitch, four channels in the code
StackPrism is a browser extension for detecting a website's technology stack.
At a glance
- What is it?
- StackPrism is a Manifest V3 extension that detects the stack behind a web page from DOM state, response headers, dynamically loaded resources and JavaScript copyright comments. Its rules are JSON files that the build step compiles into regexes, and its own documentation is unusually candid about where detection stops working.
- Who is it for?
- Judgment: StackPrism is worth installing as a second opinion rather than as an authority, because the extension itself is careful about the difference between a signal and a conclusion. The caveats section is the most valuable text in the repository: backend identification is explicitly incomplete, forged headers are detected only in the aggregate case, the source scan reads a DOM snapshot rather than the server's HTML, and Chrome's own pages are out of reach.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 8, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The pitch says six dimensions, the implementation has four channels
The summary line describes evidence gathered along six dimensions: page runtime, DOM, resource URLs, response headers, dynamic loading and source copyright comments. The section below it describes four independent channels, and the four are the implementable set. Static scanning runs an injected script over the DOM, global variables, CSS class names, CSS variables and meta tags when the page loads. Header observation uses a service worker listening on `webRequest.onHeadersReceived` to capture response headers and the HTTP version for the main document, XHR and iframes. Dynamic resource listening pairs `PerformanceObserver` with `MutationObserver` in the content script to accumulate scripts, styles, iframes and feeds that load after the user interacts. The fourth channel fetches the head of the main bundle in the background and reads its copyright comments to identify third-party dependencies bundled into index, main or vendor chunks. The results are merged, deduplicated and grouped into more than fifty categories.
Rules are JSON, and the build compiles hints into every leaf
The detection logic lives in more than fifty JSON files under `public/rules/`, split into a loading manifest, page rules, header rules and a suppression file, and most changes need no code at all. The interesting part is the build step. A Vite plugin called `precompileRulesPlugin` runs at the `closeBundle` stage and injects two fields into every leaf rule: `__hints`, built by de-duplicating and sorting literal segments and keeping the longest three, and `__keywordCombined`, a single regex combining the rule's keywords. At runtime `rule-matcher.ts` uses those first to filter candidates, so the expensive patterns only run against a shortlist. The scripts that implement this live in `build-scripts/`, including one that checks the tech links, one that extracts Wappalyzer icons, and one that produces a second injected build through `vite.injected.config.ts`. One thing to know before wiring this into a loop: the typecheck script is not a typecheck, since it runs `vue-tsc --noEmit` and then the full production build.
The rule schema exists to stop false positives
Each rule is a small JSON object, and the fields exist for a specific reason. `name` and `category` place the hit, where category is one of more than fifty. `patterns` holds regexes or keywords, `matchType` says which, and `matchIn` restricts where the pattern is allowed to match, across html, resources, url, headers and dynamic. Then `confidence` is high, medium or low, `kind` is a human description, and `selectors`, `globals` and `classPrefixes` hold CSS selectors, window globals and class name prefixes. The quality rules that go with the schema are the most useful guidance in the repository. Prefer high-signal evidence: response headers, exclusive resource URLs, the generator meta tag, a window global, a proprietary CSS selector, a JavaScript copyright comment, an official SDK package name. Avoid short or broad keywords, with `spring`, `phoenix`, `column` and `container` named as examples that hit competitor discussions or shared utility classes. And prefer restricting `matchIn`, favouring resources, url or headers over bare html.
Self-host suppression exists because a site's own name is a signal
One rule file has a job that is not detection at all. `self-host-suppress.json` implements self-referential suppression: when the user is on a mainstream site, detection of that same name is skipped. The reason is structural rather than a matter of taste, since a company's own website carries its own name in its markup, its headers and often its bundle comments, so the evidence that identifies a technology on a third-party site is exactly the evidence that makes a self-hosted page look like a deployment of it. Suppressing it is the cheapest fix and the only one that does not require distinguishing a genuine deployment from a vendor site case by case. The same theme shows up in the confidence model elsewhere: after merging, the extension actively converges on forged headers, self-referential hits and vague matches rather than presenting every hit at the same strength, which is a reasonable default for a tool whose output is a list of guesses.
Header observation needs a refresh, and Chrome's own pages are out of reach
The service worker channel has a dependency on page lifecycle that catches people out. The first time you install, you are told to refresh the target page, because the worker has to be present when the main document response arrives in order to capture its headers; a tab that was already open when the extension loaded will not produce them. There is a related boundary: Chrome's system pages, web store pages and other built-in pages do not allow content scripts to be injected, so detection there returns nothing. The Firefox path is slightly different in mechanics but the same in principle, using about:debugging to load a temporary add-on from `dist-firefox/manifest.json`, or an `.xpi` from the release directory after a Firefox build. Both stores are listed in the README, with Chrome, Edge and Firefox all supported, which is unusual for an extension of this size and is the result of staying on Manifest V3 throughout. The from-source path is four commands, with one build target per browser:
git clone https://github.com/setube/stackprism.git
cd stackprism
pnpm install
pnpm run build # Chrome / Edge
pnpm run build:firefox # FirefoxChrome then loads the unpacked `dist/` directory from its extensions page with developer mode on.
Forged headers downgrade a category, they do not block it
Two caveats belong together because both are about what the extension cannot know. The first is backend detection. Many sites hide `Server` and `X-Powered-By`, so the backend section is presented as a clue with a confidence level rather than as a fact, and the documentation says outright that backend detection is not guaranteed complete. The second is forgery. The extension actively looks for the case where four or more identity header fields coexist, and when it finds that pattern it downgrades the affected categories to low confidence and attaches a warning. What it cannot do is spot a single forged header, and the documentation says that too, advising that you combine it with other evidence. That is the right place for the line to sit: a heuristic that catches the common misconfiguration without pretending to be a defence against a determined site operator.
The source scan reads a DOM snapshot, not the server's HTML
Source search is described honestly as a DOM snapshot, built from the current page's `outerHTML` rather than the original HTML the server returned. That distinction matters more than it sounds, because a page that rewrites its markup at runtime, or that was rewritten by an extension or a script, will present different source to this tool than to a developer looking at view-source. Dynamic monitoring has the same character: the content script accumulates resources loaded after interaction in the background, so the results are not final when the popup first opens, and the documentation tells you to reopen the popup to see the merged set. Taken together, the three asynchronous channels, the DOM snapshot, the service worker header capture and the background bundle fetch, explain the refresh advice in the first-time setup notes and the warning that detection is best read as a set of clues converging.
CC BY-NC-SA on a code project, which is not the usual choice
The licence is CC BY-NC-SA 4.0, described in the README as permitting free non-commercial use and modification, with attribution required and derivatives under the same licence. That is a content licence applied to a codebase, and the practical effect is narrow but real: the non-commercial clause excludes using this extension inside a commercial product, and the share-alike clause propagates to derivatives. The repository metadata reports no licence at all, which is a common outcome for Creative Commons licences that automated detection does not recognise, so anyone reading the repository page rather than the README sees a blank field and may assume the default. A LICENSE file is present, as are a privacy policy, a sponsors file and a documentation site built with VitePress. The manifest is marked private, so nothing is published to npm and distribution happens through the three browser stores, which is the right arrangement for an extension.
Editorial conclusion
Judgment: StackPrism is worth installing as a second opinion rather than as an authority, because the extension itself is careful about the difference between a signal and a conclusion. The caveats section is the most valuable text in the repository: backend identification is explicitly incomplete, forged headers are detected only in the aggregate case, the source scan reads a DOM snapshot rather than the server's HTML, and Chrome's own pages are out of reach. What is genuinely well built is the rule system, where adding coverage means editing JSON and the build compiles hints into every rule so the runtime stops scanning the whole document. Two practical notes. The licence is CC BY-NC-SA 4.0, so commercial use is not covered by it, which matters if you were planning to ship this inside a product. And the documented typecheck command actually runs a production build as well, so budget for that before wiring it into a fast local loop.
Frequently asked questions
What is StackPrism?
A Manifest V3 browser extension for Chrome, Edge and Firefox that identifies the technology stack behind a web page. It collects clues through four channels, static scanning, response header observation, dynamic resource listening and JavaScript copyright comment scanning, then groups the merged results into more than fifty categories.
How do I add a detection rule to StackPrism?
By editing JSON. Rules live under public/rules/, with a loading manifest, page rules, header rules and a self-host suppression file, and the manifest lists which files to load. A rule carries name, category, patterns, matchType, matchIn, confidence and optional selectors, globals and classPrefixes.
How does StackPrism avoid false positives?
The build step injects hints and a combined keyword regex into every rule so the runtime filters candidates first, and rules are told to prefer high-signal evidence such as response headers, exclusive resource URLs, the generator meta tag and official SDK package names. The guidance warns against broad keywords like spring, phoenix, column and container, and asks contributors to restrict matchIn to resources, url or headers rather than bare html.
Why does StackPrism need a page refresh after installing?
Header detection depends on the service worker being present when the main document response arrives, so a tab that was already open will not produce headers. Chrome system pages, web store pages and other built-in pages do not allow content scripts at all, so detection returns nothing there.
What license is StackPrism released under?
CC BY-NC-SA 4.0, which allows non-commercial use and modification with attribution and requires derivatives to use the same licence. The repository's licence metadata comes back empty even though a LICENSE file is present, so the non-commercial limit is easy to miss from the repository page alone.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/setube-stackprism)