A lead comes in with a company website and not much else. You need their tech stack to know if they're worth a demo, their Twitter and LinkedIn for the SDR to reference, and any public contact email so the record isn't a dead end. Doing that by hand takes a few minutes per lead, and it does not scale past about thirty of them.
SiteIntel fetches the page once and returns the parsed result: detected technologies, social profile links, emails published on the page, plus the usual metadata. One request per domain.
The request
Auth is RapidAPI headers. The url param takes a full https:// URL, not a bare domain, which trips people up on the first call.
curl -s "https://siteintel.p.rapidapi.com/v1/analyze?url=https://stripe.com" \
-H "X-RapidAPI-Key: $RAPIDAPI_KEY" \
-H "X-RapidAPI-Host: siteintel.p.rapidapi.com"
Node, using global fetch (18+, no dependencies):
const HOST = "siteintel.p.rapidapi.com";
async function enrich(domain) {
const url = `https://${HOST}/v1/analyze?url=${encodeURIComponent(`https://${domain}`)}`;
const res = await fetch(url, {
headers: {
"X-RapidAPI-Key": process.env.RAPIDAPI_KEY,
"X-RapidAPI-Host": HOST,
},
});
if (!res.ok) throw new Error(`${domain}: HTTP ${res.status}`);
const data = await res.json();
return {
company: data.open_graph?.site_name || data.title,
description: data.description,
stack: data.detected_tech ?? [],
socials: data.social_links ?? [],
emails: data.emails ?? [],
finalUrl: data.final_url,
};
}
console.log(await enrich("stripe.com"));
Wrap the loop in a small concurrency limit if you're running a list. Sequential is fine for a few hundred rows overnight; four at a time is plenty for a nightly sync.
Reading the response
{
"query": "https://stripe.com",
"final_url": "https://stripe.com/",
"status": 200,
"fetched_at": "2026-07-24T14:02:11Z",
"title": "Stripe | Financial Infrastructure to Grow Your Revenue",
"description": "Stripe powers online and in-person payment processing...",
"canonical": "https://stripe.com/",
"lang": "en",
"favicon": "https://stripe.com/favicon.ico",
"open_graph": {
"title": "Stripe | Financial Infrastructure",
"image": "https://images.stripecdn.com/...",
"site_name": "Stripe",
"type": "website"
},
"detected_tech": ["Cloudflare", "React"],
"social_links": ["https://twitter.com/stripe", "https://www.linkedin.com/company/stripe"],
"emails": [],
"server": "nginx"
}
Two things worth knowing before you write your mapping code.
detected_tech and social_links are flat arrays of strings. No nested objects, no confidence scores, no category field. Sorting a social link into a CRM column means matching on the hostname yourself:
const bucket = (links) =>
Object.fromEntries(
links.map((u) => {
const h = new URL(u).hostname.replace(/^www\./, "");
if (h.includes("linkedin")) return ["linkedin", u];
if (h.includes("twitter") || h.includes("x.com")) return ["twitter", u];
if (h.includes("facebook")) return ["facebook", u];
if (h.includes("instagram")) return ["instagram", u];
if (h.includes("youtube")) return ["youtube", u];
return ["other", u];
})
);
emails is often empty, and that's the honest answer rather than a guess. It reflects addresses published on the page that was fetched. Plenty of companies route everything through a contact form, so treat a hit as a bonus and never as a required field in your schema.
Also compare final_url against what you sent. A redirect to a different apex domain usually means the company got acquired or rebranded, which is a useful flag on its own.
What to build with it
The thing I actually run: a nightly job that walks CRM records where enriched_at is null, calls /v1/analyze on the website field, and writes back three columns. Stack goes into a tag list, socials into their own fields, and the description becomes the first line of context an SDR sees.
Routing off detected_tech is where it earns its keep. If you sell a Shopify app, a lead whose array contains "Shopify" is a different lead from one running WordPress, and that decision is a single .includes() at ingest time instead of a rep opening a tab. Same trick for scoring: leads on Cloudflare and React skew toward having an actual engineering team, which matters if your product needs one to adopt it.
Cache aggressively. A company's stack does not change between Tuesday and Wednesday, so store the payload and re-fetch monthly. Store the raw JSON alongside your mapped columns too, because the first time you want a field you didn't map, you'll want the original response instead of a re-crawl.
Two other endpoints on the same key are useful in a lead context. GET /v1/seo-audit?url=https://example.com gives an on-page report, which is a decent talking point if you sell anything marketing-adjacent. GET /v1/screenshot?url=https://example.com gets you a thumbnail for the CRM record.
Working examples, including the batch runner: https://github.com/clause-netizen/siteintel-api — it's on RapidAPI too if you'd rather not host anything: https://rapidapi.com/hidanny0001/api/siteintel
Top comments (0)