# How the DataForSEO API Client Handles Billing Metering and Lazy Loading in Open SEO

> Learn how the DataForSEO API client in Open SEO uses dynamic imports for lazy loading and a meter helper for billing metering. Ensure efficient API usage and cost control.

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

---

**The DataForSEO API client in Open SEO uses dynamic imports to lazy-load the heavy SDK on first request, while wrapping every fetch method with a meter helper that checks usage credits before execution and records exact costs afterward.**

The Open SEO repository implements a sophisticated integration with the DataForSEO API that solves two critical operational challenges: keeping the server bundle size minimal and ensuring accurate usage-based billing. This article examines how the DataForSEO API client manages billing metering and lazy loading through a combination of dynamic imports and credit-tracking wrappers.

## Lazy Loading Architecture

The client keeps the approximately 3 MB DataForSEO SDK out of the eager startup graph by isolating all heavy SDK code in a separate lazy chunk. When you create a client instance using `createDataforseoClient()`, the methods themselves are lightweight proxies that do not immediately import the SDK.

Instead, each method calls `loadDataforseoSections()`, which performs a dynamic import of the section barrel at [`src/server/lib/dataforseo/sections.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/sections.ts). This ensures the large DataForSEO SDK loads only when a method is first invoked, significantly improving cold-start performance. The lazy-loading boundary is explicitly documented in [`src/server/lib/dataforseo/client.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/client.ts) with a comment explaining that the sections are loaded on demand via `import("@/server/lib/dataforseo/sections")`.

## Billing Metering Flow

Every public fetch method is wrapped by the `meter` helper, which implements a consistent billing pattern across all DataForSEO operations. The `meter` function receives the customer context, a picker that selects the concrete fetcher from the lazy-loaded sections, and an optional default credit feature.

The wrapper returns a function that executes the following sequence:

1. **Credit Feature Resolution** – Determines the credit feature using `input.creditFeature ?? defaultFeature`. The mapping from API paths to credit features is defined in [`src/shared/billing-credit-features.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/billing-credit-features.ts).
2. **Pre-flight Validation** – Checks the organization's usage-credit balance before executing the request.
3. **Execution and Tracking** – Runs the DataForSEO request and records the exact provider-reported cost via `trackUsageCreditSpend`.

### Hosted Mode Credit Checks

When running in hosted mode (`isHostedServerAuthMode()` returns true), the `meterDataforseoCall` function implements full billing integration:

- **Customer Resolution** – Calls `getOrCreateOrganizationCustomer` to resolve the Autumn customer associated with the organization.
- **Balance Validation** – Uses `assertUsageCreditsAvailable` to verify sufficient credits exist before proceeding.
- **Cost Tracking** – After successful execution, `trackDataforseoCost` records the exact `billing.costUsd` and updates the credit balance.
- **Error Handling** – Even errors that already incurred a charge (such as `DataforseoChargedTaskError`) are tracked via `trackDataforseoCost` before re-throwing the exception.

This logic appears in [`src/server/lib/dataforseo/client.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/client.ts) between lines 37 and 88, ensuring every hosted request either charges the organization accurately or fails fast if credits are insufficient.

### Non-Hosted Mode Bypass

