How the Open-SEO Dashboard Service Aggregates Backlink and Ranking Data
The DashboardService aggregates backlink and ranking data by parallelizing three distinct data streams—activation status, rank summaries, and backlink snapshots—while implementing intelligent caching to minimize external API costs.
The Open-SEO dashboard presents a unified view of search performance metrics by combining Google Search Console activation states, keyword ranking trends, and backlink profiles. At the heart of this aggregation lies the DashboardService, which orchestrates data from multiple repositories and external APIs to deliver real-time insights. Understanding how this service aggregates backlink and ranking data reveals the architectural patterns that keep the dashboard both responsive and cost-effective.
Architecture of the Dashboard Aggregation Pipeline
The DashboardService.getOverview method serves as the central orchestrator, fetching three logical sections in parallel via Promise.all. This pattern ensures that slow external API calls do not block database queries or vice versa.
In src/server/features/dashboard/services/DashboardService.ts lines 95-104, the service awaits three concurrent operations:
getRankSummary– Aggregates keyword tracking metrics from the last 7 daysgetBacklinkSummary– Retrieves cached or fresh backlink metricsgetAuditSummary– Pulls the latest site audit results
This parallel execution model allows the React-Start client to render a complete overview in a single round-trip, even when individual data sources have varying latency characteristics.
Rank Summary Aggregation Logic
The ranking data aggregation follows a capped processing pattern to prevent performance degradation on projects with extensive keyword tracking configurations.
Configuration Loading and Limiting
First, the service loads rank-tracking configurations via RankTrackingRepository.getConfigsForProject. To maintain predictable response times, the implementation enforces a hard cap defined by the constant MAX_CONFIGS_FOR_OVERVIEW = 5. This limit ensures that projects with dozens of tracking configurations do not trigger excessive database queries.
7-Day Trend Calculation
For each configuration (up to the cap), the service fetches the latest 7-day results using getLatestResults. The aggregation logic in getRankSummary (lines 107-147) iterates over these rows to compute:
- Total tracked keywords – Count of distinct keywords under monitoring
- Position improvements and declines – Comparison of current versus previous positions
- Top-10 distribution – Keywords currently ranking in positions 1-10
- Last-checked timestamp – Most recent data point for freshness indication
This approach provides trend visibility without requiring time-series database storage for the dashboard view.
Backlink Summary with Snapshot Caching
The backlink aggregation implements a snapshot caching strategy to balance data freshness against API costs, specifically when integrating with the DataForSEO API.
Freshness Validation
Before fetching new data, the service checks BacklinkSnapshotRepository.getLatestForProject to locate an existing snapshot for the current domain. The helper function isSnapshotFresh (lines 81-85) validates whether the snapshot timestamp falls within SNAPSHOT_MAX_AGE_MS (24 hours). If fresh, the cached data returns immediately, avoiding unnecessary external calls.
On-Demand Data Refresh
When the snapshot is missing or stale, ensureBacklinkSnapshot (lines 119-166) executes the following workflow:
- API Client Initialization – Creates a DataForSEO client via
createDataforseoClient - Target Normalization – Processes the domain through
normalizeBacklinksTargetto ensure consistent URL formatting - External Fetch – Retrieves fresh backlink metrics including domain rank, total backlinks, referring domains, and new/lost counts
- Persistence – Stores the normalized result back into the snapshot table for subsequent requests
This pattern ensures that the dashboard never displays data older than 24 hours while preventing redundant API charges from repeated page loads.
Code Implementation Examples
Exposing the Dashboard via Server Functions
The client consumes the aggregation through a typed server function defined in src/serverFunctions/dashboard.ts:
export const getDashboardOverview = createServerFn({ method: "POST" })
.middleware(requireProjectContext)
.validator(dashboardProjectInputSchema)
.handler(({ context }) =>
DashboardService.getOverview({
projectId: context.projectId,
domain: context.project.domain,
})
);
This endpoint encapsulates the parallel aggregation logic, providing the UI with a single object containing activation status, rank summaries, and backlink metrics.
Direct Service Invocation
For administrative scripts or background jobs, import the service directly:
import { DashboardService } from "@/server/features/dashboard/services/DashboardService";
async function printOverview(projectId: string, domain: string) {
const overview = await DashboardService.getOverview({ projectId, domain });
console.log("Rank summary:", overview.rank);
console.log("Backlink summary:", overview.backlinks);
}
Forcing Backlink Snapshot Refresh
When the UI detects stale data or when a user explicitly requests an update, trigger a fresh fetch bypassing the cache check:
import { DashboardService } from "@/server/features/dashboard/services/DashboardService";
import type { BillingCustomerContext } from "@/server/billing/subscription";
async function refresh(projectId: string, domain: string, billing: BillingCustomerContext) {
const fresh = await DashboardService.ensureBacklinkSnapshot({
projectId,
domain,
billingCustomer: billing,
});
console.log("Refreshed snapshot:", fresh);
}
Note that the billing context is required here, as fresh DataForSEO API calls may incur costs against the customer's subscription quota.
Summary
- Parallel Aggregation: The dashboard service uses
Promise.allto fetch rank summaries, backlink snapshots, and audit data concurrently, minimizing total response time. - Capped Processing: Rank tracking queries are limited to
MAX_CONFIGS_FOR_OVERVIEW(5 configurations) to ensure consistent performance regardless of project size. - Snapshot Caching: Backlink data leverages a 24-hour snapshot cache (
SNAPSHOT_MAX_AGE_MS) stored inBacklinkSnapshotRepositoryto reduce DataForSEO API costs. - Lazy Refresh: Stale or missing backlink snapshots trigger
ensureBacklinkSnapshot, which normalizes targets and persists fresh data for future requests. - Single Endpoint: The
getDashboardOverviewserver function exposes the entire aggregation as a unified payload, optimizing network efficiency for the React-Start frontend.
Frequently Asked Questions
How does the dashboard handle projects with hundreds of rank-tracking configurations?
The service enforces a hard limit of MAX_CONFIGS_FOR_OVERVIEW = 5 when calling RankTrackingRepository.getConfigsForProject. This cap ensures that the aggregation query remains performant by only analyzing the most recent configurations rather than scanning entire project histories.
What triggers a fresh backlink data fetch from DataForSEO?
The isSnapshotFresh helper checks whether the existing snapshot timestamp is younger than SNAPSHOT_MAX_AGE_MS (24 hours). If the snapshot is missing or older than this threshold, ensureBacklinkSnapshot initiates a new API call to DataForSEO, normalizes the response via normalizeBacklinksTarget, and updates the database cache.
Why does the backlink refresh function require billing context?
The ensureBacklinkSnapshot method accepts a BillingCustomerContext parameter because live DataForSEO API calls consume subscription credits or quota. Passing the billing context allows the service to validate that the customer has sufficient resources before executing costly external requests.
Where is the rank summary calculation logic implemented?
The rank aggregation logic resides in getRankSummary within src/server/features/dashboard/services/DashboardService.ts (lines 107-147). This method iterates over the latest 7-day results for each tracked configuration to calculate keyword counts, position changes, and top-10 distributions.
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 →