Two‑Phase Rank Tracking in OpenSEO: How Configuration and Execution Stay Separate
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 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 - Keywords are added via
add-rank-tracking-keywords.tsbut stored only in the database - Schedule is set to
manual,daily,weekly, ormonthly— this determines when Phase 2 triggers - Cost estimates are available through
estimate-rank-tracker-cost.tsbefore 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, the configuration object persists to the database without initiating any external requests:
// 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
RankCheckWorkflowtriggers at scheduled time or on-demand- SERP requests fire for every keyword-location-device combination
- Results populate
rank_tracking_snapshottables 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 - Same step-framework used for site-audit crawls ensures consistency
The execution phase is orchestrated by src/server/workflows/RankCheckWorkflow.ts:
// 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.
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 |
Orchestrates both phases with step-based execution |
src/server/mcp/tools/create-rank-tracker.ts |
Phase 1 entry point — configuration creation |
src/server/mcp/tools/add-rank-tracking-keywords.ts |
Phase 1 keyword management |
src/server/mcp/tools/estimate-rank-tracker-cost.ts |
Pre-execution cost preview |
src/server/features/rank-tracking/repositories/snapshotQueries.ts |
Phase 2 result storage and retrieval |
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
RankCheckWorkflowcoordinates 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. 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 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.
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 →