OpenSEO Google Search Console Google Analytics Integration: Complete Implementation Guide

OpenSEO integrates with Google Search Console and Google Analytics through a layered MCP-based architecture that uses OAuth 2.0 authentication, project-scoped service layers, and typed tools to expose GSC and GA4 data as structured, LLM-readable functions.

OpenSEO (every-app/open-seo) is an open-source SEO platform that unifies search performance data by connecting directly to Google's APIs. This guide explains how the OpenSEO Google Search Console Google Analytics integration works under the hood, from OAuth credential handling to cross-service data fusion and UI components.

Integration Architecture

OpenSEO implements a six-layer architecture to connect with Google's services safely and scalably:

  • OAuth & Connection Management: Handles GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and BETTER_AUTH_SECRET for self-hosted deployments, or uses built-in SaaS credentials in the hosted version. Implemented in src/server/features/google/oauth-config.ts.

  • Project-Scoped Context: Every request wraps a ProjectAuthContext containing the organization ID and base URL. This context scopes all GSC/GA4 connections to specific projects and builds UI links. Defined in src/server/mcp/context.ts via buildProjectMeta.

  • Service Layer: Low-level API wrappers including GscService for Search Console (searchAnalytics, urlInspection) and Ga4ReportingService for GA4 Admin & Data APIs.

  • MCP (Model-Chat-Program) Tools: Expose typed, read-only functions that LLMs and UI components invoke. Each tool validates input via Zod and returns formatted text plus structured JSON. Search Console tools live in src/server/mcp/tools/search-console-tools.ts (e.g., getSearchConsolePerformanceTool), while GA4 tools reside in src/server/mcp/tools/google-analytics-tools.ts (e.g., getGoogleAnalyticsOrganicLandingPagesTool).

  • UI Integration: React components SearchConsoleConnectionCard.tsx and GoogleAnalyticsConnectionCard.tsx let users connect accounts, view status, and navigate to settings.

  • Routing: The settings page at src/routes/_project/p/$projectId/settings/integrations.tsx renders connection cards with deep-link anchors (#search-console, #google-analytics).

Connection Workflow

OAuth Configuration Detection

When running self-hosted, the server first checks for required environment variables. If GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, or BETTER_AUTH_SECRET are missing, the tool returns a nudge with documentation links:

// src/server/mcp/tools/search-console-tools.ts
// Lines 70-80: detect missing OAuth config and return a helpful message
if (!config.clientId || !config.clientSecret) {
  return {
    text: `Google OAuth is not configured...`,
    structuredContent: { status: "error", setupUrl: GSC_SELF_HOSTED_SETUP_DOCS_URL }
  };
}

User-Initiated Connection

The UI's SearchConsoleConnectionCard (or GoogleAnalyticsConnectionCard) presents a Connect button that redirects to Google's OAuth consent screen. After consent, Google redirects back with an authorization code that the server exchanges for refresh and access tokens, storing them scoped to the specific project.

Token Refresh and Error Handling

When MCP tools execute, they validate stored tokens. If expired or revoked, the service catches GscTokenError (for Search Console) or Ga4ReportError and returns a response containing a reconnect URL:

// src/server/mcp/tools/google-analytics-tools.ts
// Lines 191-202: translate GA4 errors into user-visible messages + reconnect link
} catch (error) {
  if (error.code === 'UNAUTHENTICATED') {
    return {
      text: "Google Analytics connection expired",
      structuredContent: { status: "error", reconnectUrl: buildReconnectUrl(projectId) }
    };
  }
}

Data Retrieval Methods

Search Console Performance

The get_search_console_performance MCP tool builds a GscPerformanceInput object from Zod-validated user input, forwards it to GscService.getPerformance, and formats results into markdown tables with structured JSON:

// src/server/mcp/tools/search-console-tools.ts
// Lines 58-62: invoke the service and format the result
const result = await gscService.getPerformance(projectId, input);
return {
  text: formatAsMarkdownTable(result.rows),
  structuredContent: { status: "ok", rows: result.rows }
};

Google Analytics Organic Data

The get_google_analytics_organic_landing_pages tool calls Ga4ReportingService.runReport with specific parameters to isolate organic search traffic:

// src/server/mcp/tools/google-analytics-tools.ts
// Lines 46-48: configure the report kind for organic landing pages
const report = await ga4Service.runReport({
  kind: "landing_pages",
  channel: "organic_search",
  ...dateRange
});

