# How the Open-SEO Dashboard Service Aggregates Backlink and Ranking Data

> Learn how the Open-SEO dashboard service aggregates backlink and ranking data through parallel processing and intelligent caching. Discover efficient data aggregation for your SEO needs.

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

---

**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`](https://github.com/every-app/open-seo/blob/main/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 days
- `getBacklinkSummary` – Retrieves cached or fresh backlink metrics
- `getAuditSummary` – 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:

1. **API Client Initialization** – Creates a DataForSEO client via `createDataforseoClient`
2. **Target Normalization** – Processes the domain through `normalizeBacklinksTarget` to ensure consistent URL formatting
3. **External Fetch** – Retrieves fresh backlink metrics including domain rank, total backlinks, referring domains, and new/lost counts
4. **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`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/dashboard.ts):

```typescript
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:

```typescript
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:

```typescript
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.all` to 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 in `BacklinkSnapshotRepository` to 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 `getDashboardOverview` server 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`](https://github.com/every-app/open-seo/blob/main/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.