How OpenSEO Handles AI-Powered Features: Onboarding Agent and Content Suggestions Architecture
OpenSEO implements AI-powered onboarding and content suggestions through Cloudflare's AI-Chat SDK and DataForSEO-integrated tool functions, using Durable Objects for persistent chat sessions and a unified credit-based billing system to meter both LLM tokens and SEO data API calls.
The every-app/open-seo repository delivers intelligent SEO assistance by combining edge-computing infrastructure with real-world search data. Its onboarding agent provides new users with a limited, credit-aware conversational experience that demonstrates the platform's capabilities while enforcing strict usage boundaries. This article examines the technical implementation of these AI features, from the Durable Object architecture to the integrated billing mechanisms that power the content suggestions engine.
The OnboardingChatAgent Durable Object Architecture
OpenSEO's onboarding agent is implemented as a Cloudflare Durable Object that ensures persistent state across worker restarts. The OnboardingChatAgent class extends AIChatAgent and is defined in /src/server/features/onboarding/OnboardingChatAgent.ts, where it manages a short, free-preview chat experience referred to internally as "Sam."
The agent authenticates the user's organization and enforces a free-question limit through a system prompt constructed between lines 26 and 55. This prompt encodes specific UX constraints including tone directives, emoji restrictions, and explicit credit-aware messaging guidelines. The LLM model itself is obtained via getChatAgentModel from /src/server/lib/openrouter.ts, which connects to OpenRouter for inference.
Each chat session persists in a SQLite-backed Durable Object, guaranteeing that conversation state survives across Cloudflare Worker restarts. This architecture enables stateful interactions while maintaining the scalability benefits of edge computing.
AI Tool Integration with DataForSEO
The agent's capabilities are extended through a curated set of tools constructed by buildOnboardingTools in /src/server/features/onboarding/onboardingChatTools.ts. These tools expose DataForSEO functionality to the LLM as callable functions, categorized into low-cost core tools and credit-consuming market tools.
Low-cost tools like read_website, get_seo_metrics, and research_keywords are available without consuming credits, while market-level tools including get_domain_overview, get_serp_results, find_serp_competitors, get_competitor_keywords, and get_backlinks_overview deduct from the onboarding credit bucket. Each tool forwards to a service layer that ultimately invokes the DataForSEO client at /src/server/lib/dataforseo/client.ts.
The meter helper function in the DataForSEO client tags each request with the creditFeature: "onboarding" property, enabling the billing layer to track consumption accurately. This design prevents accidental over-spending by requiring explicit credit checks before executing expensive market data calls.
Content Suggestions Implementation
Content suggestions are generated through the research_keywords tool, which demonstrates OpenSEO's value by providing real search volume and keyword difficulty data. When given a seed topic, the tool calls dataforseo.keywords.suggestions and returns structured data that the agent formats into a Markdown table of target keywords.
This implementation reuses the same DataForSEO service that powers the full-product "SAM" agent, but the onboarding version limits calls to a single seed topic and caps credit usage explicitly. The integration allows new users to receive actionable SEO insights based on actual search data rather than synthetic recommendations.
Unified Credit-Based Billing System
All AI consumption flows through a unified billing model defined in /src/server/billing/subscription.ts. Within OnboardingChatAgent.onChatMessage, after the model finishes generating a response, the onFinish callback (lines 70-84 in OnboardingChatAgent.ts) aggregates costs from both OpenRouter token usage and DataForSEO API calls.
The billing logic calculates openRouterCostUsd from provider metadata and records spend via trackUsageCreditSpend with the parameters creditFeature: "onboarding", costUsd, and customerId. If the checkUsageCreditsDepleted function determines the organization has exhausted its balance, the agent returns a static "Subscribe to continue" message rather than processing further tool calls.
This architecture ensures that both LLM-token spend and SEO data API costs are deducted from the same "onboarding-plan" credit balance, simplifying accounting while allowing precise free-tier enforcement.
Client-Side Integration Example
Frontend applications interact with the onboarding agent through Cloudflare's AI-Chat SDK. The useAgent hook connects to the Durable Object endpoint and manages message streaming.
import { useAgent } from "@cloudflare/ai-chat";
function OnboardingChat({ projectId }: { projectId: string }) {
const { sendMessage, messages } = useAgent({
name: projectId, // Durable Object name = projectId
endpoint: "/agents/onboarding", // Route defined in routeTree
});
// UI rendering omitted – just call sendMessage and display messages
}
The name parameter maps directly to the Durable Object identifier, while the endpoint routes to the OnboardingChatAgent instance.
Tool Definition and Metering Example
Tools are defined as structured objects with Zod-like parameter schemas and async handlers. The research_keywords tool demonstrates how DataForSEO calls are wrapped with credit attribution:
export function buildOnboardingTools({ project, billingCustomer }) {
return {
read_website: {
description: "Read pages as plain text",
parameters: { urls: { type: "array", items: { type: "string" } } },
handler: async ({ urls }) => {
// internal scraper, no credits used
return await readWebsite(urls);
},
},
research_keywords: {
description:
"Return related keywords with real search volume and difficulty",
parameters: {
seed_topic: { type: "string", description: "Primary topic" },
},
handler: async ({ seed_topic }) => {
// DataForSEO client – credit‑metered
return await dataforseo.keywords.suggestions({
keyword: seed_topic,
country: project.country,
});
},
},
// …other market tools omitted for brevity
};
}
Billing Hook Implementation
Credit consumption is recorded in the onFinish event handler, which aggregates per-step costs from the LLM provider:
async function trackSpend(event: FinishEvent) {
const costUsd = event.steps.reduce(
(sum, step) => sum + openRouterCostUsd(step.providerMetadata),
0
);
await trackUsageCreditSpend({
customer: billingCustomer,
customerId: organizationId,
creditFeature: "onboarding",
costUsd,
monthlyRemaining,
properties: { provider: "openrouter" },
});
}
This function sums token costs across all reasoning steps and persists the transaction to the organization's credit ledger.
Summary
- OpenSEO implements AI features through Cloudflare Durable Objects that extend
AIChatAgent, ensuring persistent, stateful conversations at the edge. - The onboarding agent uses a system prompt-driven architecture to enforce UX constraints and tone while limiting responses to credit-aware messaging.
- DataForSEO integration provides real search data through function-calling tools, with
research_keywordspowering the content suggestions feature via actual volume and difficulty metrics. - A unified billing system meters both LLM tokens and SEO API calls against a single credit balance, using
trackUsageCreditSpendwithcreditFeature: "onboarding"to enforce free-tier limits. - Tool gating mechanisms distinguish between free low-cost tools (
read_website) and credit-consuming market tools (get_serp_results), preventing accidental overspending.
Frequently Asked Questions
What infrastructure powers OpenSEO's AI onboarding agent?
OpenSEO's onboarding agent runs on Cloudflare Durable Objects with SQLite persistence, utilizing the AI-Chat SDK for real-time messaging. The agent extends the AIChatAgent class defined in /src/server/features/onboarding/OnboardingChatAgent.ts and obtains its LLM through getChatAgentModel from /src/server/lib/openrouter.ts, routing inference through OpenRouter while maintaining conversation state across worker restarts.
How does OpenSEO prevent users from exceeding free AI usage limits?
The platform enforces limits through trackUsageCreditSpend in /src/server/billing/subscription.ts, which checks customerHasManagedAccess and checkUsageCreditsDepleted before processing requests. Each LLM call and DataForSEO API request is metered against an "onboarding" credit bucket; when exhausted, the OnboardingChatAgent returns a static subscription message rather than processing additional tool calls.
What is the difference between low-cost and market-level tools in OpenSEO?
Low-cost tools like read_website and research_keywords are available during onboarding without consuming credits, while market-level tools including get_domain_overview, get_serp_results, and get_backlinks_overview deduct from the organization's credit balance. This distinction is implemented in buildOnboardingTools at /src/server/features/onboarding/onboardingChatTools.ts, where the meter helper tags expensive calls for billing attribution.
How are content suggestions generated in OpenSEO?
Content suggestions are produced by the research_keywords tool, which calls dataforseo.keywords.suggestions through the client at /src/server/lib/dataforseo/client.ts. Given a seed topic, the tool returns real-world search volume and competition difficulty data, which the LLM formats into a Markdown table of target keywords. The onboarding version limits these calls to single seeds and caps credit usage to stay within free-tier boundaries.
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 →