# How Backlinks Analysis Works with the DataForSEO Backlinks API in OpenSEO

> Discover how OpenSEO leverages the DataForSEO Backlinks API for powerful link analysis. Learn about its three-layer architecture and seamless integration for your SEO needs.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-08-07

---

**OpenSEO implements a three-layer architecture where React client hooks call validated server functions that delegate to a centralized `BacklinksService`, which builds HTTP requests for the DataForSEO Backlinks API, maps the response fields to OpenSEO's schema, and handles credit billing and error translation.**

OpenSEO provides a robust integration with the **DataForSEO backlinks API** to deliver comprehensive backlink analysis capabilities. This open-source SEO platform wraps the external API in a type-safe TypeScript layer that handles validation, data transformation, and usage tracking. Understanding how backlinks analysis works with the DataForSEO backlinks API reveals a clean separation between client UI components, server-side validation, and the core service integration.

## Architecture Overview

The integration follows a strict three-layer pattern that isolates external API dependencies behind stable internal interfaces.

- **Client Layer**: React components in [`src/client/features/backlinks/useBacklinksPageData.ts`](https://github.com/every-app/open-seo/blob/main/src/client/features/backlinks/useBacklinksPageData.ts) consume server functions to request either a backlinks overview or a detailed profile view.

- **Server Functions**: The file [`src/serverFunctions/backlinks.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/backlinks.ts) exposes `getBacklinksOverview` and `getBacklinksProfile`, which validate incoming parameters using Zod schemas before translating them into internal service calls.

- **BacklinksService**: Located at [`src/server/features/backlinks/services/BacklinksService.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/backlinks/services/BacklinksService.ts), this core integration point builds the DataForSEO HTTP request, applies pagination and filtering, maps DataForSEO field names to OpenSEO's schema, and manages credit billing and error translation.

## Input Validation with Zod Schemas

Every request passes through strict validation defined in [`src/types/schemas/backlinks.ts`](https://github.com/every-app/open-seo/blob/main/src/types/schemas/backlinks.ts) before reaching the external API.

The system enforces **scope** restrictions distinguishing between `domain` (whole site analysis) and `page` (single URL analysis). It also validates **tab** selection across `backlinks`, `domains`, or `pages` views, plus sorting parameters, pagination controls, and the **mode** setting (`one_per_domain` versus `as_is`).

```typescript
// src/types/schemas/backlinks.ts
export const backlinksOverviewInputSchema = backlinksLookupSchema.extend({ /* … */ });
export const backlinksRowsPageRequestSchema = backlinksPageRequestBase.extend({ /* … */ });

```

If validation fails, the server returns a clear 400 error immediately, preventing unnecessary external API calls and credit consumption.

## The BacklinksService Integration Layer

The `BacklinksService` class centralizes all communication with DataForSEO's endpoints, providing a consistent interface for both overview and detailed profile data.

### Overview Requests

For high-level metrics, the service constructs a JSON payload containing the target URL, scope, and optional market codes, then posts to the `/v3/backlinks/overview` endpoint.

### Profile Requests

Detailed backlink data requires the `/v3/backlinks/backlinks` endpoint. The service passes pagination parameters, sorting directives, filters, and the selected mode to retrieve raw backlink rows.

### Field Mapping and Filtering

DataForSEO returns fields using snake_case keys such as `first_seen`, `referring_pages`, and `anchor_text`. The service maps these to OpenSEO's camelCase output schema (`firstSeen`, `referringPages`, `anchor`).

The **mode** parameter controls data granularity:

- **`one_per_domain`**: Collapses multiple backlinks from the same referring domain to return only the strongest link.
- **`as_is`**: Returns every raw backlink row without deduplication.

The platform also applies a spam-score filter, though the web interface disables DataForSEO's strict spam-score cutoff to ensure comprehensive results.

## Credit Billing and Error Handling

Backlink analysis consumes **usage credits** tracked through [`src/shared/billing.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/billing.ts). Approximate costs include:

- **Overview**: Approximately 50 credits for a domain scope, 25 credits for a single page.
- **Profile**: Approximately 30 credits per page of results (defaulting to 10 rows per page).

Self-hosted deployments pay DataForSEO directly, while hosted OpenSEO deployments deduct from the organization's credit pool.

When DataForSEO returns errors (insufficient balance, invalid targets, or spam-score rejections), `BacklinksService` catches the exception and routes it through [`src/server/lib/dataforseoBillingClassification.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseoBillingClassification.ts). This module translates raw API error messages into user-friendly error codes that the client can display appropriately.

## MCP Chat Tool Integration

OpenSEO exposes backlinks functionality to the **MCP** (chat) layer through dedicated tool implementations:

- [`src/server/mcp/tools/get-backlinks-overview.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/tools/get-backlinks-overview.ts) renders the overview as a markdown table.
- [`src/server/mcp/tools/get-backlinks-profile.ts`](https://github.com/every-app/open-seo/blob/main/src/server/mcp/tools/get-backlinks-profile.ts) streams paginated lists of raw backlink rows.

Both tools call `BacklinksService` directly, reusing the same validation logic and billing mechanisms available to the web interface.

## Implementation Examples

### Fetching Overview Data

React hooks in the client layer call the validated server function to retrieve domain or page-level backlink summaries:

```typescript
import { getBacklinksOverview } from '@/serverFunctions/backlinks';
import { useQuery } from '@tanstack/react-query';

function useBacklinksOverview(projectId: string, target: string, scope?: 'domain' | 'page') {
  return useQuery({
    queryKey: ['backlinksOverview', projectId, target, scope],
    queryFn: () =>
      getBacklinksOverview({
        data: { projectId, target, scope },
      }),
  });
}

```

This call is validated against `backlinksOverviewInputSchema` and ultimately hits the DataForSEO overview endpoint via `BacklinksService`.

### Paginated Profile Queries

For detailed backlink lists, implement infinite scrolling using the profile endpoint:

```typescript
import { getBacklinksProfile } from '@/serverFunctions/backlinks';
import { useInfiniteQuery } from '@tanstack/react-query';

function useBacklinksProfile(projectId: string, target: string, params) {
  return useInfiniteQuery({
    queryKey: ['backlinksProfile', projectId, target, params],
    queryFn: ({ pageParam = 1 }) =>
      getBacklinksProfile({
        data: {
          projectId,
          target,
          scope: params.scope,
          page: pageParam,
          sortField: params.sortField,
          sortOrder: params.sortOrder,
          mode: params.mode,
          filters: params.filters,
        },
      }),
    getNextPageParam: (lastPage) => lastPage.nextPage ?? false,
  });
}

```

The request is built from `backlinksRowsPageRequestSchema`, forwarded to DataForSEO's backlinks endpoint, and returned as `backlinksProfileOutputSchema`.

### MCP Tool Usage

From within chat conversations, invoke the overview tool directly:

```typescript
await get_backlinks_overview({
  projectId: "project_123",
  target: "example.com",
  scope: "domain",
});

```

The tool executes `BacklinksService.getOverview`, applies credit deduction, and returns a markdown table:

```

domain | backlinks | referring pages | rank
-------------------------------------------------
example.com | 1 200 | 350 | 12

```

## Summary

- OpenSEO's backlinks analysis relies on a three-layer architecture: client hooks, server functions, and the centralized `BacklinksService`.
- All inputs are validated using Zod schemas defined in [`src/types/schemas/backlinks.ts`](https://github.com/every-app/open-seo/blob/main/src/types/schemas/backlinks.ts) before external API calls occur.
- The service maps DataForSEO's snake_case fields to OpenSEO's camelCase schema and supports both `one_per_domain` and `as_is` retrieval modes.
- Credit consumption is tracked via [`src/shared/billing.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/billing.ts) with overview calls costing ~50 credits and profile pages costing ~30 credits each.
- Error handling in [`src/server/lib/dataforseoBillingClassification.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseoBillingClassification.ts) translates DataForSEO errors into actionable user messages.
- The same core functionality is exposed through web interfaces and MCP chat tools, ensuring consistent validation and billing across all entry points.

## Frequently Asked Questions

### How much do DataForSEO backlinks API calls cost in OpenSEO credits?

According to the billing implementation in [`src/shared/billing.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/billing.ts), an overview request costs approximately 50 credits for a domain scope or 25 credits for a single page scope. Each page of profile results (default 10 rows) consumes approximately 30 credits. Self-hosted instances pay DataForSEO directly, while hosted versions deduct from the organization's allocated credit pool.

### What is the difference between 'domain' and 'page' scope in the backlinks analysis?

The **scope** parameter, validated in `backlinksOverviewInputSchema`, determines whether the analysis targets an entire domain or a specific URL. Domain scope aggregates backlinks across all pages of a website, while page scope restricts the analysis to backlinks pointing to a single, specific URL. This distinction affects both the data returned and the credit cost, with domain overviews typically consuming more credits than page-specific queries.

### How does the 'one_per_domain' mode filter backlink results?

When the **mode** is set to `one_per_domain`, the `BacklinksService` instructs DataForSEO to collapse multiple backlinks originating from the same referring domain into a single entry, returning only the strongest or most relevant link from that domain. In contrast, the `as_is` mode returns every individual backlink row without deduplication, providing a complete raw dataset that includes multiple links from the same referring domain.

### Where does OpenSEO handle errors from the DataForSEO API?

Error handling occurs in [`src/server/features/backlinks/services/BacklinksService.ts`](https://github.com/every-app/open-seo/blob/main/src/server/features/backlinks/services/BacklinksService.ts), which catches exceptions from DataForSEO and routes them through [`src/server/lib/dataforseoBillingClassification.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseoBillingClassification.ts). This module translates technical API error messages (such as insufficient balance or invalid target errors) into standardized, user-friendly error codes that the React client can display to end users.