How Rank Tracking Is Implemented in OpenSEO: Architecture and Code Walkthrough
OpenSEO implements rank tracking through a four-layer architecture that combines PostgreSQL schema definitions, Zod validation schemas, pure business-logic utilities, and API endpoints orchestrating DataForSEO service calls.
The every-app/open-seo repository provides a production-ready implementation of SEO rank tracking that balances cost efficiency with scheduling flexibility. Understanding how rank tracking is implemented in this TypeScript codebase reveals a modular design that separates database concerns, validation logic, and external API orchestration into discrete, testable units.
Database Schema for Rank Tracking Configurations
The foundation of rank tracking in OpenSEO lives in src/db/schema.ts, which defines the rank_tracking_configs table. This table stores both static configuration parameters and runtime state fields.
Each configuration row tracks the target domain, location settings, device preferences (desktop, mobile, or both), SERP crawl depth, and check frequency (daily, weekly, or monthly). Runtime fields include nextCheckAt for scheduling and lastSkipReason for debugging execution failures.
This declarative approach allows the system to treat rank tracking as configuration-driven background jobs rather than hardcoded processes.
Validation Layer with Zod Schemas
Before any database operations occur, OpenSEO validates all incoming payloads using Zod schemas defined in src/types/schemas/rank-tracking.ts. This layer prevents malformed data from reaching the business logic or external APIs.
The module exports four primary schemas:
createConfigSchema– Validates new rank tracking configurationsupdateConfigSchema– Validates partial updates to existing configstriggerCheckSchema– Validates manual check requestsestimateCostSchema– Validates cost estimation requests
This validation strategy ensures type safety across the API surface while providing clear error messages to API consumers.
Business Logic Utilities in src/shared/rank-tracking.ts
All core calculations and transformations live in src/shared/rank-tracking.ts. This module contains pure functions that handle cost estimation, scheduling, and UI formatting without side effects.
Cost Estimation Functions
The estimateRankCheckCredits and estimateScheduledRankCheckCredits functions calculate both USD and credit costs based on four parameters: keyword count, device count, SERP depth, and execution method (live or queued).
import { estimateRankCheckCredits } from '@/shared/rank-tracking';
import type { RankTrackingConfig } from '@/types/schemas/rank-tracking';
const config: RankTrackingConfig = {
devices: 'both',
serpDepth: 30,
// other required fields...
};
const { costUsd, costCredits } = estimateRankCheckCredits(
150, // keywordCount
config.devices,
config.serpDepth,
'live', // method: 'live' for immediate checks
);
console.log(`Live check will cost $${costUsd} (${costCredits} credits)`);
Live checks cost more than queued checks because they bypass the batching optimization. The estimateScheduledRankCheckCredits function specifically handles the queued method for background jobs.
Scheduling Logic
The computeNextCheckAt function generates ISO 8601 timestamps for the next execution based on the schedule type (daily, weekly, or monthly). It handles timezone drift and implements randomized execution windows to prevent thundering herd problems against the DataForSEO API.
import { computeNextCheckAt } from '@/shared/rank-tracking';
const nextRun = computeNextCheckAt('weekly');
console.log('Next weekly check scheduled for:', nextRun);
This function appears in src/shared/rank-tracking.ts around lines 78-95 and 100-124, implementing drift compensation to ensure checks run at consistent local times regardless of daylight saving changes.
UI Label Helpers
The module exports formatting utilities including devicesLabel, scheduleLabel, and devicesCount. These convert database enums into human-readable strings for dashboard displays and calculate the numeric device multiplier used in cost equations.
API Routes and Execution Flow
The route tree defined in src/routeTree.gen.ts wires HTTP endpoints to service functions that coordinate the validation, database, and DataForSEO layers.
A typical rank check flow follows this sequence:
- The request body validates against Zod schemas from
src/types/schemas/rank-tracking.ts - The service creates or updates a row in
rank_tracking_configs - For manual triggers, the service calls the DataForSEO live endpoint immediately
- For scheduled execution, the system enqueues a queued task using the cost-effective batch API
- The billing module (
src/shared/billing.ts) applies charges using theAUTUMN_SEO_DATA_CREDITS_PER_USDconversion rate
This separation allows the same cost estimation logic to preview expenses before execution while ensuring users cannot exceed their credit balance.
Background Task Execution and Error Handling
Scheduled rank checks execute via background workers that poll active configurations. The worker uses computeNextCheckAt to determine eligibility, then calls DataForSEO via the queued method for cost efficiency.
When checks cannot execute, the system records a RankTrackingSkipReason in src/shared/rank-tracking.ts. The three possible values are:
plan_required– No active subscription existsno_keywords– Configuration lacks associated keywordsinsufficient_credits– Cost estimation exceeds available balance
These skip reasons appear in the lastSkipReason column of rank_tracking_configs, providing transparency for debugging failed executions.
Summary
OpenSEO implements rank tracking through a clean separation of concerns that prioritizes testability and cost transparency:
- Database layer stores configuration and state in
rank_tracking_configs(defined insrc/db/schema.ts) - Validation layer uses Zod schemas in
src/types/schemas/rank-tracking.tsto enforce type safety - Business logic layer provides pure functions for cost estimation (
estimateRankCheckCredits), scheduling (computeNextCheckAt), and formatting insrc/shared/rank-tracking.ts - API layer routes requests through the generated tree in
src/routeTree.gen.ts, choosing between live and queued DataForSEO execution methods - Billing integration converts USD estimates to credit deductions via
src/shared/billing.ts
Frequently Asked Questions
How does OpenSEO calculate the cost of a rank tracking check?
OpenSEO calculates costs through the estimateRankCheckCredits function in src/shared/rank-tracking.ts. The calculation multiplies keyword count by device count (1 for single device, 2 for both) and SERP depth, then applies different rates for live versus queued execution methods. The billing.ts module then converts the USD estimate into platform credits using the AUTUMN_SEO_DATA_CREDITS_PER_USD constant.
What is the difference between live and queued rank checks?
Live checks execute immediately against the DataForSEO API at premium pricing, suitable for on-demand validation. Queued checks execute through the batch processing endpoint at lower cost, making them ideal for scheduled monitoring. The estimateRankCheckCredits function accepts a method parameter to distinguish between these modes, while the API routes automatically select the appropriate endpoint based on whether the request is manual or scheduled.
How does OpenSEO handle scheduling for recurring rank checks?
The computeNextCheckAt function in src/shared/rank-tracking.ts handles all scheduling logic. It accepts a schedule type ('daily', 'weekly', or 'monthly') and returns the next ISO 8601 timestamp. The implementation includes drift compensation to maintain consistent local execution times and randomization to prevent API rate limiting. Background workers reference this timestamp to determine when to enqueue the next check.
What happens when a rank tracking job fails due to insufficient credits?
When cost estimation exceeds the available balance, the system records insufficient_credits as the RankTrackingSkipReason in the configuration's lastSkipReason field. Other skip reasons include plan_required (missing subscription) and no_keywords (empty keyword list). These values are defined in src/shared/rank-tracking.ts and allow the dashboard to display specific failure explanations without exposing internal error details.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →