Build with Citepoint.

Find the questions you're losing, write and publish the pages that win them back, and track visibility from your own code, the terminal or an AI agent.

Overview

Run Citepoint from your own code, the terminal or an AI agent. You can:

  • Scan a domain.
  • List opportunities: the buyer questions where AI recommends a competitor instead of you.
  • Write a page that answers one.
  • Publish it.
  • Show your visibility across AI engines.

The API and MCP server are on every plan.

API keys

Create and revoke keys in the app under Settings, API. A key starts with cp_ and is shown once, so store it somewhere safe. A key acts on the whole workspace, so keep it secret and revoke it if it leaks.

Send it as a Bearer token on every request:

Authorization: Bearer <key>

The CLI uses the same keys, and so can the MCP server, though agents that support sign-in need none: see MCP server.

REST API

The base URL is https://citepoint.ai/api/v1. Request bodies and responses are JSON.

Endpoints

GET/projects
List your projects.
POST/projects
Send {"domain": "acme.com"}. Reads the site, creates the project, finds buyer questions and runs the first checks. Returns 201, or 409 with code exists if the domain is already a project.
POST/projects/{projectId}/scan
Re-checks every tracked question on every engine now. Returns 202.
GET/projects/{projectId}/opportunities?limit=20
Questions where AI recommends someone else, with a score, each engine's status (mentioned, missing, pending or no_answer) and who is recommended instead.
GET/projects/{projectId}/pages
List the project's pages.
POST/projects/{projectId}/pages
Starts writing a page. Send {"question": "..."} or {"promptId": "..."}. Returns 202.
GET/pages/{pageId}
The page's status, markdown, FAQ, sources and live URL. Pages published through GitHub also carry review: the pull request URL and its state.
POST/pages/{pageId}/publish
Publishes the page. Returns 202.
GET/projects/{projectId}/visibility
7-day visibility and its change, share of voice, per-engine and per-question results over 28 days, and who AI recommends instead.
POST/projects/{projectId}/visits
Counts AI traffic forwarded from your own server. Send a JSON array of up to 50 visits, each with path and userAgent, and referrer and url when you have them. Returns {"counted": 1, "ignored": 0}. See Whole-site AI traffic.

Examples

Create a project
curl -X POST https://citepoint.ai/api/v1/projects \
  -H "Authorization: Bearer $CITEPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "acme.com"}'
List opportunities
curl "https://citepoint.ai/api/v1/projects/$PROJECT_ID/opportunities?limit=20" \
  -H "Authorization: Bearer $CITEPOINT_API_KEY"
Write a page
curl -X POST https://citepoint.ai/api/v1/projects/$PROJECT_ID/pages \
  -H "Authorization: Bearer $CITEPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"question": "best crm for law firms"}'

Writing and publishing take a while, so those calls return 202 straight away. Check progress with GET /pages/{pageId}.

Whole-site AI traffic

Citepoint counts visits from AI answers and AI crawler reads on the pages and tools it hosts, on the server, with no script or cookies. To count them on the rest of your site, forward them from your own server. AI crawlers don't run JavaScript, so an analytics script never sees them.

Send each hit to POST /projects/{projectId}/visits: the page's path, the request's user agent and, when there is one, the referrer and the full URL (Citepoint reads utm_source from it). Citepoint counts reads by AI crawlers and visits from ChatGPT, Perplexity, Claude, Gemini, Grok and Copilot, and ignores everything else. Paths are stored without their query string or fragment. If Citepoint hosts pages in a subfolder of your site, hits under it are skipped, since they're already counted.

