Find and refresh the Ghost posts quietly losing traffic

See every published post ranked by how much search traffic it has lost, then let an agent draft a refreshed version you approve before publishing.

App
GhostGoogle Search ConsoleGoogle AnalyticsMarketingResearch & MonitoringContent Generation
PromptCreate

Build me a content decay desk for my Ghost blog. Most of my traffic comes from posts I wrote a year ago and I have no idea which of them are quietly dying, so I want one screen: a ranked table of my published posts, worst decay first, that tells me what each post used to earn from search versus what it earns now.

Discover the account identifiers instead of asking me to paste them. Use Google Search Console List Sites and use the returned siteUrl string verbatim, because an inexact property string silently returns empty data rather than an error. Use Google Analytics List Account Summaries to find the numeric GA4 property id. If either credential can reach more than one property, let me pick from a dropdown and remember the choice.

Get the post inventory from Ghost with Browse Posts (Admin API), filtered to published posts, capturing slug, title, url, published_at, updated_at, tags and author for each one. Ghost 6.0 removed support for limit=all and caps results at 100 items per page, so request 100 per page and keep paging by reading meta.pagination.next and passing it as the next page until it comes back null. Do not assume one request covers the whole blog.

Get the search data from Google Search Console with Search Analytics Query, called twice with the page dimension: a current window of the last 90 days and a prior window covering the 90 days immediately before it. End the current window three days before today rather than at today, because Search Console data lags two to three days and the freshest days come back artificially low. For each page, compare the two windows to produce clicks now versus clicks before, impressions now versus impressions before, the absolute and percentage change in each, and the drift in average position, where a rising position number means the post has slipped down the results.

Get pageviews and engagement per page path from Google Analytics with Run Report (GA4), using pagePath as the dimension and screenPageViews plus engagement metrics such as userEngagementDuration and engagementRate, over the same current window. This is the supporting signal that separates a post that lost its ranking from a post that people still find but no longer read.

Join the three sources by matching the Ghost slug to the page URL that Search Console and Google Analytics report. Normalise both sides before comparing: strip the protocol and domain, drop query strings and fragments, and treat trailing slashes as equivalent. Show me a small count of rows that failed to match so I can see the coverage rather than silently losing posts.

Bake in three business rules. Exclude any post published within the last 90 days, since a new post has not stabilised and would clutter the top of the list with normal early movement. Exclude posts below a minimum impression floor in the prior window, defaulting to around 100 impressions and adjustable in the UI, so statistical noise does not outrank real problems. Rank by absolute clicks lost, descending, not by percentage, so a post that fell from 4,000 clicks to 2,000 sits above a post that fell from 20 clicks to 2.

The main table shows one row per post with title linking to the live post, clicks now versus prior with the delta, impressions now versus prior with the delta, average position and its drift, pageviews and engagement, days since the post was last updated based on updated_at, publish date, and tags. Make the decay severity visually obvious at a glance and let me sort by any column and filter by tag, author and date range.

Each row expands to show the query-level detail for that post. Call Search Analytics Query again scoped to that single page with the query dimension, for both the current and prior windows, then split the results into terms the post is holding, meaning it appears in both windows, and terms it has lost, meaning it had meaningful impressions in the prior window and has fallen away or dropped out entirely. Show clicks, impressions and average position for each term in both windows. Note in the UI that Search Console only returns rows with at least one impression, so a query disappearing means it fell below that floor rather than proving the post was deindexed.

Every row gets a Refresh this post button that starts a background agent for that post. The agent reads the full current post with Ghost Read Post (Admin API), pulls the queries that post is losing with Search Analytics Query, then writes an updated version of the article that genuinely addresses those lost queries: updating stale facts, dates and examples, strengthening or adding the sections that map to the lost terms, and tightening the introduction, while keeping my voice and the existing structure where it still works. It saves the result with Ghost Create Post (Admin API) as a draft, using ?source=html when sending HTML, carrying over the original tags, and titling it so I can tell it apart from the original.

The agent must always create a new draft and must never overwrite, edit or publish the live post. Nothing goes live from this app. Alongside the draft it writes a plain English changelog explaining what it changed and why, tied back to the specific queries the post was losing, in language I could forward to a colleague with no API or SEO jargon.