Both tools return a structured JSON envelope with status: "ok" or "error" that downstream LLM agents parse reliably.

Cross-Service Analysis

OpenSEO fuses GSC and GA4 data through the search opportunities tool (get_search_opportunities), which merges Search Console ranking data (pages ranking in positions 4-20) with GA4 organic landing page metrics. The SearchOpportunityService scores opportunity rows and exposes them via an MCP tool:

// src/server/mcp/tools/google-analytics-tools.ts
// Lines 48-50: invoke the opportunity service
const opportunities = await searchOpportunityService.find({
  projectId,
  dateRange,
  limit: args.limit
});

Implementation Examples

Fetching Search Console Performance

import { getSearchConsolePerformanceTool } from "@/server/mcp/tools/search-console-tools";

const args = {
  projectId: "proj_123",
  dimensions: ["query", "page"],
  dateRange: "last_28_days",
  rowLimit: 500,
};

const response = await getSearchConsolePerformanceTool.handler(args, {
  auth: { organizationId: "org_456" },
  baseUrl: "https://app.openseo.so",
});

console.log(response.text);   // Human-readable table
console.log(response.structuredContent?.rows); // Structured rows

Retrieving GA4 Organic Landing Pages

import { getGoogleAnalyticsOrganicLandingPagesTool } from "@/server/mcp/tools/google-analytics-tools";

const args = {
  projectId: "proj_123",
  startDate: "2024-08-01",
  endDate: "2024-08-28",
};

const response = await getGoogleAnalyticsOrganicLandingPagesTool.handler(
  args,
  { auth: { organizationId: "org_456" }, baseUrl: "https://app.openseo.so" }
);

console.log(response.text);                // Summary + table
console.log(response.structuredContent?.rows?.length); // Row count

Combining GSC and GA4 for Search Opportunities

import { getSearchOpportunitiesTool } from "@/server/mcp/tools/google-analytics-tools";

const args = {
  projectId: "proj_123",
  startDate: "2024-08-01",
  endDate: "2024-08-28",
  limit: 100,
};

const response = await getSearchOpportunitiesTool.handler(
  args,
  { auth: { organizationId: "org_456" }, baseUrl: "https://app.openseo.so" }
);

console.log(response.text); // Human-readable summary of scored opportunities

Summary

  • Layered Architecture: OpenSEO uses distinct layers for OAuth management, project context, API services, MCP tools, and UI components to ensure secure, scalable integrations.

  • OAuth Flexibility: The system supports both self-hosted configurations (requiring GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and BETTER_AUTH_SECRET) and hosted SaaS deployments with built-in credentials.

  • Project Scoping: All data access is wrapped in ProjectAuthContext from src/server/mcp/context.ts, ensuring organization-level isolation of Google account connections.

  • MCP Tool Design: Functions like getSearchConsolePerformanceTool and getGoogleAnalyticsOrganicLandingPagesTool provide typed, Zod-validated interfaces that return both human-readable text and structured JSON for LLM consumption.

  • Error Resilience: Token expiration and authentication errors are caught as GscTokenError or Ga4ReportError and surfaced to users with specific reconnect URLs rather than raw failures.

Frequently Asked Questions

How does OpenSEO handle authentication for self-hosted deployments?

Self-hosted deployments must provide GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and BETTER_AUTH_SECRET environment variables. The system detects missing configuration in src/server/features/google/oauth-config.ts and returns setup documentation links rather than failing silently.

Can OpenSEO refresh expired Google tokens automatically?

Yes. When MCP tools execute, they validate token freshness. If a token is expired or revoked, the tool catches the error (such as GscTokenError for Search Console) and returns a structured response containing a reconnect URL, prompting the user to re-authenticate without breaking the workflow.

What specific Google Analytics data does OpenSEO retrieve?

OpenSEO retrieves organic search-specific metrics through Ga4ReportingService, particularly focusing on landing page performance via the get_google_analytics_organic_landing_pages tool. It filters for channel: "organic_search" to isolate SEO-relevant traffic from other acquisition sources.

Where are the UI components for connecting Google accounts located?

The connection interface components are located at src/client/features/gsc/SearchConsoleConnectionCard.tsx for Search Console and src/client/features/ga4/GoogleAnalyticsConnectionCard.tsx for Google Analytics. These components render on the integrations settings page at src/routes/_project/p/$projectId/settings/integrations.tsx.

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 →