CitationBenchTalk to Sales
Playbooks

Refresh stale content automatically when rankings drop

When a high-value page drops in rank, the agent audits it against the current SERP, regenerates weak sections, and queues an approval-gated refresh — same loop for AI citation drops.

When a high-value page drops in rank, CitationBench audits it, drafts an update, and queues it for approval. Same loop works for AI citation drops.

OutcomeDetected drops → graded → refreshed → approved → republished → re-indexed
Time~3 min per refresh draft; runs continuously
Cost~30 credits per refresh + downstream publish (1) + indexing (1)
PrereqsWorkspace with keywords + published content, GSC connected (for indexing), DataForSEO connected (for rank tracking)

What it does

rank_monitor (scheduled) detects drop of 5+ on a FOCUSED keyword
  ↓ on detection, spawns refresh_stale invocation
refresh_stale:
  produce.evaluate (current article vs current SERP)
  ↓ identifies weak sections + missing topics
  produce.blog_post.regenerate (scope: weak sections)

  produce.refine (workspace standard refiner chain)
  ↓ pauses at WAITING_APPROVAL with the draft
↓ on approval:
  produce.publish (auto-fires indexing.gsc.submit + indexnow)

Step 1 — Identify content worth monitoring

Not every page deserves auto-refresh. Filter to:

  • Content linked to PURCHASE or ALTERNATIVE-intent keywords
  • Content that's been published > 90 days
  • Content with priority: HIGH or CRITICAL
curl -X POST .../v1/produce/blog-post -G \
  --data-urlencode "status=PUBLISHED" \
  --data-urlencode "publishedBefore=$(date -u -d '90 days ago' -Iseconds)" \
  --data-urlencode "tag=monitor-rank"

Tag these as monitor-rank so the rank_monitor skill picks them up.

Step 2 — Wire rank monitoring → refresh_stale

curl -X POST .../v1/agent/invoke -d '{
  "skill": "rank_monitor",
  "input": {
    "scope":   { "tag": "monitor-rank" },
    "alertOn": { "drop": 5 },
    "onDrop": {
      "invokeSkill": "refresh_stale",
      "approval":    { "required": true }
    },
    "schedule": "weekly:mon:09:00"
  }
}'

Now every Monday, ranks get checked; any drop of 5+ spawns a refresh draft.

Step 3 — Watch + approve drafts

The refresh_stale invocation pauses at WAITING_APPROVAL with the draft + the eval report (showing exactly why it changed each section).

curl -G .../v1/agent/approvals \
  --data-urlencode "skill=refresh_stale" \
  --data-urlencode "scope=workspace"

Each approval surfaces a preview like:

{
  "approvalId": "appr_***",
  "invocationId": "inv_***",
  "skill": "refresh_stale",
  "step": "publish_refreshed",
  "preview": {
    "blogPostId": "bp_***",
    "currentPublishedUrl": "https://acme.com/blog/engineering-team-capacity-tracking",
    "previousScore": 62,
    "newScore": 81,
    "sectionsRewritten": ["intro", "section_3_forecasting"],
    "diff": {
      "wordsAdded": 840,
      "wordsRemoved": 312
    },
    "evaluationReport": { "...": "..." }
  }
}

Approve in the dashboard, in Slack, or via API:

curl -X POST .../v1/agent/invocations/inv_***/approve

Step 4 — Also wire AI citation drops

The same pattern works for GEO. Wire citation_hunter to refresh_stale:

curl -X POST .../v1/agent/invoke -d '{
  "skill": "citation_hunter",
  "input": {
    "queryIds":    ["aiq_***"],
    "reclamation": "recommend",
    "schedule":    "daily:08:00"
  }
}'

Drops in AI citation rates spawn refresh_stale drafts on the content tied to those queries.

One-shot script

#!/usr/bin/env bash
set -euo pipefail
KEY="${CITATIONBENCH_API_KEY:?}"
WS="${WORKSPACE_ID:?}"
BASE="https://api.citationbench.com/v1"

# 1. Tag the content worth monitoring
curl -sf -G $BASE/produce/blog-post \
  -H "Authorization: Bearer $KEY" -H "X-Workspace-Id: $WS" \
  --data-urlencode "status=PUBLISHED" \
  --data-urlencode "publishedBefore=$(date -u -d '90 days ago' -Iseconds)" \
  | jq -r '.data[].id' \
  | while read BP; do
      curl -sf -X PATCH $BASE/produce/blog-post/$BP \
        -H "Authorization: Bearer $KEY" -H "X-Workspace-Id: $WS" \
        -d '{ "tags": ["monitor-rank"] }'
    done

# 2. Wire rank monitor → refresh_stale
curl -sf -X POST $BASE/agent/invoke \
  -H "Authorization: Bearer $KEY" -H "X-Workspace-Id: $WS" \
  -d '{
    "skill": "rank_monitor",
    "input": {
      "scope":   { "tag": "monitor-rank" },
      "alertOn": { "drop": 5 },
      "onDrop":  { "invokeSkill": "refresh_stale", "approval": { "required": true } },
      "schedule":"weekly:mon:09:00"
    }
  }'

echo "Stale-content refresh active."

Gotchas

  • Approval is essential for refresh. Auto-publishing a rewritten article without human eyes is a recipe for breaking your voice. Keep approval.required: true.
  • Some drops are SERP volatility, not your fault. If a competitor temporarily ranks higher, you might trigger a refresh you didn't need. Set a higher threshold (drop ≥ 8) or require sustained drop over 2 weeks.
  • The agent uses the current SERP as a benchmark. If the SERP is dominated by content types you don't produce (e.g., a video carousel), the refresh might overshoot. Manually review.
  • Indexing lag. Even after re-publishing, Google may take 1–4 weeks to re-evaluate. Don't expect instant rank recovery.

On this page