> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chatgrid.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Build a Competitive Intelligence Board

> Track competitors, vectorize their content, and ask AI to compare positioning. 10 minutes.

## What you'll build

A board that tracks competitor website source nodes, vectorizes extracted competitor notes, and lets you ask AI to compare positioning across all competitors at once.

* Add competitor websites as visual nodes
* Vectorize content for semantic search
* Ask AI to compare positioning and pricing
* Create summary sticky notes linked to sources

## Prerequisites

* ChatGrid API key ([get one here](/authentication))
* Node.js 18+ or Python 3.10+

## Step 1: Create a board

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.chatgrid.ai/v1/boards \
    -H "Authorization: Bearer cgk_live_..." \
    -H "Content-Type: application/json" \
    -d '{"name": "Competitive Intel — Q1 2026"}'
  ```

  ```typescript Node.js theme={null}
  const res = await fetch("https://api.chatgrid.ai/v1/boards", {
    method: "POST",
    headers: { Authorization: "Bearer cgk_live_...", "Content-Type": "application/json" },
    body: JSON.stringify({ name: "Competitive Intel — Q1 2026" }),
  });
  const { data: board } = await res.json();
  const boardId = board.id;
  ```

  ```python Python theme={null}
  import requests
  API_KEY = "cgk_live_..."
  BASE = "https://api.chatgrid.ai/v1"
  headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
  res = requests.post(f"{BASE}/boards", headers=headers, json={"name": "Competitive Intel — Q1 2026"})
  board_id = res.json()["data"]["id"]
  ```
</CodeGroup>

Save the `board_id` from the response.

## Step 2: Add competitor website nodes

Batch-create a node for each competitor in one request.

```bash cURL theme={null}
curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/nodes/batch \
  -H "Authorization: Bearer cgk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operations": [
      {"action": "create", "data": {"type": "url", "position": {"x": 0, "y": 0}, "data": {"url": "https://competitor-a.com", "label": "Competitor A"}}},
      {"action": "create", "data": {"type": "url", "position": {"x": 400, "y": 0}, "data": {"url": "https://competitor-b.com", "label": "Competitor B"}}},
      {"action": "create", "data": {"type": "url", "position": {"x": 800, "y": 0}, "data": {"url": "https://competitor-c.com", "label": "Competitor C"}}}
    ]
  }'
```

Save the returned node IDs -- you need them to link vectorized content.

## Step 3: Vectorize competitor content

Vectorize extracted competitor notes. The `node_id` ties chunks back to the source node.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/documents/vectorize \
    -H "Authorization: Bearer cgk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "content": "Competitor A homepage notes: enterprise positioning, SOC 2 emphasis, integrations with Salesforce and Slack. Pricing page starts at $49 per seat.",
      "node_id": "{nodeIdA}",
      "metadata": {"source": "competitor-a", "type": "homepage-pricing"}
    }'

  # Repeat for competitors B and C
  ```

  ```python Python theme={null}
  notes = [
      ("Competitor A homepage notes: enterprise positioning, SOC 2 emphasis, integrations with Salesforce and Slack. Pricing page starts at $49 per seat.", node_a_id, "competitor-a"),
      ("Competitor B notes: SMB positioning, usage-based pricing, fast onboarding.", node_b_id, "competitor-b"),
      ("Competitor C notes: developer-first positioning, generous free tier, API-led workflow.", node_c_id, "competitor-c"),
  ]
  for content, nid, source in notes:
      requests.post(f"{BASE}/boards/{board_id}/documents/vectorize", headers=headers,
          json={"content": content, "node_id": nid, "metadata": {"source": source}})
  ```
</CodeGroup>

## Step 4: Ask AI to compare positioning

Create a chat thread and ask a cross-competitor question.

<CodeGroup>
  ```bash cURL theme={null}
  # Create a chat thread
  curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/chats \
    -H "Authorization: Bearer cgk_live_..." \
    -H "Content-Type: application/json" \
    -d '{"title": "Competitive Analysis"}'

  # Ask the comparison question (use chatId from above)
  curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/chats/{chatId}/messages \
    -H "Authorization: Bearer cgk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "content": "Compare the positioning and pricing of all three competitors. What does each one emphasize? Where are the gaps we could exploit?",
      "stream": false
    }'
  ```

  ```typescript Node.js theme={null}
  const chatRes = await fetch(`https://api.chatgrid.ai/v1/boards/${boardId}/chats`, {
    method: "POST",
    headers: { Authorization: "Bearer cgk_live_...", "Content-Type": "application/json" },
    body: JSON.stringify({ title: "Competitive Analysis" }),
  });
  const { data: chat } = await chatRes.json();

  const msgRes = await fetch(
    `https://api.chatgrid.ai/v1/boards/${boardId}/chats/${chat.id}/messages`,
    {
      method: "POST",
      headers: { Authorization: "Bearer cgk_live_...", "Content-Type": "application/json" },
      body: JSON.stringify({
        content: "Compare the positioning and pricing of all three competitors. What does each one emphasize? Where are the gaps we could exploit?",
        stream: false,
      }),
    }
  );
  const { data: analysis } = await msgRes.json();
  ```
</CodeGroup>

The AI searches all vectorized content and responds with sourced comparisons.

## Step 5: Create summary sticky notes

Turn findings into visual sticky notes on the canvas.

```bash cURL theme={null}
curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/nodes/batch \
  -H "Authorization: Bearer cgk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operations": [
      {"action": "create", "data": {"type": "note", "position": {"x": 200, "y": 400}, "data": {"label": "Key Finding", "text": "A targets enterprise, B targets SMBs, C is developer-first. Gap: mid-market team leads."}}},
      {"action": "create", "data": {"type": "note", "position": {"x": 600, "y": 400}, "data": {"label": "Pricing Insight", "text": "A: per-seat $49/mo. B: usage-based. C: generous free tier. Our opportunity: flat team pricing."}}}
    ]
  }'
```

## Step 6: Connect findings to sources

Link summary nodes back to the competitors they reference.

```bash cURL theme={null}
curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/edges \
  -H "Authorization: Bearer cgk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"source_node_id": "{findingNodeId}", "target_node_id": "{competitorANodeId}", "data": {"label": "references"}}'
```

## Step 7: Search across competitors

Run semantic searches to answer specific questions at any time.

```bash cURL theme={null}
curl -X POST https://api.chatgrid.ai/v1/boards/{boardId}/documents/search \
  -H "Authorization: Bearer cgk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"query": "which competitor offers an API?", "limit": 5}'
```

## What's happening under the hood

When you vectorize extracted text, ChatGrid splits it into chunks and generates embeddings stored in pgvector. Each chunk is tagged with the `node_id` and `metadata` you provide, so search results trace back to their source. When AI answers a question, it performs semantic search across all vectorized content on the board and uses the top matches as grounded context. Edges between nodes create a traversable graph from findings back to evidence.

## Next steps

<CardGroup cols={2}>
  <Card title="Synthesize Documents" icon="files" href="/cookbooks/document-synthesis">
    Combine PDFs and reports into visual findings
  </Card>

  <Card title="Streaming Responses" icon="bolt" href="/cookbooks/streaming-responses">
    Stream AI analysis in real time
  </Card>
</CardGroup>