Count a crawler read
curl -X POST https://citepoint.ai/api/v1/projects/$PROJECT_ID/visits \
  -H "Authorization: Bearer $CITEPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[{"path": "/pricing", "userAgent": "Mozilla/5.0 (compatible; GPTBot/1.2; +https://openai.com/gptbot)"}]'

The snippets below check the user agent and referrer first, so only AI traffic is sent. They send it in the background, so your pages never wait. Replace YOUR_PROJECT_ID with the id from GET /projects, or copy the snippet from Settings, Integrations in the app, where it's filled in. Keep the key in your server's environment and never expose it to the browser.

Next.js
Save it at the root of your project as proxy.ts, or middleware.ts before Next.js 16. If you already have one, add the check to it.
Cloudflare Worker
Deploy it as a Worker on your site's route, such as acme.com/*. If a Worker already serves your site, add the check to it.
Next.js, in proxy.ts
// Counts AI crawler reads and visits from AI answers in Citepoint. Everything else is skipped.
// Set CITEPOINT_API_KEY in your server environment. Never prefix it with NEXT_PUBLIC_.
import { NextResponse, type NextFetchEvent, type NextRequest } from "next/server";

const AI_BOT = /GPTBot|OAI-SearchBot|ChatGPT|Claude|anthropic|Perplexity|Googlebot|Google-Extended|bingbot|Applebot|meta-externalagent|Amazonbot|MistralAI|DuckAssistBot|Grok/i;
const AI_REFERRER = /chatgpt\.com|openai\.com|perplexity\.ai|claude\.ai|gemini\.google\.com|grok\.com|copilot\.microsoft\.com/i;
const ASSET = /\.(css|js|map|png|jpe?g|gif|svg|webp|avif|ico|woff2?)$/i;

export default function proxy(request: NextRequest, event: NextFetchEvent) {
  const { pathname, search } = request.nextUrl;
  const userAgent = request.headers.get("user-agent") ?? "";
  const referrer = request.headers.get("referer") ?? "";
  if (!ASSET.test(pathname) && (AI_BOT.test(userAgent) || AI_REFERRER.test(referrer + search))) {
    event.waitUntil(
      fetch("https://citepoint.ai/api/v1/projects/YOUR_PROJECT_ID/visits", {
        method: "POST",
        headers: { Authorization: `Bearer ${process.env.CITEPOINT_API_KEY}`, "Content-Type": "application/json" },
        body: JSON.stringify([{ path: pathname, userAgent, referrer, url: request.url }]),
      }).catch(() => {}),
    );
  }
  return NextResponse.next();
}

export const config = { matcher: "/((?!_next/|api/).*)" };
Cloudflare Worker, in worker.js
// Counts AI crawler reads and visits from AI answers in Citepoint, then serves the page as usual.
// Add the key as a secret: npx wrangler secret put CITEPOINT_API_KEY
const AI_BOT = /GPTBot|OAI-SearchBot|ChatGPT|Claude|anthropic|Perplexity|Googlebot|Google-Extended|bingbot|Applebot|meta-externalagent|Amazonbot|MistralAI|DuckAssistBot|Grok/i;
const AI_REFERRER = /chatgpt\.com|openai\.com|perplexity\.ai|claude\.ai|gemini\.google\.com|grok\.com|copilot\.microsoft\.com/i;
const ASSET = /\.(css|js|map|png|jpe?g|gif|svg|webp|avif|ico|woff2?)$/i;

export default {
  async fetch(request, env, ctx) {
    const { pathname, search } = new URL(request.url);
    const userAgent = request.headers.get("user-agent") ?? "";
    const referrer = request.headers.get("referer") ?? "";
    if (!ASSET.test(pathname) && (AI_BOT.test(userAgent) || AI_REFERRER.test(referrer + search))) {
      ctx.waitUntil(
        fetch("https://citepoint.ai/api/v1/projects/YOUR_PROJECT_ID/visits", {
          method: "POST",
          headers: { Authorization: `Bearer ${env.CITEPOINT_API_KEY}`, "Content-Type": "application/json" },
          body: JSON.stringify([{ path: pathname, userAgent, referrer, url: request.url }]),
        }).catch(() => {}),
      );
    }
    return fetch(request);
  },
};

Errors

Errors come back as JSON with a message and a code:

{"error": {"message": "...", "code": "..."}}
400
The request body is missing something or isn't valid. The message says what.
401
The key is missing, wrong or revoked.
402
You've reached a plan limit, or the workspace has no active plan.
404
The project or page doesn't exist, or this key can't reach it.
409
The domain is already a project (code exists). Only from POST /projects.
429
Rate limited. Wait a moment and try again.

CLI

Install it with npm, then log in with an API key. It needs Node 20 or later.

npm install -g citepoint
citepoint login

Commands

citepoint scan acme.com
Scan a domain and run checks on every engine.
citepoint opportunities
List the questions where AI recommends someone else.
citepoint write "best crm for law firms" --wait
Write a page for a question. --wait returns once it's written.
citepoint publish <pageId> --wait
Publish a page. --wait returns once it's published.
citepoint visibility
Show visibility, share of voice and who AI recommends instead.
citepoint projects
List your projects.
citepoint use <project>
Set the project other commands act on.
citepoint page <id> --markdown > page.md
Print a page as Markdown, here saved to a file.

Add --json to any command for output that scripts and agents can parse.

Environment

CITEPOINT_API_KEY
An API key to use instead of the one saved by citepoint login. Useful in CI and for agents.
CITEPOINT_URL
The Citepoint URL to talk to. Defaults to https://citepoint.ai.

MCP server

Citepoint runs a remote MCP server over Streamable HTTP at https://citepoint.ai/mcp. Agents sign in to Citepoint in your browser, so there's no key to copy.

Tools

list_projects
List your projects.
scan_domain
Scan a domain and run checks on every engine.
list_opportunities
Questions where AI recommends someone else.
write_page
Start writing a page for a question.
get_page
A page's status, content and live URL.
publish_page
Publish a page.
get_visibility
Visibility, share of voice and who AI recommends instead.

Set up

Every agent at once
npx add-mcp https://citepoint.ai/mcp -g -y

Adds Citepoint to every coding agent it finds on your machine. Leave off -y to choose which ones. It uses add-mcp, an open-source CLI. Sign in to Citepoint in the browser window your agent opens the first time it connects.

Or add it to one agent:

Claude Code
claude mcp add --transport http citepoint https://citepoint.ai/mcp
Codex, in ~/.codex/config.toml
[mcp_servers.citepoint]
url = "https://citepoint.ai/mcp"
Then sign in
codex mcp login citepoint
Cursor, in ~/.cursor/mcp.json
{
  "mcpServers": {
    "citepoint": {
      "url": "https://citepoint.ai/mcp"
    }
  }
}
Gemini CLI
gemini mcp add --transport http citepoint https://citepoint.ai/mcp
Grok Build
grok mcp add --transport http citepoint https://citepoint.ai/mcp
OpenCode, in opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "citepoint": {
      "type": "remote",
      "url": "https://citepoint.ai/mcp"
    }
  }
}
Then sign in
opencode mcp auth citepoint

