How OpenSEO Monitors AI Search Visibility: Architecture and Implementation

OpenSEO tracks AI search visibility through a three-layer pipeline that queries DataForSEO’s AI-search API via an MCP tool, persists brand mention metrics to PostgreSQL or SQLite, and renders real-time results through a TanStack React Router interface.

OpenSEO (from the repository every-app/open-seo) treats AI search visibility as a core SEO signal alongside traditional rankings. The platform monitors how brands appear in AI-driven search results—such as ChatGPT responses and Google AI Overviews—by tracking mentions, citations, and referring domains. This article breaks down the exact implementation, from the feature definition in the frontend to the DataForSEO API integration on the backend.

The Three-Layer Monitoring Architecture

OpenSEO’s AI search visibility monitoring consists of distinct layers that handle feature configuration, routing, and data collection.

1. Feature Definition in the UI Schema

The feature specification lives in web/src/lib/feature-pages.ts at lines 537–606. This file declares the "AI Brand Visibility" feature and defines the four metrics that constitute AI search visibility:

  • Mentions – How often the brand appears in AI-generated responses
  • Citations – The number of pages citing the brand
  • Platforms – Which AI platforms (ChatGPT, Google AI Overview, etc.) contain the citations
  • Cited Domains – The count of distinct domains that cite the brand

This configuration also maps the "Find visibility gaps" workflow and FAQ content that explains the monitoring methodology to end users.

2. Route Registration and Page Rendering

The frontend route is registered in web/src/routes/_marketing/features/ai-brand-visibility.tsx at lines 9–20 using TanStack React Router. This file wires the URL path /features/ai-brand-visibility to the generic FeaturePageTemplate component.

When a user navigates to this route, the template fetches the latest AI search visibility data from the server and renders the four metric cards defined in the feature schema. The route file itself handles the layout and initial data loading, delegating the metric display to the reusable template.

3. Backend Data Collection via MCP

The data acquisition happens in src/server/mcp/tools/dataforseo-research-tools.ts. This Multi-Chain Processor (MCP) tool communicates directly with DataForSEO’s AI-search endpoints to retrieve brand monitoring data.

The tool constructs a POST request to /ai/search/brand-lookup with the target domain and requested metrics:

const response = await dataForSeoClient.post('/ai/search/brand-lookup', {
  domain,
  metrics: ['mentions', 'citations', 'platforms', 'cited_domains'],
});

The response is normalized into a structured payload ({ mentions: number, citations: number, platforms: number, citedDomains: number }) and returned to the frontend. According to the every-app/open-seo source code, this data is persisted in the database schema defined in src/db/schema.ts, which supports both PostgreSQL and SQLite backends.

How the Data Pipeline Works

The AI search visibility pipeline operates in real-time when a user accesses the feature page. The flow follows this sequence:

  1. User Request – The TanStack Router triggers a loader function that calls the backend API
  2. MCP Processing – The dataforseo-research-tools.ts MCP tool validates the domain and constructs the DataForSEO API request
  3. External Query – DataForSEO returns raw brand mention data from ChatGPT, Google AI Overview, and other platforms
  4. Normalization – The tool sorts results by visibility (the default ordering) and extracts the four key metrics
  5. Persistence – Results are stored in the database tables defined in src/db/schema.ts for historical tracking
  6. Rendering – The frontend receives the JSON payload and displays it through the FeaturePageTemplate

This architecture allows the system to run on-demand when users open the page, or via scheduled background jobs for continuous monitoring.

Implementation Examples

Client-Side Data Fetching with TanStack Query

The frontend consumes AI search visibility data using a custom React Hook built on TanStack Query. This pattern handles caching, loading states, and error boundaries:

import { useQuery } from '@tanstack/react-query';

function useAiBrandVisibility(domain: string) {
  return useQuery(['aiBrandVisibility', domain], async () => {
    const res = await fetch(`/api/ai-brand-visibility?domain=${domain}`);
    if (!res.ok) throw new Error('Failed to load AI visibility');
    return res.json(); // { mentions, citations, platforms, citedDomains }
  });
}

// Example component
export function AiVisibilityCard({ domain }: { domain: string }) {
  const { data, isLoading, error } = useAiBrandVisibility(domain);
  if (isLoading) return <div>Loading…</div>;
  if (error) return <div>Error loading visibility</div>;

  return (
    <div className="grid grid-cols-4 gap-4">
      <Metric label="Mentions" value={data.mentions} />
      <Metric label="Citations" value={data.citations} />
      <Metric label="Platforms" value={data.platforms} />
      <Metric label="Cited domains" value={data.citedDomains} />
    </div>
  );
}

Server-Side Route Handler

The API endpoint that serves the frontend is implemented using TanStack Server Router. The handler in src/server/routes/ai-brand-visibility.ts (or similar) invokes the MCP tool:

import { createServerRoute } from '@tanstack/server-router';
import { getAiBrandVisibility } from '@/server/mcp/tools/dataforseo-research-tools';

export const Route = createServerRoute('/api/ai-brand-visibility')({
  async loader({ request }) {
    const url = new URL(request.url);
    const domain = url.searchParams.get('domain');
    if (!domain) throw new Error('Domain required');
    const visibility = await getAiBrandVisibility(domain);
    return new Response(JSON.stringify(visibility), {
      headers: { 'Content-Type': 'application/json' },
    });
  },
});

Summary

Frequently Asked Questions

What metrics does OpenSEO track for AI search visibility?

OpenSEO tracks four primary metrics for AI search visibility: Mentions (how often the brand appears in AI responses), Citations (the volume of pages citing the brand), Platforms (which AI systems contain the citations), and Cited Domains (the number of unique referring domains). These metrics are defined in web/src/lib/feature-pages.ts and provide a comprehensive view of brand presence across generative search results.

How does OpenSEO fetch AI brand mention data?

The platform uses a Multi-Chain Processor (MCP) tool located in src/server/mcp/tools/dataforseo-research-tools.ts to fetch data. This tool sends authenticated requests to the DataForSEO API endpoint /ai/search/brand-lookup, passing the target domain and requested metrics. The tool then normalizes the response and sorts results by visibility before returning the data to the frontend or persisting it to the database.

Where is AI visibility data stored in OpenSEO?

AI search visibility data is stored in the relational database schema defined in src/db/schema.ts. OpenSEO supports both PostgreSQL and SQLite backends. The MCP tool writes the normalized metrics (mentions, citations, platforms, cited domains) to this schema, enabling historical tracking and trend analysis for monitored domains.

Can the AI visibility monitoring be automated?

Yes. While the AI search visibility feature runs on-demand when a user opens the /features/ai-brand-visibility page, the MCP-based architecture supports scheduled background jobs. You can configure cron jobs or queue workers to periodically invoke the getAiBrandVisibility function for specific domains, ensuring the database always contains fresh AI-search metrics without requiring manual page loads.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →