Node.js AI Visibility API
Query the raw answers ChatGPT, Perplexity, Google AI Overviews, Google AI Mode, Copilot and Gemini actually give - from Node.js, using nothing but the fetch that ships with the runtime. POST a query to https://api.agentgeo.org/v1/fetches with your ag_live_ key and the answer text, citations and sources come back as clean JSON. No Puppeteer, no proxy pool, no npm install at all. AgentGEO is the answer-access layer for AI visibility - a Node.js GEO API in the plainest sense. Your own code (or your users' AI agent over MCP) runs the GEO/AEO analysis; the API just hands you the raw data, structured and identical across all six engines.
Read this page with an AI
Query the raw answers ChatGPT, Perplexity, Google AI Overviews, Google AI Mode, Copilot and Gemini actually return - from Node.js, with the fetch that ships in the runtime. No Puppeteer, no browser pool, no dependency to install: one POST, and the answer text, citations and sources arrive as clean JSON your code can act on.
Get a free AI-visibility audit → · Read the quickstart → - No card, no account.
Get my free auditCall the AI Visibility API from Node.js
POST to https://api.agentgeo.org/v1/fetches with your ag_live_ key as a bearer token and the engines you want in the surfaces array. Node 20+ ships fetch natively, so the entire integration is standard library - no axios, no SDK, no node_modules at all.
// Node 20+ - native fetch, zero dependencies. Run as ESM for top-level await.
const resp = await fetch("https://api.agentgeo.org/v1/fetches", {
method: "POST",
headers: {
"Authorization": "Bearer ag_live_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
query: "best running shoes for flat feet",
surfaces: ["chatgpt"], // chatgpt | perplexity | gemini | google_ai_overview | copilot
}),
});
if (!resp.ok) throw new Error(`AgentGEO ${resp.status}: ${await resp.text()}`);
const run = await resp.json();
for (const answer of run.answers) {
console.log(answer.surfaceKey, "→", answer.answerText);
for (const src of answer.sources) { // cited sources, in order
console.log(" ", src.position, src.title, src.url);
}
}What comes back is plain JSON - no DOM, no cleanup pass:
{
"id": "run_84c1f2ab91d3",
"query": "best running shoes",
"surfaces": ["chatgpt"],
"status": "completed",
"recordsDelivered": 1,
"creditsCharged": 1,
"answers": [
{
"surfaceKey": "chatgpt",
"answerText": "For most runners, top picks include ...",
"sources": [
{ "title": "Best Running Shoes", "url": "https://example.com/guide", "position": 1 }
]
}
]
}The response shape is identical across all six engines, so the fan-out below is the whole integration: the same query into chatgpt, perplexity, gemini, google_ai_overview and copilot, then diff the citation sets. That diff is the core of any GEO/AEO analysis you'd want to build.
Fanning one query across every engine is a Promise.all away - one request per surface key, then print who cites what:
const SURFACES = ["chatgpt", "perplexity", "gemini", "google_ai_overview", "google_ai_mode", "copilot"];
async function fetchAnswers(query, surface) {
const resp = await fetch("https://api.agentgeo.org/v1/fetches", {
method: "POST",
headers: {
"Authorization": "Bearer ag_live_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({ query, surfaces: [surface] }),
});
if (!resp.ok) throw new Error(`AgentGEO ${resp.status}`);
return resp.json();
}
// One query, six engines, in parallel
const runs = await Promise.all(
SURFACES.map((s) => fetchAnswers("best running shoes for flat feet", s))
);
// Who cites what - the raw material for any share-of-voice metric
for (const run of runs) {
for (const answer of run.answers) {
console.log(answer.surfaceKey, "cites:", answer.sources.map((src) => src.url));
}
}What the Node.js API gives you
AgentGEO is a thin answer-access layer, not another closed dashboard. The API delivers the raw material; your Node service, worker or cron job (or your users' AI agent) does the analysis.
- Six engines, one contract - ChatGPT, Perplexity, Google AI Overviews, Google AI Mode, Copilot and Gemini behind the same request/response shape, so covering a new engine is one more string in the
surfacesarray. - Citations and sources, structured - every answer carries
sources[]withtitle,urlandposition, ready to store, rank or diff. No cheerio, no regexing links out of markup. - Managed-scraper engine, maintained for you - answers come through supported access paths, so there is no Chromium to babysit, no stealth plugin to update and no IP ban to recover from at 2 a.m.
- Provider metadata -
surfaceKeyandproviderFieldsride along on every response, keeping your dataset auditable as the underlying models change. - MCP connection, too - the same data is exposed over MCP via the
agentgeo-mcpnpm package, so Claude Code, Cursor, Codex or any MCP client can pull answers and run the analysis itself. - Usage-based billing - run allowances by tier. Priced by usage, never per seat.
Common problems with DIY answer-scraping in Node.js
The default instinct in Node is to reach for Puppeteer or Playwright, drive ChatGPT or Perplexity headlessly, and pull answers out of the DOM. It works in a demo on Tuesday and becomes an ops project by the following sprint.
- Puppeteer/Playwright farms. Every tracked query runs a real Chromium instance - hundreds of MB apiece - so a modest keyword set turns into a browser farm with its own memory graphs, restarts and crash handling.
- Stealth-plugin cat-and-mouse.
puppeteer-extra-plugin-stealthworks until fingerprinting updates, then you're pinning forks and chasing GitHub issues just to stay logged in - work that ships zero product. - Selectors break on their deploys, not yours. cheerio and DOM queries bind to hashed, ever-shifting class names; ChatGPT ships a frontend change and your extraction starts returning nulls in production with no failing test.
- Proxy rotation and pool orchestration. Residential proxies, retries, backoff and
p-queueconcurrency caps across six engines - a distributed-systems side quest bolted onto a marketing metric. - Headless Chrome doesn't fit serverless. Chromium blows past Lambda's bundle limits, so you maintain
@sparticuz/chromiumbuilds and slow cold starts - or give up and run a persistent browser fleet.
| DIY scraping in Node.js | AgentGEO API | |
|---|---|---|
| Setup | Puppeteer + stealth plugins, proxies, browser pools | Native fetch + a key - zero dependencies |
| Parsing | cheerio/DOM selectors that break on frontend deploys | Stable JSON, identical across engines |
| Citations | Hand-rolled DOM walking per engine | Structured answers[].sources[] |
| Serverless & CI | Chromium vs Lambda size limits | A plain HTTPS call - runs anywhere |
| Adding an engine | A new scraper and browser pool | One more key in the surfaces array |
AgentGEO is the answer-access layer; whatever dashboard, alert or score you build in Node on top of it is yours. You own the raw data and ship it inside your own product, instead of renting a login to someone else's.
Prefer MCP? Same data, no glue code
Everything the REST endpoint returns is also exposed over MCP. If the consumer is an AI agent rather than a Node service - Claude Code, Cursor, Codex or any MCP client - install the agentgeo-mcp package from npm and the agent fetches answers and runs the GEO analysis itself:
claude mcp add agentgeo -- npx -y agentgeo-mcp --key ag_live_your_key_hereWho builds on this
Mostly product engineers adding AI-visibility tracking to an existing SaaS - a nightly worker that fans a keyword set across six engines and writes citations to Postgres is an afternoon of Node - plus agencies white-labeling GEO/AEO reporting for clients. If you evaluated closed dashboards like Profound and wanted the data underneath them, or you were about to scrape ChatGPT yourself, this is the layer to build on.
Ready to see the answers on your own brand? Get a free audit → · Read the 5-minute quickstart →
Get my free audit