Ship the SEO engine into your product.
Ascent is the autonomous SEO engine behind the app — pure ESM cores plus a two-seam adapter contract. Embed it, self-host it, or white-label it. One engine, six ways to ship it.
createSeoAgent()
One facade over the cores. Trusted/untrusted split — the browser never holds keys.
HTTP service
One Request→Response router, Bearer-licensed, secrets server-side.
MCP server
Zero-dep stdio server, six SEO tools, for Claude and other MCP clients.
Claude skill
Drop-in ascent-seo skill — MCP-preferred, script fallback.
Browser widgets
Pure build/mount widgets — rank badge, potential gauge, result card.
Admin cockpit
Operator panels — proposals, keywords, rankings — writes via your onAction.
Architecture & integration brief
The full developer document — runtime profile, the six surfaces, the action lifecycle, a safe adoption path and the production checklist.
Analyze a site in about a minute.
Install the SDK, point it at a site with the sitemap content adapter, and run an audit. No keys needed for analyze().
# install (licensed — see the access note below)
npm i @ascent/seo-agent
import { createSeoAgent, sitemapAdapter } from '@ascent/seo-agent'
// the sitemap adapter is the no-code source of pages to audit
const { listIndexableEntities } = sitemapAdapter({ origin: 'https://acme.com' })
const seo = createSeoAgent(
{ site: { domain: 'acme.com' } },
{ listIndexableEntities },
)
const { issues } = await seo.analyze()
console.log(issues)
generate() (AI content proposals) and run() (the job loop) take the provider and storage seams — see the SDK section.
The SDK — one facade, four profiles.
createSeoAgent(config, deps) wraps the pure cores and returns { analyze, generate, run }. A runtime layer detects Node / Deno / edge / browser and splits trusted (server, holds keys) from untrusted (browser, proxies secret calls to the service). An offline ES256 license gate reuses your entitlements.
import { createSeoAgent, sitemapAdapter, memoryStore } from '@ascent/seo-agent'
const seo = createSeoAgent(
{ site: { domain: 'acme.com' }, serviceUrl: 'https://your-service' },
{
listIndexableEntities: sitemapAdapter({ origin: 'https://acme.com' }).listIndexableEntities,
store: memoryStore(),
// callClaude, db, auth … wire the seams you need for generate()/run()
},
)
const { issues } = await seo.analyze()
const draft = await seo.generate() // human-approved content proposals
@ascent/seo-agent/license—verifyLicense(token, {now, publicKey}), offline.@ascent/seo-agent/config·/runtime— resolve config + the runtime/trust split.- Four
initprofiles: headless · api · frontend · admin.
npm i @ascent/seo-agent↓ Types .zip↓ Examples .zipOne handler. N routes. Server-side secrets.
A single Web-standard handleRequest(Request) → Response router over every backend shell, with unified Authorization: Bearer license auth, CORS, and fail-soft responses. This is the endpoint the browser SDK proxies to — so keys stay on the server.
import { createSeoService, defaultHandlers, toNodeHandler } from '@ascent/seo-agent/service'
const service = createSeoService({ handlers: defaultHandlers, secrets: process.env })
// Web-standard (edge / Deno / Bun):
export default (request) => service.handleRequest(request)
// or adapt to a Node http handler:
export const nodeHandler = toNodeHandler(service)
# call it with a license
curl -X POST https://your-service/analyze \
-H "authorization: Bearer $ASCENT_LICENSE" \
-H "content-type: application/json" \
-d '{"site":{"domain":"acme.com"}}'
Six SEO tools, over MCP.
A hand-rolled, zero-dependency Model Context Protocol server over stdio, exposing analyze · generate · rankings · competitors · content · status. Runs against a remote service (SP1) or a local in-process SDK.
// add to your MCP client config (e.g. Claude Desktop)
{
"mcpServers": {
"ascent-seo": {
"command": "npx",
"args": ["-y", "@ascent/seo-agent-mcp"],
"env": {
"ASCENT_SERVICE_URL": "https://your-service",
"ASCENT_LICENSE": "your-license-token"
}
}
}
}
Prefer to import it? @ascent/seo-agent/mcp exposes runServer, defineTools, and resolveBackend.
A drop-in Claude skill.
The ascent-seo skill lets Claude run SEO tasks for you. It prefers the MCP server when it’s connected and falls back to a zero-dep CLI script otherwise — so it works whether or not MCP is wired up. An honesty reference keeps measured and projected results clearly separated in what Claude reports back.
- Ships as
skill/ascent-seo/—SKILL.md+ honesty reference + fallback CLI. - MCP-preferred; the script path needs only
ASCENT_SERVICE_URL+ASCENT_LICENSE. - Pairs naturally with the MCP server above.
Browser widgets — pure build, thin mount.
Zero-dependency, XSS-escaped browser widgets: a meta injector, a rank badge (measured), a potential gauge (projected), and an honest result card. Each is a pure buildX(data) → html plus a thin mountX(el, data), with a base theme.css.
import { mountRankBadge } from '@ascent/seo-agent/widgets'
import '@ascent/seo-agent/widgets/theme.css'
mountRankBadge(document.querySelector('#rank'), {
keyword: 'best crm',
position: 5, // measured on Google — not a projection
})
A browser ascentClient talks to your SP1 service; only the token is sent, never secrets.
An operator cockpit you control.
Six actionable panels — proposals, keywords, rankings, competitors, autonomy, status — built on a small panel framework. Panels read through the ascentClient and write through an onAction callback you wire, so there’s no hidden write endpoint pretending to exist.
import { mountProposals } from '@ascent/seo-agent/admin'
mountProposals(document.querySelector('#proposals'), {
client, // reads via SP1
onAction: (action) => approve(action) // you own the write path,
})
Two ways to pay for paid ops.
Paid operations (SERP + AI) cost money to run. How they’re billed depends on where the engine runs — on your infrastructure, or on Ascent’s hosted API.
Self-hosted / licensed → your keys, no Ascent credits
Run the engine on your own infrastructure with your own Serper/Anthropic keys. You pay those providers directly — Ascent credits don’t apply and there’s nothing to top up. Your cost is your provider bill plus the annual license. Generate a key from any 🔒 Generate license button.
Hosted API / Service → Ascent credits
Call Ascent’s hosted Service (Authorization: Bearer). Ascent runs the ops on its keys and meters them in Ascent credits — the same wallet as the app. Each dispatched run debits credits (refunded on provider failure); an empty wallet returns 402 insufficient_credits.
// check your balance (Bearer = your session token)
POST /rest/v1/rpc/credit_balance
{ "p_account": "<account_id>" } // → { total, planRemaining, topupBalance, resetsAt }
// top up: buy a credit pack (redirects to the hosted card page)
POST /api/payments/mips/create-payment
{ "kind": "credit_pack", "packId": "pack_5k", "accountId": "<account_id>" }
Bring your own keys (BYOK): connect your Serper/Claude keys in Account settings and hosted ops run on your keys at near-zero credits — the natural fit for agencies and high-volume dispatch.
During an open beta the operator may pause metering — hosted calls then run free (usage is still recorded).
Grab the free components.
The open pieces are yours to download and use now. The licensed engine — SDK core, service/API, MCP server, admin cockpit — is available on request.
🔒 Licensed · SDK core · service/API · MCP · admin
The engine itself is a commercial, licensed product — self-host or white-label. It isn’t a public download — request developer access and we’ll set you up.