# How to Contribute to the OpenSEO Project: A Complete Developer's Guide

> Learn how to contribute to the open-seo project with this developer's guide. Fork the repo, set up your environment, and submit a pull request to join the effort.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-07-26

---

**To contribute to the open-seo project, fork the repository, configure a local Cloudflare Workers environment with a DataForSEO API key, and follow the six-step pull request workflow documented in [`docs/CONTRIBUTING.md`](https://github.com/every-app/open-seo/blob/main/docs/CONTRIBUTING.md).**

OpenSEO is an open-source, pay-as-you-go SEO platform that provides fully transparent alternatives to commercial tools like Semrush and Ahrefs. Built on **Cloudflare Workers**, **Drizzle ORM**, and **React**, the codebase supports both SQLite and PostgreSQL backends and exposes a Micro-service Control-Plane (MCP) for AI agent integration. This guide explains how to contribute to the open-seo project by mastering its architecture, setting up local development, and submitting high-quality pull requests.

## Understanding the OpenSEO Architecture

Before you contribute to the open-seo project, familiarize yourself with its layered architecture. The system separates concerns between serverless API endpoints, versioned database schemas, and a reactive frontend.

### Cloudflare Workers API Layer

The backend runs as a **Micro-service Control-Plane (MCP)** on Cloudflare Workers, exposing JSON-RPC-style endpoints that both the React UI and AI agents consume. Core TypeScript definitions reside in [`worker-configuration.d.ts`](https://github.com/every-app/open-seo/blob/main/worker-configuration.d.ts), while database connection logic is configured in [`drizzle.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle.config.ts) for local development and [`drizzle-prod.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle-prod.config.ts) for production deployments.

### Database Layer with Drizzle ORM

Data persistence uses **Drizzle ORM** with dual support for **SQLite** (via D1) and **PostgreSQL**. Migration files live in `drizzle/` (SQLite) and `drizzle-pg/` (PostgreSQL) directories. For example, [`drizzle-pg/0012_dashboard.sql`](https://github.com/every-app/open-seo/blob/main/drizzle-pg/0012_dashboard.sql) represents a versioned schema change that you can reference when writing new migrations.

### React Frontend with TanStack Query

The user interface is a **Vite**-powered React application styled with **Tailwind CSS**. Server-state management relies on **TanStack Query**, with wrapper utilities located in [`src/lib/query.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/query.ts) and the application entry point at [`src/app.tsx`](https://github.com/every-app/open-seo/blob/main/src/app.tsx).

### AI Agent Integration

OpenSEO exposes an **MCP server** designed for consumption by AI agents like Claude Code or OpenClaw. Reusable workflows called "skills" orchestrate API calls, with documentation and examples available in [`docs/AGENTS.md`](https://github.com/every-app/open-seo/blob/main/docs/AGENTS.md).

## Setting Up Local Development

To contribute to the open-seo project, you must configure a local environment that mirrors the Cloudflare Workers runtime and includes external API access.

1. **Clone the repository and install dependencies**:
   ```bash
   git clone https://github.com/every-app/open-seo.git
   cd open-seo
   pnpm install
   ```

2. **Configure environment variables**:
   Copy the example environment file and add your DataForSEO credentials:
   ```bash
   cp .env.example .env.local
   # Edit .env.local to set DATAFORSEO_API_KEY=your_key_here

   ```

3. **Start the development server**:
   ```bash
   pnpm dev
   ```

   This command launches the Vite frontend and a local Workers API wrapper simultaneously.

4. **Validate your setup**:
   Run the full check suite before making changes:
   ```bash
   pnpm ci:check   # Linting, type-checking, and unit tests

   pnpm test       # Playwright end-to-end tests

   ```

## Contribution Workflow

The project follows a structured six-step process for all contributions to the open-seo project.

- **Open an Issue**: Create a GitHub issue describing the bug or feature. Include minimal reproduction steps for bugs and specify which files like [`src/app.tsx`](https://github.com/every-app/open-seo/blob/main/src/app.tsx) or [`drizzle.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle.config.ts) are affected.
- **Fork and Branch**: Fork the repository and create a focused branch (e.g., `feat/keyword-export`).
- **Implement**: Write code following the existing Prettier and ESLint standards. Update documentation in `docs/` and add tests.
- **Test Locally**: Verify functionality using `pnpm dev` and target specific e2e tests with `pnpm test:e2e --grep "keyword-research"`.
- **Submit PR**: Open a pull request against `main` explaining the "what" and "why" of your changes.
- **Review**: Address feedback from maintainers until CI checks pass.

## Code Contribution Examples

When you contribute to the open-seo project, you will typically modify the API layer, frontend hooks, or AI skills.

### Adding a New API Endpoint

Create route handlers in the server directory. For example, to add a keyword retrieval endpoint:

```ts
// src/server/routes/seo.ts
import { json } from '@cloudflare/workers-types';
import { db } from '@/db';

export async function getProjectKeywords(request: Request) {
  const { projectId } = request.params;
  const keywords = await db.select().from('keywords').where({ projectId });
  return json(keywords);
}

```

Register this handler in [`src/server/index.ts`](https://github.com/every-app/open-seo/blob/main/src/server/index.ts) and add a corresponding Playwright test in [`e2e/keyword-research-navigation.spec.ts`](https://github.com/every-app/open-seo/blob/main/e2e/keyword-research-navigation.spec.ts).

### Creating a TanStack Query Hook

Frontend data fetching requires custom hooks. Create a new file in the lib directory:

```ts
// src/lib/useKeywords.ts
import { useQuery } from '@tanstack/react-query';
import { apiClient } from './apiClient';

export const useProjectKeywords = (projectId: string) =>
  useQuery(['keywords', projectId], async () => {
    const res = await apiClient.get(`/api/v1/keywords/${projectId}`);
    return res.json();
  });

```

Consume this hook in React components to display server state managed by TanStack Query.

### Defining an AI Agent Skill

AI workflows are defined as YAML skills. Create a new skill specification:

```yaml

# docs/skills/keyword-research.yaml

name: KeywordResearch
description: Guide an AI agent through a full keyword-research workflow.
steps:
  - request: GetKeywordIdeas
    args:
      query: "{{ user_input }}"
  - request: GetSearchVolume
    args:
      keywords: "{{ previous_step.result }}"

```

Skills are consumed via the MCP endpoint documented at `https://openseo.so/docs/skills/setup`.

## Key Configuration Files

Understanding these files helps you navigate the codebase effectively:

- **`wrangler.jsonc`**: Cloudflare Workers bindings, routes, and environment variable configuration.
- **[`package.json`](https://github.com/every-app/open-seo/blob/main/package.json)**: PNPM workspace definitions and npm scripts.
- **[`scripts/migrate-d1-to-postgres.ts`](https://github.com/every-app/open-seo/blob/main/scripts/migrate-d1-to-postgres.ts)**: Database migration utilities for moving between SQLite and PostgreSQL.
- **[`docs/LOCAL_DEVELOPMENT.md`](https://github.com/every-app/open-seo/blob/main/docs/LOCAL_DEVELOPMENT.md)**: Extended setup instructions beyond this guide.
- **[`docs/SELF_HOSTING_DOCKER.md`](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_DOCKER.md)** and **[`docs/SELF_HOSTING_CLOUDFLARE.md`](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_CLOUDFLARE.md)**: Deployment guides for contributors interested in operations.

## Summary

- OpenSEO is a Cloudflare Workers-based SEO platform using Drizzle ORM and React.
- To contribute to the open-seo project, you need a DataForSEO API key and PNPM installed.
- The architecture separates API routes in `src/server/`, database migrations in `drizzle/`, and TanStack Query-powered frontend code in `src/`.
- Follow the six-step workflow: Issue → Branch → Implement → Test → PR → Review.
- Reference [`docs/CONTRIBUTING.md`](https://github.com/every-app/open-seo/blob/main/docs/CONTRIBUTING.md) and [`docs/LOCAL_DEVELOPMENT.md`](https://github.com/every-app/open-seo/blob/main/docs/LOCAL_DEVELOPMENT.md) for detailed contribution policies.

## Frequently Asked Questions

### What technology stack does OpenSEO use?

OpenSEO runs on **Cloudflare Workers** with **Drizzle ORM** for database access (SQLite/Postgres) and a **React** frontend using **Vite**, **Tailwind CSS**, and **TanStack Query**. The project uses **PNPM** workspaces for monorepo management and **DataForSEO** as the external data provider.

### Is a DataForSEO API key required for local development?

Yes, you must obtain a DataForSEO API key and configure it in `.env.local` copied from `.env.example`. The application relies on this external service for SEO data, though some contributions like UI fixes may work with mock data or stubbed responses.

### How do I run tests before submitting a pull request?

Execute `pnpm ci:check` to run linting, TypeScript checks, and unit tests. Run `pnpm test` to execute Playwright end-to-end tests. All checks must pass before maintainers will merge your PR, as enforced by the continuous integration pipeline.

### Can I contribute documentation or AI skills without changing the core code?

Absolutely. You can contribute AI agent skills by adding YAML files to `docs/skills/` or improve documentation in `docs/`. These contributions follow the same PR workflow and require sign-off per the Developer Certificate of Origin (DCO) guidelines in [`docs/CONTRIBUTING.md`](https://github.com/every-app/open-seo/blob/main/docs/CONTRIBUTING.md).