How to Implement Core SEO Functionality in Next.js Using every-app/open-seo

Open-SEO provides a self-hosted MCP (Machine-Client-Protocol) API that aggregates data from Google Search Console, DataForSEO, and Lighthouse, allowing Next.js applications to generate meta tags, sitemaps, and structured data at build or request time.

This guide explains how to integrate the every-app/open-seo repository into a Next.js project to automate SEO artifact generation. By offloading heavy analytics processing to Open-SEO’s backend, your Next.js frontend remains lightweight while serving fully optimized pages.

What Is Open-SEO and the MCP API?

Open-SEO is a self-hosted backend service that normalizes data from disparate SEO sources into a unified MCP (Machine-Client-Protocol) API. Rather than managing separate integrations with Google Search Console, DataForSEO SERP APIs, and Lighthouse audits in your frontend, Open-SEO handles the throttling, caching, and pagination internally.

Your Next.js application communicates with Open-SEO via HTTP endpoints exposed by the MCP layer. According to the source code in src/serverFunctions/searchPerformance.ts, the /api/seo/meta endpoint extracts the correct row from DataForSEO SERP responses and returns a normalized JSON payload containing titles, descriptions, and Open Graph fields.

Prerequisites and Environment Setup

Before implementing the integration, configure your environment variables to authenticate with the MCP layer. As implemented in src/serverFunctions/middleware.ts, all MCP routes are protected by a createMiddleware wrapper that validates project tokens against environment variables.

Create a .env.local file in your Next.js project root:

OPENSEO_MCP_URL=https://your-open-seo-instance.com
OPENSEO_PROJECT_TOKEN=your_project_token_here

The middleware reads OPENROUTER_API_KEY or DATAFORSEO_API_KEY to validate requests, so ensure these match your Open-SEO deployment configuration.

Implementing Meta Tags and Canonical URLs

Fetching SEO Metadata from the MCP Endpoint

The function computeNextCheckAt in src/shared/rank-tracking.ts handles URL normalization and canonicalization, ensuring consistent canonical URLs across your tracked pages. To inject these into your Next.js pages, call the MCP endpoint inside getServerSideProps or getStaticProps.

Here is a complete implementation for a dynamic page:

// pages/[slug].tsx
import { GetServerSideProps } from 'next';
import Head from 'next/head';
import type { SEOData } from '@/types';

export const getServerSideProps: GetServerSideProps = async ({ params, req }) => {
  const slug = params?.slug as string;
  const res = await fetch(
    `${process.env.OPENSEO_MCP_URL}/api/seo/meta?url=${encodeURIComponent(slug)}`,
    {
      headers: { Authorization: `Bearer ${process.env.OPENSEO_PROJECT_TOKEN}` },
    }
  );
  const seo: SEOData = await res.json();

  return { props: { seo } };
};

export default function Page({ seo }: { seo: SEOData }) {
  return (
    <>
      <Head>
        <title>{seo.title}</title>
        <meta name="description" content={seo.description} />
        <meta property="og:title" content={seo.title} />
        <meta property="og:description" content={seo.description} />
        <meta property="og:image" content={seo.ogImage} />
        <link rel="canonical" href={seo.canonical} />
      </Head>
      <article>{/* page content */}</article>
    </>
  );
}

This approach leverages Open-SEO’s pre-aggregated data, eliminating the need for complex API orchestration in your frontend.

Generating Dynamic Sitemaps and Robots.txt

Proxying the XML Sitemap

The RankCheckWorkflow.ts workflow iterates over all tracked URLs and writes an XML sitemap to Cloudflare KV or Postgres, depending on your deployment. Rather than generating sitemaps client-side, create a thin API route in Next.js that proxies the pre-generated XML from Open-SEO.

Create pages/api/sitemap.xml.ts:

