SEO Agent
Always-on SEO optimization worker with autonomous sub-agents, auto-blogger, and campaign lifecycle
Overview
The SEO Agent is an always-on optimization worker for a connected website. It reads SEO reporting data, site content, keyword opportunities, prior action history, and operator-submitted ideas — then chooses the next executable SEO action within budget and safety limits.
The agent can:
- Audit technical and content health
- Research keywords, SERPs, and competitors
- Build topical maps and content clusters
- Draft SEO blog posts through the auto-blogger
- Optimize money pages
- Apply or recommend technical SEO fixes
- Monitor reports for ranking, traffic, and striking-distance changes
- Record every action into campaign and action history for review
Think of the SEO agent as a loop, not a one-shot generator. It continuously watches reporting data, queues campaigns, analyzes situations, runs actions, and measures outcomes.
A Campaign Is The Execution Of A Plan
Older campaigns picked one next action at a time with no bigger picture — analyze, do one thing, repeat. A campaign now builds a short ordered plan first (for example: refresh the audit, then run research, then write two blog posts) and works through it item by item, instead of deciding fresh after every single action. When the plan runs out, the agent goes back to research and builds a new one.
This makes campaigns more predictable to read in the campaign history — you can see the intended sequence, not just a string of individual decisions — and it avoids the old failure mode where an agent would commit to writing a post, discover mid-run that it had nothing good to write about, and burn most of the campaign recovering from that.
Runtime Loop
The runtime processes work asynchronously through a worker heartbeat:
- Queue — A campaign is queued by an admin trigger, manual request, or SEO reporting alert
- Lease & start — The worker heartbeat claims the campaign and sets runtime to
running - Situation analysis — Loads current domain state, reporting trends, previous actions, site context, and memory
- Action context — Builds the executable action catalog, verifying each action has real inputs (due keyword, target URL, audit findings)
- Build the plan — On the first pass, lays out the ordered list of work items for this campaign
- Strategy — Walks the plan one item at a time, or returns
nonewhen no safe action is ready - Sub-agent dispatch — The selected action runs with resolved inputs
- Website handoff — If the action changes site content, it hands off to website execution: a WordPress draft job, a GitHub pull request, or — for GHL-hosted sites — a native GHL blog post
- Evaluation — Records results, updates keyword timestamps, appends action history, checks budget/duration/cancellation
- Loop or complete — The graph moves to the next plan item, builds a fresh plan once the current one is exhausted, or completes the campaign with a report
- Outcome measurement — Later reporting data is compared against baseline so the agent learns
- Alert scan — Continues watching for position drops, traffic cliffs, and striking-distance surges
Runtime States
| State | Meaning |
|---|---|
idle | No active campaign |
queued | Campaign accepted, waiting for worker |
running | Worker owns the lease, actively executing |
cancelling | Cancellation requested, stops at next safe boundary |
Only one active campaign per SEO agent at a time.
New-Agent Setup Now Actually Runs On Its Own
When a new SEO agent is created, it used to only run the initial audit automatically — research and the topical map needed a manual trigger, even though the setup screen told operators those steps would "start automatically after activation." That was wrong, and it's fixed: activating a new agent now runs audit, research, and topical map as one setup campaign, in that order, without anyone having to trigger the later steps by hand. Progress shows on the same setup screen as before. If a client asks why their new agent is "still setting up," the setup screen's progress line is the accurate answer now — check it before assuming something is stuck.
Sub-Agents
| Action | Worker | Purpose |
|---|---|---|
audit | Auditor | Refresh technical/content health and identify findings |
research | Researcher | Gather keyword, SERP, and competitor context |
topography | Topography | Build or refine topical clusters and site structure |
blog-write | Blog Writer | Produce or update informational content tied to executable keyword context |
money-page | Money Page | Improve high-intent pages tied to executable URL context |
technical-seo | Technical SEO | Apply or recommend technical fixes (requires completed audit with actionable findings) |
none | Strategy only | Explicitly take no action when no safe high-value action is executable |
Aliases like auto-blogger, blogger, auditor, and topographer normalize to the supported runtime actions.
Strategy never chooses blog-write or money-page without executable inputs. If inputs are missing, the runtime returns none instead of attempting a partial action.
Action Outputs
| Action | Intended Output |
|---|---|
audit | Audit record with score, findings, and summary of site health |
research | Keyword, SERP, and competitor research payload used for planning |
topography | Updated topical map or cluster structure |
blog-write | Content generation or update result tied to a specific keyword opportunity |
money-page | Page optimization result tied to a specific URL and commercial intent |
technical-seo | Technical remediation result or structured set of fixes |
Auto-Blogger
The auto-blogger is the blog-write sub-agent. It does not blindly invent posts — it uses executable keyword context from DataForSEO, Google Search Console, tracked keywords, and operator-submitted ideas.
Auto-Blogger Loop
- Select a due keyword candidate (weighted by priority, ranking opportunity, intent, freshness)
- Skip keywords recently drafted to avoid repeated posts
- Build a content brief from cluster context, internal link opportunities, and SERP/research data
- Generate the blog draft, title, slug, meta title, meta description, FAQ/article schema, and review notes
- Publish through the site's connected platform — a WordPress
WebsiteExecutionJob(operation: "write_entity",postType: "post"), a GitHub pull request, or a direct GHL blog post - Attach a client asset as the featured image when
featuredAssetReforassetRefsare provided - Save keyword timestamps (
lastSelectedAt,lastDraftedAt) - The reporting loop measures rankings and traffic later before strategy repeats or changes direction
The SEO agent's own Publish Mode setting (draft or publish) decides whether a finished post goes live right away or waits for operator review — draft is the default for both WordPress and GHL sites. GitHub-backed sites always land as a pull request, never an auto-merge.
GHL blog posts need a little setup the first time: a GHL blog site, a blog author, and a featured image are all required. If more than one GHL blog is connected, set website.config.ghlBlogId so the agent doesn't guess which one to post to. If any of these are missing, the agent skips the post and records why instead of failing silently.
Content Plan (Proactive Posting Quota)
Each SEO agent has a Content Plan on its Config tab. Turning it on lets the agent write new blog posts on its own schedule, instead of waiting for an operator to ask for each one. The Content Plan sets how many posts to write per month and how many can go out in a single run.
Turning the per-agent switch on is not enough by itself. There is also one global switch that covers the whole deployment: the SEO_CONTENT_ENGINE environment variable. It must be set to on, or the content engine will not draft any posts — even if every agent's Content Plan says "enabled."
If an agent's Content Plan is on but no posts are showing up, check whether SEO_CONTENT_ENGINE=on is set for the deployment. This is a server-wide setting, not a per-agent one — no individual agent can turn it on by itself. Maintenance work and manually triggered campaigns are not affected by this switch; it only blocks the automatic, on-schedule blog quota.
If the per-agent switch is on but the deployment switch is off, the Config tab now shows an amber warning naming the exact environment variable to check, so this mismatch is visible without digging through logs. The Config tab also shows a plain-language cadence line, like "about one post every 7 days," so operators can check the numbers match the posting schedule they had in mind.
Keyword Ideas & Scheduling
Operators can influence the agent without editing database records directly.
Submit Keyword Ideas
POST /admin/seo/agents/:id/keyword-ideas
Fields: keyword, proposedAction, intent, priority, scheduledFor, url, clusterSlug, and notes.
- Future-dated ideas are held until due
- Higher priority due ideas receive a stronger score in action selection
- Submitted ideas are stored as manual
SeoKeywordrecords with operator tags and scheduling metadata
Inspect Action Context
GET /admin/seo/agents/:id/action-context
See what the runtime currently considers executable or blocked, including candidates for blog writing, money-page work, and technical SEO.
The admin SEO detail page exposes this in the Keywords tab.
Keyword Hit List & Maintenance
The Hit List (SEO ▸ Keywords ▸ Hit List) is the single committed master list for a client's keyword work — every keyword the agent or an operator has research has been through the same pipeline lands here, alongside the Saved Keywords research library it's promoted from.
Before a keyword can claim a hit-list candidate slot, an LLM relevance check screens out GSC queries that share a word with the site but have no commercial tie to the business (e.g. a school or an unrelated app name that happens to match a query). Screened-out keywords stay in the agent's working set — they just don't clutter the curated hit list.
- Stages:
candidate → proposed → approved → scheduled → drafting → published → live, with content type (blog post / service page / local page), schedule, published URL, and per-channel distribution chips. - One master list. Agent research, operator-submitted keyword ideas, and the Hit List page all write into the same pipeline — a submitted idea shows up on the Hit List immediately as a
candidate, not just once the agent acts on it. - Promote to hit list — a row action on the Saved Keywords tab (or from the Hit List tab directly) that moves a keyword into the build pipeline and queues it into the agent's working set.
- Remove from hit list — a row action on the Hit List tab that resets a keyword's stage back to
noneand pulls it out of the agent's working set, without deleting the underlying research row. Use the Saved Keywords delete action instead to archive a keyword's research history entirely. - Manual pipeline correction — if a build genuinely published but the Hit List never picked it up, open the keyword in the Saved Keywords editor and use the Stage select and Published URL field to correct it by hand instead of waiting on support. Marking a keyword newly published/live this way stamps its publish date automatically, and the fix shows up on both the Saved Keywords and Hit List tabs right away.
- Distribute fans a published keyword across channels (blog, GMB, Facebook/Instagram/LinkedIn/Pinterest, newsletter) using the client's connected accounts; unconnected channels show as skipped, not failed.
- Autopilot (per agent, off by default) auto-promotes the strongest fresh candidates into the build pipeline within configured volume/difficulty/pace thresholds, instead of waiting for operator review.
Publishing or promoting a keyword to published/live auto-enrolls it in rank tracking by default. An hourly scheduled check keeps position history up to date automatically after that, so the maintenance watchers below always have fresh data to work from.
Maintenance Watchers
Once a keyword is published/live, the agent keeps watching it instead of moving on:
| Watcher | What It Catches |
|---|---|
| Hit-list decay | Published keywords whose ranking position dropped week-over-week, or that have sat 30+ days with no clicks and no progress |
| Index coverage | Published pages Google can't or won't index — Soft 404s, robots.txt blocks, crawled-but-not-indexed |
Both watchers feed the same alert scan that already watches for position drops and traffic cliffs, so a maintenance campaign can be queued automatically when a published page needs attention — and that campaign is built to fix or refresh the specific flagged page rather than propose generic new content. Once a decay or index-coverage alert queues a campaign, it won't queue another one for the same condition for 7 days, since these are slow-moving issues that don't need a fresh campaign every scan cycle.
The index-coverage watcher's result also shows up directly on the Hit List row as a badge next to the published link (Indexed / Not indexed yet / the specific issue, e.g. Soft 404), so you don't have to wait for an alert to see it.
Triggering a rank check manually on a config tracking more than 15 keywords now starts it in the background instead of blocking the request — the page shows it as started and keeps polling until results are in, rather than risking a timeout on a long serial SERP run.
The Delete domain action on a tracked domain's rank-tracking page now actually removes it, after a confirm prompt. It frees that client/domain/location/language/device slot for re-adding, and keeps the keyword and ranking history that was already collected.
Budget & Safety
Launch safety boundaries protect against unbounded execution:
- API responses redact WordPress, Rank Math, and DataForSEO secrets
- Generic agent updates cannot overwrite runtime state, campaign history, budget config, alert config, or initial audit state
- Budget and alert values are validated and bounded before they can affect a campaign
- Unknown sub-agent names fail clearly instead of pretending an action ran
- Full campaigns stop at cancellation-safe boundaries
- Blog posts default to draft status on both WordPress and GHL sites unless the agent's Publish Mode is set to
publish - WordPress edits go through bounded website execution jobs with target constraints and preview metadata
- Elementor smart edits remain widget-scoped and backup-aware
The SEO agent's detail header shows a running-cost stat (spend against budget) alongside the same in-place rename affordance available on other agents — see Creating & Configuring Agents.
Budget Controls
PUT /admin/seo/agents/:id/budget
Change action, token, cost, duration, and cooldown caps.
Alert Controls
PUT /admin/seo/agents/:id/alerts
Change alert thresholds only. This does not function as a scheduling endpoint.
Campaign Lifecycle
| Step | Description |
|---|---|
| Queue | API accepts the request, stores runtime state as queued |
| Lease & start | Worker claims ownership, sets running, records heartbeat data |
| Decide | Situation and strategy nodes choose the highest-value executable action |
| Dispatch | Runtime invokes the matching worker with resolved inputs |
| Evaluate | Results recorded in action history and used for future strategy context |
| Continue or stop | Worker loops for another action or completes the campaign |
| Cancel | Queued campaigns cancel immediately; running campaigns transition to cancelling and stop at next safe boundary |
Operator API Reference
| Endpoint | Purpose |
|---|---|
POST /admin/seo/agents/:id/trigger | Run a specific sub-agent or queue a full campaign |
POST /admin/seo/agents/:id/campaign | Queue a manual full campaign |
POST /admin/seo/agents/:id/campaign/cancel | Request cancellation |
GET /admin/seo/agents/:id/runtime | Inspect current runtime state, current work, recent actions, audit trail |
GET /admin/seo/agents/:id/campaigns | Inspect campaign history |
GET /admin/seo/agents/:id/actions | Inspect action history with pagination |
WordPress & MCP Integration
- WordPress REST writes and reads through the SEO WordPress connector
- Rank Math and Yoast-compatible meta fields are sent with blog draft jobs
- Rank Math redirects are supported when the site exposes the namespace
- Elementor smart edits available through the WordPress connector with constrained edit behavior
- Website execution previews and runs SEO-originated WordPress draft jobs
- Client asset library references resolve through website asset consumers and upload into WordPress media
- MCP WordPress and image-generation features can create or reference assets the SEO flow later uses for posts
Agent Model Provider
The SEO agent defaults to Gemini but can be switched per agency to OpenAI or Claude (Anthropic) at Admin → Config → LLMS. GLM (z.ai) is not offered for this role — a full campaign fires many calls in a time-boxed run, and GLM's reasoning latency risks a timeout. Grounded research calls (Google Search retrieval) stay pinned to Gemini regardless of the selected provider, since grounding is Gemini-native. Leave it on the default unless you have a specific reason to change it.