That output lands back in the app next to the original so I can compare before publishing anything: the original post and the new draft side by side, the changelog above them, and a link out to the draft in Ghost admin. Show the agent run state on the row as queued, running, done or failed with the error reason, and persist both the run state and the finished result so I can close the app, come back later, and still see the drafts and changelogs from earlier runs.

What does this prompt do?

  • Ranks every published post on your Ghost blog by how much search traffic it has actually lost, worst first, so the quietly dying pages stop hiding behind your overall traffic number
  • Shows clicks, impressions and average search position for the last 90 days beside the 90 days before that, plus how long it has been since you last touched the post
  • Expands any row to reveal the exact search terms the post still ranks for and the ones it has slipped out of, so you know what to write toward
  • Gives every post a Refresh button that sends an assistant to read the post, study the terms it is losing, and write a refreshed version as a new draft with a plain English list of what it changed and why

What do I need to use this?

  • A Ghost blog you can log into as an admin
  • A Google Search Console account where your blog is already verified
  • A Google Analytics account collecting traffic for the same blog
  • A blog with at least a few months of history, since the decay comparison needs a before and after period to measure

How can I customize it?

  • Change the comparison window from 90 days to 28 or 180 days depending on how fast your niche moves
  • Raise or lower the minimum impressions a post needs before it can appear, to keep low-traffic noise off the list
  • Filter the desk down to a single tag or author so each writer only sees the posts they own
  • Adjust how much editorial freedom the refresh assistant has, from light factual touch-ups to a full rewrite of the weakest sections

FAQs

What is content decay?
Content decay is the slow slide of an older post down the search results over months, rather than a sudden drop from a penalty. The tell-tale signs are impressions and clicks drifting down while your average position creeps up, which is exactly what this desk puts side by side for you.
Will this overwrite my live blog posts?
No. The refresh assistant always creates a brand new draft in Ghost and never edits or replaces the published post. You compare the draft against the original inside the app and nothing goes live until you publish it yourself in Ghost.
Why are my newest posts missing from the list?
Posts published in the last 90 days are left out on purpose, because a new post is still climbing and has not settled into a stable ranking yet. Including them would fill the top of your list with normal early fluctuation instead of real decay.
Do I need both Google Analytics and Google Search Console?
Search Console is the essential one, since clicks, impressions and search position are what decay is measured in. Google Analytics adds pageviews and engagement for each page, which helps you tell a post that lost its ranking from one that still gets found but no longer holds attention.
How up to date is the search data?
Google Search Console data typically runs two to three days behind, so the most recent day or two will look artificially low. The desk accounts for this by ending its comparison window a few days back rather than at today.
Why is a post ranked above another that lost a bigger percentage?
The list is ordered by the number of clicks actually lost, not the percentage. A post that fell from 4,000 clicks to 2,000 is a far bigger problem than one that fell from 20 clicks to 2, even though the second looks worse as a percentage.

Related templates

Ghost editorial calendar: drag your month into shape

See every draft, scheduled and published Ghost post on a month calendar, drag posts to new dates, and park ideas until you are ready to write.

Ghost
App
Build every client's monthly marketing report in one click

See every client's traffic, ad spend and search numbers on one screen, then let an agent write and design this month's report for you to approve.

Gamma
Google Analytics
Google Ads
+2
App
Sell and invoice Ghost newsletter sponsor slots in one board

Replace the sponsorship spreadsheet with a live board of upcoming issues, sold and open slots, real subscriber counts, and paid or unpaid status from Stripe.

Ghost
Stripe
App
Gravity Forms conversion dashboard with dead form alerts

See submissions, page views, and a real conversion rate for every form on your WordPress site, with dead and declining forms flagged for you.

Gravity Forms
Google Analytics
Slack Bot
App
Merchandising board for products people view but never buy

Rank your catalog by view to cart and cart to purchase rate, so the products getting real traffic and losing the sale sit at the top of the screen.

Google Analytics
Shopify
Google Sheets
App
Multi-site GA4 dashboard with one-click client reports

See every Google Analytics property your login can reach in one table, catch broken tracking instantly, and let an agent write each client's monthly report.

Google Analytics
Google Docs
Google Sheets
App

Stop losing traffic to posts you forgot you wrote.

Put every declining post in one ranked list and refresh the ones that matter, starting with the biggest losses.