Any other client that supports MCP sign-in (OAuth): use the URL https://citepoint.ai/mcp.

How sign-in works

The first time your agent connects, it opens Citepoint in your browser. Sign in, choose the workspace it should use, and allow it. The agent stays signed in after that. Each connection appears in the app under Settings, API, where you can revoke it: members can revoke their own, and owners any in the workspace. Someone removed from a workspace loses their connections to it at once.

With an API key instead

For CI, scripts, or an agent without sign-in, send an API key as a Bearer token.

Every agent at once
npx add-mcp https://citepoint.ai/mcp --header "Authorization: Bearer $CITEPOINT_API_KEY" -g -y

add-mcp writes the key's value into each agent's config file, so keep those files private.

Claude Code
claude mcp add --transport http citepoint https://citepoint.ai/mcp --header "Authorization: Bearer $CITEPOINT_API_KEY"
Codex, in ~/.codex/config.toml
[mcp_servers.citepoint]
url = "https://citepoint.ai/mcp"
bearer_token_env_var = "CITEPOINT_API_KEY"
Cursor, in ~/.cursor/mcp.json
{
  "mcpServers": {
    "citepoint": {
      "url": "https://citepoint.ai/mcp",
      "headers": { "Authorization": "Bearer ${env:CITEPOINT_API_KEY}" }
    }
  }
}
Gemini CLI
gemini mcp add --transport http --header "Authorization: Bearer $CITEPOINT_API_KEY" citepoint https://citepoint.ai/mcp
Grok Build
grok mcp add --transport http citepoint https://citepoint.ai/mcp --header "Authorization: Bearer $CITEPOINT_API_KEY"
OpenCode, in opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "citepoint": {
      "type": "remote",
      "url": "https://citepoint.ai/mcp",
      "headers": { "Authorization": "Bearer {env:CITEPOINT_API_KEY}" }
    }
  }
}

Any other client: use the URL https://citepoint.ai/mcp and send the header Authorization: Bearer <key>.

Try it

Ask your agent:

“Where am I losing in ChatGPT?”

“Write and ship a page for the top one.”

GitHub pull requests

For sites built in code, such as Next.js, Astro or Hugo, Citepoint can publish each page as a pull request to your repo. You review and merge it, and your usual deploy publishes it.

Set up

  1. In the app, open Settings, Publishing, GitHub.
  2. Install the Citepoint GitHub App on only the repos you pick.
  3. Choose the repo and the base branch.
  4. Choose the content folder, for example content/compare.
  5. Choose the format: Markdown or MDX.
  6. Set the live URL pattern, for example https://acme.com/compare/{slug}.

How it works

Each page and free tool becomes a file with front matter, committed on its own branch, with a pull request. Citepoint marks the page live when the pull request merges. Autopilot can open pull requests, but a person always merges them.

A generated page, in Markdown
---
title: "Best CRM for law firms in 2026"
description: "..."
slug: best-crm-for-law-firms
date: 2026-09-27
updated: 2026-09-27
faq:
  - q: "..."
    a: "..."
---

Markdown links can't carry a rel attribute, so link exchange links in a page are written as HTML anchors with rel="sponsored".