Everything you need to detect website tech stacks programmatically.
https://stackpeek.web.app
All API endpoints are under /api/v1/.
The free tier (GET /api/v1/detect) requires no authentication and is rate limited. For higher limits and batch scanning, include your API key in the x-api-key header:
curl -H "x-api-key: stk_your_key_here" ...
API keys use the stk_ prefix. You can generate one for free via the /api/v1/keys endpoint.
Scan a single URL and return all detected technologies with confidence scores. The URL is automatically prefixed with https:// if no protocol is provided.
| Parameter | Type | Required | Description |
|---|---|---|---|
| url | string | Yes | The website URL to scan (e.g. stripe.com) |
curl "https://stackpeek.web.app/api/v1/detect?url=stripe.com"
const res = await fetch(
"https://stackpeek.web.app/api/v1/detect?url=stripe.com"
);
const data = await res.json();
console.log(data.technologies);
import requests
resp = requests.get(
"https://stackpeek.web.app/api/v1/detect",
params={"url": "stripe.com"}
)
data = resp.json()
print(data["technologies"])
{
"url": "https://stripe.com/",
"technologies": [
{ "name": "React", "category": "Frontend Framework", "confidence": 95 },
{ "name": "Next.js", "category": "Frontend Framework", "confidence": 90 },
{ "name": "Cloudflare", "category": "CDN", "confidence": 100 },
{ "name": "Stripe", "category": "Payments", "confidence": 100 }
],
"categories": {
"Frontend Framework": [
{ "name": "React", "confidence": 95 },
{ "name": "Next.js", "confidence": 90 }
],
"CDN": [{ "name": "Cloudflare", "confidence": 100 }],
"Payments": [{ "name": "Stripe", "confidence": 100 }]
},
"meta": {
"technologiesDetected": 4,
"scanDuration": "342ms",
"timestamp": "2026-03-28T12:00:00.000Z"
}
}
Scan up to 10 URLs in a single request. Each URL is scanned concurrently. Requires an API key on a Starter or Pro plan.
| Field | Type | Required | Description |
|---|---|---|---|
| urls | string[] | Yes | Array of URLs to scan (max 10) |
curl -X POST "https://stackpeek.web.app/api/v1/detect/batch" \
-H "x-api-key: stk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"urls": [
"https://stripe.com",
"https://vercel.com",
"https://linear.app"
]
}'
const res = await fetch("https://stackpeek.web.app/api/v1/detect/batch", {
method: "POST",
headers: {
"x-api-key": "stk_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
urls: ["https://stripe.com", "https://vercel.com"]
}),
});
const data = await res.json();
console.log(data.results);
import requests
resp = requests.post(
"https://stackpeek.web.app/api/v1/detect/batch",
headers={"x-api-key": "stk_your_key_here"},
json={"urls": ["https://stripe.com", "https://vercel.com"]}
)
for result in resp.json()["results"]:
print(result["url"], len(result["technologies"]), "techs")
{
"results": [
{
"url": "https://stripe.com/",
"technologies": [/* ... */],
"status": "ok"
},
{
"url": "https://vercel.com/",
"technologies": [/* ... */],
"status": "ok"
}
],
"meta": {
"total": 2,
"timestamp": "2026-03-28T12:00:00.000Z"
}
}
Create a free API key. You start on the free plan with 100 scans/day.
curl -X POST "https://stackpeek.web.app/api/v1/keys" \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com"}'
const res = await fetch("https://stackpeek.web.app/api/v1/keys", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email: "you@example.com" }),
});
const { apiKey } = await res.json();
console.log("Your key:", apiKey);
import requests
resp = requests.post(
"https://stackpeek.web.app/api/v1/keys",
json={"email": "you@example.com"}
)
print(resp.json()["apiKey"])
{
"apiKey": "stk_abc123def456...",
"plan": "free",
"limit": "100 scans/day"
}
Check your current usage stats and plan details.
curl -H "x-api-key: stk_your_key_here" \
"https://stackpeek.web.app/api/v1/usage"
{
"plan": "starter",
"requestsToday": 142,
"requestsThisMonth": 3847
}
Check if the API is up and running. Useful for monitoring and uptime checks.
curl "https://stackpeek.web.app/api/health"
{
"status": "ok",
"service": "stackpeek",
"version": "1.0.0"
}
Every detection response includes three sections:
A flat array of all detected technologies. Each item contains:
| Field | Type | Description |
|---|---|---|
| name | string | Technology name (e.g. "React", "Cloudflare") |
| category | string | Technology category (e.g. "Frontend Framework", "CDN") |
| confidence | number | Detection confidence from 0 to 100 |
The same technologies grouped by category. Each key is a category name, and the value is an array of { name, confidence } objects.
| Field | Type | Description |
|---|---|---|
| technologiesDetected | number | Total number of technologies found |
| scanDuration | string | Time taken to scan (e.g. "342ms") |
| timestamp | string | ISO 8601 timestamp of the scan |
| Plan | Daily Scans | Monthly Scans | Batch |
|---|---|---|---|
| Free | 100 | 1,000 | No |
| Starter | 500 | 5,000 | Yes (10 URLs) |
| Pro | 2,500 | 25,000 | Yes (10 URLs) |
Rate limits reset daily at midnight UTC and monthly on the 1st. The free GET endpoint also has a per-IP rate limit to prevent abuse. If you exceed your limit, the API returns a 429 response.
Timeouts: Target URLs that don't respond within 10 seconds are aborted with a 504 response. Private/internal URLs (localhost, 127.0.0.1, 10.x, 192.168.x) are blocked.
| Plan | Price | Scans/day | Features |
|---|---|---|---|
| Free | $0 | 100 | Single URL detection, JSON response |
| Starter | $9/mo | 500 | Batch scanning (10 URLs), API key, usage dashboard |
| Pro | $29/mo | 2,500 | Everything in Starter + priority support, higher limits |
Upgrade anytime at stackpeek.web.app/#pricing. All paid plans include a 7-day free trial.
url parameter, invalid URL, private/internal URL, or invalid batch bodyError responses return JSON:
{
"error": "Missing required parameter: url",
"example": "/api/v1/detect?url=https://example.com"
}
async function getFrameworks(url) {
const res = await fetch(
`https://stackpeek.web.app/api/v1/detect?url=${url}`
);
const { categories } = await res.json();
const frameworks = categories["Frontend Framework"] || [];
frameworks.forEach(fw =>
console.log(`${fw.name} (${fw.confidence}% confidence)`)
);
}
getFrameworks("vercel.com");
import requests
def get_frameworks(url):
resp = requests.get(
"https://stackpeek.web.app/api/v1/detect",
params={"url": url}
)
categories = resp.json()["categories"]
for fw in categories.get("Frontend Framework", []):
print(f"{fw['name']} ({fw['confidence']}% confidence)")
get_frameworks("vercel.com")
const API_KEY = "stk_your_key_here";
const res = await fetch("https://stackpeek.web.app/api/v1/detect/batch", {
method: "POST",
headers: {
"x-api-key": API_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({
urls: [
"https://competitor1.com",
"https://competitor2.com",
"https://competitor3.com",
],
}),
});
const { results } = await res.json();
results.forEach(r => {
console.log(`\n${r.url}:`);
r.technologies.forEach(t =>
console.log(` ${t.category}: ${t.name}`)
);
});
import requests
API_KEY = "stk_your_key_here"
resp = requests.post(
"https://stackpeek.web.app/api/v1/detect/batch",
headers={"x-api-key": API_KEY},
json={"urls": [
"https://competitor1.com",
"https://competitor2.com",
"https://competitor3.com",
]}
)
for r in resp.json()["results"]:
print(f"\n{r['url']}:")
for t in r["technologies"]:
print(f" {t['category']}: {t['name']}")