In self-hosted deployments where `isHostedServerAuthMode()` returns false, the wrapper skips all credit checks and billing logic entirely. The meter simply returns the raw result from the underlying DataForSEO fetcher without interacting with Autumn or the credit system. This design matches the specification outlined in [`specs/0002-hosted-dataforseo-metering-with-autumn.md`](https://github.com/every-app/open-seo/blob/main/specs/0002-hosted-dataforseo-metering-with-autumn.md), which defines the responsibilities and bypass conditions for non-hosted environments.

## Implementation Details

The client architecture separates concerns across three distinct layers:

**Client Creation** – `createDataforseoClient(customer)` receives a `BillingCustomerContext` and returns an object with methods like `serp.live` and `keywords.related`. Each method is constructed using the `meter` helper, binding the specific DataForSEO endpoint to the billing wrapper.

**Credit Feature Mapping** – The system uses strongly-typed credit features defined in [`src/shared/billing-credit-features.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/billing-credit-features.ts) to categorize spend by API endpoint. This enables granular analytics and cost attribution across different types of SEO data (SERP results, keyword research, etc.).

**Meter Wrapper** – The `meter` function abstracts the complexity of async loading and billing verification. It handles the dynamic import of sections, the conditional billing logic based on server mode, and the translation of DataForSEO responses into usage credit records.

## Usage Examples

### Creating a Client and Executing a Metered Request

```typescript
import { createDataforseoClient } from "@/server/lib/dataforseo";

// billingCustomer is a BillingCustomerContext obtained from the request
const dataforseo = createDataforseoClient(billingCustomer);

// Fetch live SERP results with automatic billing metering
const serpResults = await dataforseo.serp.live({
  target: "google.com",
  location_code: 2840, // United States
});

```

This call triggers `loadDataforseoSections()` to dynamically import the SDK, then executes the billing flow before returning results.

### Overriding Credit Features for Specific Requests

```typescript
const result = await dataforseo.keywords.related({
  keyword: "open seo",
  // Attribute spend to a custom feature instead of the default "keyword_research"
  creditFeature: "ai_citations",
});

```

The `meter` wrapper reads `input.creditFeature` and uses this value when recording the usage credit spend, allowing flexible cost attribution across different product features.

### Direct Execution in Non-Hosted Mode

```typescript
// In self-hosted deployments without Autumn integration
const rawResult = await dataforseo.labs.keywordOverview({
  target: "open seo",
});

```

When `isHostedServerAuthMode()` is false, the wrapper bypasses `assertUsageCreditsAvailable` and `trackDataforseoCost`, returning the raw provider data without billing side effects.

## Summary

- **Lazy Loading** – The DataForSEO SDK (~3 MB) loads only on first use via `loadDataforseoSections()`, which dynamically imports [`src/server/lib/dataforseo/sections.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/sections.ts).
- **Billing Wrapper** – Every method uses the `meter` helper to enforce consistent credit checking and cost tracking across all API calls.
- **Hosted Mode** – Validates credits via `assertUsageCreditsAvailable`, resolves Autumn customers with `getOrCreateOrganizationCustomer`, and records exact costs using `trackDataforseoCost`.
- **Non-Hosted Mode** – Skips billing logic entirely when `isHostedServerAuthMode()` is false, executing requests directly.
- **Credit Features** – Maps API endpoints to billing categories defined in [`src/shared/billing-credit-features.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/billing-credit-features.ts) for granular spend tracking.

## Frequently Asked Questions

### How does the client prevent the DataForSEO SDK from bloating the server startup?

The client uses dynamic imports via `loadDataforseoSections()` to defer loading of [`src/server/lib/dataforseo/sections.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/dataforseo/sections.ts) until the first API method is called. This keeps the heavy SDK out of the initial server bundle, reducing cold-start times and memory footprint until SEO data is actually requested.

### What happens if an organization runs out of credits during a request?

The `meterDataforseoCall` function calls `assertUsageCreditsAvailable` before executing any DataForSEO request. If insufficient credits exist, the function throws an error immediately, preventing the API call from executing and consuming provider resources that couldn't be billed.

### How does the system handle partial failures or errors that still incur costs?

The billing wrapper catches `DataforseoChargedTaskError` and other error conditions that indicate the provider already processed the request. Before re-throwing the error, it calls `trackDataforseoCost` to record the incurred cost against the organization's credit balance, ensuring accurate billing even for failed operations.

### Can I use the DataForSEO client without the Autumn billing system?

Yes. When `isHostedServerAuthMode()` returns false (typical in self-hosted deployments), the `meter` wrapper skips all credit checks and directly returns the raw DataForSEO result. This allows the client to function as a thin proxy over the provider API without requiring Autumn integration or credit management.