OpenSEO charges through third-party DataForSEO (self-hosted accounts pay 28% less); hosted mode tracks credit balance across monthly and top-up tiers via prepareRankCheckKeywords and AuditService.ts, gating rank-check and audit features behind paid-plan checks and capacity limits. Cost estimation and validation happen twice—once in prepareRankCheckKeywords using queued or live pricing, and again in triggerCheck—with caller-supplied maxCostCredits caps enforcing user approval before any external API call.
DataForSEO is a pay-as-you-go third-party service; new accounts include $1 of free credit, and the minimum top-up is $50. The DATAFORSEO_API_KEY environment variable holds a Base64-encoded email:password credential pair obtained from the DataForSEO dashboard, not a bare API token. Self-hosters pay DataForSEO directly and pay roughly 28% less than through the hosted service, which marks up every DataForSEO request by that margin.
Credit balance checks in prepareRankCheckKeywords run only in hosted mode (isHostedServerAuthMode()), combining a monthly balance (AUTUMN_SEO_DATA_BALANCE_FEATURE_ID) and a top-up balance (AUTUMN_SEO_DATA_TOPUP_BALANCE_FEATURE_ID) to determine total availability. In hosted mode, when the combined monthly and top-up credit balance is exhausted, rank-check and audit features are blocked until the balance is replenished. requireRankCheckAccess in RankTrackingService.ts is a no-op in self-hosted mode; on the hosted platform it gates access behind a paid-plan check via customerHasPaidPlan. In hosted mode, resolveAuditLimitTier in AuditService.ts maps subscription state to one of three AuditLimitTier values: 'self_hosted' (not hosted mode), 'paid' (has paid plan), or 'free' (has managed access but no paid plan). Accounts with no managed access at all receive an AppError('PAYMENT_REQUIRED').
Credit cost estimation in prepareRankCheckKeywords uses 'queued' pricing for scheduled triggers and 'live' pricing for manual triggers, because a live-price estimate for scheduled checks would incorrectly skip checks the user can afford. prepareRankCheckKeywords enforces a caller-supplied cost cap: if maxCostCredits is set and the estimated credit cost exceeds it, a VALIDATION_ERROR with a user-readable approval message is thrown before touching any external APIs. triggerCheck in RankTrackingService.ts also validates the estimated credit cost against the caller-supplied maxCostCredits budget before starting the workflow, throwing VALIDATION_ERROR if exceeded.
The includeClickstreamData parameter on the research_keywords tool is opt-in and defaults to false; enabling it doubles the credit cost per seed by using clickstream-refined volumes that disaggregate Google Ads' close-variant groupings, and has no effect for countries served from Google Ads data. When audit capacity is reached, run_site_audit returns a human-readable error directing users to delete old audits rather than throwing; it catches AppError with code "AUDIT_CAPACITY_REACHED" for this case.