import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(_: NextApiRequest, res: NextApiResponse) {
  const resp = await fetch(`${process.env.OPENSEO_MCP_URL}/sitemap.xml`, {
    headers: { Authorization: `Bearer ${process.env.OPENSEO_PROJECT_TOKEN}` },
  });
  const xml = await resp.text();

  res.setHeader('Content-Type', 'application/xml');
  res.setHeader('Cache-Control', 's-maxage=86400, stale-while-revalidate');
  res.send(xml);
}

The Cache-Control headers enable CDN-level caching, reducing load on both your Next.js server and the Open-SEO backend.

Serving Robots.txt

Similarly, the RankCheckWorkflow generates robots.txt as part of the same KV payload. Serve it via a dedicated API route:

// pages/api/robots.txt.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(_: NextApiRequest, res: NextApiResponse) {
  const resp = await fetch(`${process.env.OPENSEO_MCP_URL}/robots.txt`, {
    headers: { Authorization: `Bearer ${process.env.OPENSEO_PROJECT_TOKEN}` },
  });
  const txt = await resp.text();

  res.setHeader('Content-Type', 'text/plain');
  res.send(txt);
}

Injecting Structured Data (JSON-LD)

Open-SEO extracts structured data from Lighthouse audits via the lighthouseStoredPayload.ts library. This file parses audit results and surfaces the structuredData field if present in the page source.

To include JSON-LD in your Next.js pages, extend your Head component:

{seo.jsonLd && (
  <script 
    type="application/ld+json" 
    dangerouslySetInnerHTML={{ __html: seo.jsonLd }} 
  />
)}

This ensures search engines receive properly formatted schema markup without requiring manual JSON-LD construction in your frontend components.

Displaying Rank Tracking Data

For dynamic keyword-rank tables, query the RankTrackingRepository which stores pre-aggregated rank data for each project. The repository implementation in src/server/features/rank-tracking/repositories/RankTrackingRepository.ts provides optimized queries that pull the latest rank data without heavy computation on the frontend.

Fetch this data in getServerSideProps and render it in a table component. Because Open-SEO handles the aggregation, your page bundle stays lightweight while displaying real-time SEO performance metrics.

Summary

  • Open-SEO acts as a self-hosted MCP backend that consolidates Google Search Console, DataForSEO, and Lighthouse data.
  • Meta tags and canonical URLs are fetched from /api/seo/meta and injected via next/head, with canonical logic handled in src/shared/rank-tracking.ts.
  • Sitemaps and robots.txt are generated by RankCheckWorkflow.ts and served through thin Next.js API routes with CDN caching.
  • Structured data is extracted from Lighthouse audits in lighthouseStoredPayload.ts and embedded as JSON-LD.
  • Authentication uses the createMiddleware wrapper in src/serverFunctions/middleware.ts, requiring only environment variables in your Next.js project.

Frequently Asked Questions

What is the MCP protocol in Open-SEO?

The Machine-Client-Protocol (MCP) is a lightweight API layer that standardizes communication between your Next.js frontend and various SEO data sources. It handles authentication, caching, and data normalization, exposing a consistent interface for requesting meta tags, rank data, and audit results without managing multiple third-party APIs directly.

How does Open-SEO handle authentication?

According to src/serverFunctions/middleware.ts, Open-SEO uses a createMiddleware wrapper that validates requests against project tokens and API keys stored in environment variables like OPENROUTER_API_KEY or DATAFORSEO_API_KEY. Your Next.js application must include the Authorization: Bearer header with the OPENSEO_PROJECT_TOKEN when calling MCP endpoints.

Can I use Open-SEO with static site generation (SSG)?

Yes. While the examples above use getServerSideProps, you can implement the same fetch logic inside getStaticProps for static generation. The MCP endpoints return JSON data suitable for both static and dynamic rendering, allowing you to build SEO-optimized pages at deploy time while keeping the Open-SEO backend as your single source of truth.

Where does Open-SEO store sitemap and robots.txt data?

The RankCheckWorkflow.ts workflow writes XML sitemaps and robots.txt files to Cloudflare KV or Postgres, depending on your deployment configuration. Your Next.js application then proxies these files via API routes, enabling efficient CDN distribution while maintaining the generation logic on the Open-SEO backend.

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 →