# Two‑Phase Rank Tracking in OpenSEO: How Configuration and Execution Stay Separate

> Discover OpenSEO's two-phase rank tracking. Separate configuration from execution to plan your SEO projects cost-free before running live data collection and spending credits.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: internals
- Published: 2026-09-01

---

**OpenSEO uses a two-phase rank-tracking approach that separates configuration (planning) from execution (SERP queries), letting you set up tracking projects at zero cost before spending credits on live data collection.**

The **every-app/open-seo** repository implements rank tracking through a deliberate split between *what to track* and *when to collect data*. This design prevents accidental credit consumption and gives teams full control over their DataForSEO API spending. The two-phase approach is fully documented in [`specs/0008-local-rank-tracking-locations.md`](https://github.com/every-app/open-seo/blob/main/specs/0008-local-rank-tracking-locations.md) and implemented across the `RankCheckWorkflow` orchestration layer.

---

## Phase 1: Configuration (Setup) – "Planning"

The first phase builds a **rank-tracking configuration** without making any external API calls. You define the scope, schedule, and keywords while spending zero credits.

### What Happens During Configuration

- A new tracker is created with domain, target market, devices, and locations specified in [`create-rank-tracker.ts`](https://github.com/every-app/open-seo/blob/main/create-rank-tracker.ts)
- Keywords are added via [`add-rank-tracking-keywords.ts`](https://github.com/every-app/open-seo/blob/main/add-rank-tracking-keywords.ts) but stored only in the database
- Schedule is set to `manual`, `daily`, `weekly`, or `monthly` — this determines when Phase 2 triggers
- Cost estimates are available through [`estimate-rank-tracker-cost.ts`](https://github.com/every-app/open-seo/blob/main/estimate-rank-tracker-cost.ts) before any commitment

### Key Configuration Characteristics

- **Zero credit consumption** until execution begins
- Full preview of intended queries and estimated spend
- DataForSEO SERP endpoints remain untouched
- Configurations are reusable and editable before activation

In [`src/server/mcp/tools/create-rank-tracker.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/tools/create-rank-tracker.ts), the configuration object persists to the database without initiating any external requests:

```typescript
// Phase 1: Create configuration (no credits spent)
await createRankTracker({
  projectId,
  domain: "example.com",
  market: "us",
  devices: ["mobile", "desktop"],
  locations: [{ country: "US", city: "New York" }],
  schedule: "weekly", // or "manual", "daily", "monthly"
});

```

---

## Phase 2: Execution (Run) – "Tracking"

The second phase dispatches actual SERP requests and stores results as **rank-tracking snapshots**. This is where DataForSEO credits are consumed.

### What Happens During Execution

- `RankCheckWorkflow` triggers at scheduled time or on-demand
- SERP requests fire for every keyword-location-device combination
- Results populate `rank_tracking_snapshot` tables for querying and visualization
- Subsequent runs update snapshots, enabling trend analysis

### Key Execution Characteristics

- **Credits spent per SERP request** based on depth, device, and location
- Snapshots are versioned and queryable through [`snapshotQueries.ts`](https://github.com/every-app/open-seo/blob/main/snapshotQueries.ts)
- Same step-framework used for site-audit crawls ensures consistency

The execution phase is orchestrated by [`src/server/workflows/RankCheckWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/RankCheckWorkflow.ts):

```typescript
// Phase 2A: Estimate cost before committing
const estimate = await estimateRankTrackerCost({
  trackerId,
});
console.log(`Estimated credits: ${estimate.totalCredits}`);

// Phase 2B: Trigger live SERP collection (credits consumed)
await startRankTrackingRun({ trackerId });

```

Results are then accessible through the snapshot repository at [`src/server/features/rank-tracking/repositories/snapshotQueries.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/rank-tracking/repositories/snapshotQueries.ts).

---

## Why the Two-Phase Design Matters

**Cost transparency** is the primary benefit. Teams can build entire tracking programs, review estimates, and get stakeholder approval before any API spend occurs.

**Operational flexibility** follows — manual trackers allow ad-hoc research, while scheduled trackers automate ongoing monitoring without repeated setup.

**Architectural consistency** ties the approach to OpenSEO's broader workflow pattern: every long-running operation breaks into discrete, testable steps with clear state transitions.

---

## Core Implementation Files

| File Path | Purpose |
|-----------|---------|
| [`src/server/workflows/RankCheckWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/src/server/workflows/RankCheckWorkflow.ts) | Orchestrates both phases with step-based execution |
| [`src/server/mcp/tools/create-rank-tracker.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/tools/create-rank-tracker.ts) | Phase 1 entry point — configuration creation |
| [`src/server/mcp/tools/add-rank-tracking-keywords.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/tools/add-rank-tracking-keywords.ts) | Phase 1 keyword management |
| [`src/server/mcp/tools/estimate-rank-tracker-cost.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/tools/estimate-rank-tracker-cost.ts) | Pre-execution cost preview |
| [`src/server/features/rank-tracking/repositories/snapshotQueries.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/rank-tracking/repositories/snapshotQueries.ts) | Phase 2 result storage and retrieval |
| [`specs/0008-local-rank-tracking-locations.md`](https://github.com/every-app/open-seo/blob/main/specs/0008-local-rank-tracking-locations.md) | Design specification for the two-phase approach |

---

## Summary

- **Phase 1 (Configuration)** lets you define what to track and when, with **zero credit cost**
- **Phase 2 (Execution)** dispatches DataForSEO SERP requests and stores **versioned snapshots**
- The split prevents accidental spending and enables **cost estimation** before commitment
- `RankCheckWorkflow` coordinates both phases using OpenSEO's shared step-framework

---

## Frequently Asked Questions

### How do I check the estimated cost before running a rank-tracking job?

Use `estimateRankTrackerCost()` from [`src/server/mcp/tools/estimate-rank-tracker-cost.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/tools/estimate-rank-tracker-cost.ts). Pass the `trackerId` created during Phase 1 to receive a credit breakdown based on keyword count, locations, devices, and search depth. This call consumes no credits itself.

### Can I change keywords after creating a rank-tracking configuration?

Yes. Phase 1 remains open until you trigger Phase 2 execution. Call `addRankTrackingKeywords()` or modify the configuration through the MCP tools. Scheduled trackers will use the latest keyword set when their next run triggers.

### What happens to historical data when a new execution runs?

Previous snapshots remain intact. The [`snapshotQueries.ts`](https://github.com/every-app/open-seo/blob/main/snapshotQueries.ts) repository stores each execution as a separate snapshot record with timestamps. Query by date range to build trend visualizations or feed historical data into OpenSEO's AI agent.

### Does manual scheduling mean I lose automation features?

No. Manual trackers simply require explicit `startRankTrackingRun()` calls. You still get full snapshot storage, cost tracking, and AI agent integration. Switch a manual tracker to a schedule at any time without losing accumulated data.