I Built a WordPress Plugin to Find Content Decay. Then I Taught It to Diagnose Why.

The first version found pages losing traffic. The refined Content Performance Analyzer separates ranking decay from seasonality, tracking failures, indexing problems, zero-click search, and changing demand — then builds the right fix plan.

Dark title card reading 'A Traffic Drop Isn't a Diagnosis.' above a pipeline snippet: drop, diagnose the cause, matched fix.

A few days ago, I wrote about automating the most boring job in SEO: finding old pages that used to perform and are now quietly losing traffic.

The first version of that story was true. It was also already becoming outdated.

Content Performance Analyzer could find a falling page, combine its Google Analytics 4 and Search Console numbers, read the content, and produce an AI-assisted fix plan. That removed a lot of spreadsheet work. But the more real sites I tested, the more obvious the next problem became.

A traffic drop is not a diagnosis.

Sometimes a page has genuinely lost rankings. Sometimes demand for the topic has cooled. Sometimes Google still shows the page but answers the query before anyone clicks. Sometimes the page is fine and the GA4 tag is broken. Sometimes somebody added noindex. Sometimes December is simply behaving like December.

If a tool treats all of those as “refresh the article,” it has automated the spreadsheet while preserving the bad decision.

So I kept building. The current plugin does more than find a red number. It tries to explain why the number turned red, rules out the most expensive false alarms, and matches the recommendation to the evidence. The Google connection is now verified, the background AI workflow is far more resilient, and the plugin finally has a proper home at cpanalyzer.com.

This is the second version of the story.

The Difference Between a Report and a Diagnosis

Most content reports are very good at telling you that something moved.

Clicks are down 31%. Average position slipped by 2.4 places. Engagement fell. Impressions rose but CTR did not. Those are useful observations, but they still leave the expensive question to a person: what actually happened, and what should we do next?

Content Performance Analyzer now classifies a decline into a more useful set of causes:

  • Ranking decay: the page lost search position, and clicks fell with it.
  • Zero-click capture: visibility and rankings held, but an answer box or Google AI Overview started satisfying the query before the click.
  • Demand decay: fewer people are searching for the topic, so rewriting the same page may not recover the missing traffic.
  • Non-search decline: GA4 traffic fell while Google organic search remained healthy, which points toward email, social, referral, direct, or internal traffic instead of SEO.
  • Self-inflicted decay: the page was edited during the decline window, so the previous WordPress revision deserves a look before the team rewrites it again.
  • Technical or indexing loss: impressions collapsed because the page disappeared from search, possibly after a noindex tag or an incorrect canonical.
  • Tracking failure: GA4 dropped toward zero while Search Console continued recording clicks, which is usually a measurement problem rather than a content problem.
  • Seasonal pattern: the decline mirrors the same period last year, so the right action may be to wait rather than “optimize” a page that is behaving normally.

That classification changes the work.

You refresh a page that lost rankings. You investigate distribution when the loss came from another channel. You fix the tag before touching the copy when analytics broke. You repair indexing before asking AI for a better introduction. You do not manufacture busywork for a seasonal dip.

The plugin can make those distinctions because it joins signals that usually live in separate tabs: GA4 traffic and engagement, Search Console clicks, impressions, queries and position, the page’s live content, WordPress revision dates, internal-link relationships, and optional PageSpeed and live SERP data.

The useful part is not another dashboard. It is the connection between the evidence.

Not every useful page is decaying, either. The same scan flags SEO opportunities where impressions are strong but clicks or position are weak, and conversion gaps where a page attracts real traffic without producing enough GA4 key events. GA4 key events work by default, and a site can add its own event names for outcomes such as demo requests or trial signups. Search Console also supplies the primary query for each URL, so the opportunity is tied to what the page is already earning visibility for rather than a keyword invented by the tool.

It Now Tries to Disprove Itself

False positives are especially expensive in content work. A confident but wrong diagnosis can send a writer into a six-hour rewrite that never had a chance of fixing the problem.

The refined decay system now checks the obvious alternative explanations before it raises the alarm.

For suspected demand decay, it compares the current period with the same window one year earlier. If the pattern is seasonal, the page is marked as expected rather than unhealthy.

If Search Console impressions collapse, the plugin checks the live page for noindex and for a canonical pointing somewhere else. If GA4 disappears while Search Console clicks survive, it tells you to inspect tracking. If a page still has traffic but almost no Google search footprint, it stops pretending the decline must be an SEO issue and points you toward the GA4 channel breakdown.

It also keeps six 28-day click periods, so one noisy comparison does not have to carry the whole argument. You can see whether a page is in a sustained slide and how far it has fallen from its peak.

This was one of the largest improvements in the plugin, even though it is less photogenic than an AI button. Good analysis is not only about finding a pattern. It is about trying to prove that pattern wrong before asking someone to act on it.

The Problems Around the Page Matter Too

A page rarely declines in isolation. The problem may sit elsewhere on the site.

The plugin now detects keyword cannibalization by finding queries where two or more of your own URLs divide the clicks. Instead of recommending that both pages become longer, it shows the competing URLs and their positions so you can consolidate, redirect, or clarify their intent.

It also detects orphan pages using editorial links, excluding the menus and widgets that make every page look connected. A strong article with no contextual inbound links is not necessarily a writing problem. It may be an architecture problem.

After a scan, a new-issue alert identifies pages that were healthy in the previous run and are flagged now. That turns the plugin from a quarterly audit into a lightweight monitoring system. Daily automatic rescans are available, but opt-in, because I would rather protect a user’s API quota than pretend every site needs the same schedule.

For optional live-search analysis, a Serper key lets the plugin inspect the current results page. It can confirm answer boxes and AI Overviews, or notice when the results have shifted toward video, forums, products, or another format that no amount of paragraph polishing will solve.

Again, the goal is not to produce more recommendations. It is to avoid the wrong recommendation.

The original plugin started as a content-decay tool. It has grown into something closer to an AI content strategist inside WordPress because discovery itself has changed.

A page can rank in Google and still be difficult for an answer engine to quote. It can also receive traffic from ChatGPT or Perplexity that is invisible in a traditional organic-search report. Treating those as the same problem hides useful opportunities.

Every analyzed page now receives an answer-engine readiness score from 0 to 100. The score is not a mystical prediction of whether an AI model “likes” the page. It is a checklist of things the page can actually improve: question-style headings, direct answers beneath them, useful lists, structured data, clear organization, and freshness signals. Failed checks are named rather than buried inside one opaque number.

Search Console queries create another useful layer. If a page ranks between positions 2 and 20 for a real question but no heading on the page answers it, the plugin marks a question gap. That is simultaneously a classic SEO opportunity, a featured-snippet opportunity, and a clearer passage for an answer engine to cite.

For a suitable gap, the plugin can draft a concise answer grounded in the page’s existing content, append it as an editable Q&A block, and add FAQ schema. It skips the schema when the page already has it, because duplicate automation is still duplication.

The dashboard also reports referral sessions from ChatGPT, Perplexity, Copilot, Gemini, and Claude by landing page. That makes AI visibility measurable instead of theoretical. An optional llms.txt file can publish a machine-readable guide to the site’s analyzed content, with conflict detection if another plugin or file already owns that route.

I am deliberately careful with the language here. None of this guarantees a citation in an AI answer. It makes pages clearer, more answerable, and easier to measure. That is useful without turning it into magic.

AI That Has to Show Its Work

Generic AI advice was never the goal. “Improve your title,” “add more detail,” and “use engaging language” are sentences a tool produces when it does not know enough about the page.

The plugin’s recommendation prompts now carry the actual evidence: current and previous traffic, clicks, impressions, position, engagement, conversion signals, the diagnosed decay type, content issues, question gaps, internal links, and optional competitor findings. The output separates SEO, AEO, generative-engine visibility, engagement, and measurement actions, and it asks for concrete deliverables rather than motivational copy.

Most importantly, the recommendation follows the diagnosis.

A tracking failure leads with checking the tag. An indexing problem leads with removing the technical block. A seasonal page does not get a compulsory rewrite. A topic with falling demand gets a different strategy from a page whose ranking slipped while demand stayed healthy.

You can use OpenAI, Groq, or Google Gemini with your own API key, select the exact model when cost control matters, or leave the choice automatic. Each generated action records the model that created it. Responses use structured output where the provider supports it, which has made the recommendations much more reliable to parse and display.

The AI can also do a few carefully bounded jobs rather than merely describe them:

  • List the exact images missing alt text, use vision to draft the text, and apply it without overwriting alt text that already exists.
  • Find safe internal-link opportunities and insert them only when the exact anchor text exists outside an existing link or HTML tag.
  • Build a content-refresh brief from the page’s diagnosis and evidence.
  • Draft the answer blocks described above.
  • Export the complete analysis to CSV, including the recommendation groups, model, decay evidence, AEO score, AI referral sessions, and inbound-link count.

Automation earns trust by having boundaries. I would rather have a smaller button that behaves predictably than a larger one that quietly rewrites the wrong thing.

Free-Tier AI Is Messy. The Queue Had to Learn That.

The first AI workflow worked beautifully on the happy path. Real API limits introduced themselves immediately afterward.

Free models rate-limit. Long pages can exceed a context window. One failure can leave a batch mostly complete but a few flagged pages blank. Worse, a dashboard can say “processing” forever even though nothing is running.

That entire path has now been rebuilt.

When a content-heavy page creates an oversized request, the plugin retries once with a compressed payload. It trims body content and removes competitor excerpts while preserving the performance metrics and decay diagnosis that ground the recommendation.

If a normal analysis run still leaves flagged pages without suggestions, an automatic drain queue picks them up one page at a time. It spaces attempts by a couple of minutes, backs off exponentially when a provider rate-limits, caps daily attempts, permanently skips a page that cannot fit even after compression, and stops on configuration errors that require a human. The dashboard shows a calm progress notice and the next attempt time instead of an immortal spinner.

This sounds like plumbing because it is plumbing. It is also the difference between a demo and a tool somebody can leave running on 200 URLs.

The larger analysis pipeline works in dynamic background batches, prioritizes flagged pages, saves partial progress, and continues without requiring the browser tab to stay open. Live status updates explain what is happening. A one-click importer loads published posts and pages with search and selection controls, and a content-only scan works before any Google or AI setup at all.

Reliable boring machinery is still a feature.

The Google Button Finally Feels Like a Google Button

One-click Google connection existed in the earlier build, but there was an important rough edge: while the OAuth app was still going through Google’s verification process, new users could encounter the “Google hasn’t verified this app” warning.

The OAuth app has now passed verification. That warning is gone.

The setup is the experience I wanted from the beginning: click Connect with Google, choose an account, approve read-only Analytics and Search Console access, then select the GA4 property and Search Console site from dropdowns. No Google Cloud project. No client ID and secret copied into WordPress. No property identifiers hunted out of three different settings screens.

The permissions are intentionally narrow. The plugin can read Analytics traffic and engagement, Search Console performance and queries, and the email address needed to show which account is connected. It cannot edit a Google property and never asks for Gmail, Drive, Contacts, or anything unrelated.

The hosted connection service at auth.cpanalyzer.com runs on Cloudflare Workers. It completes the OAuth handshake and passes the tokens to the user’s WordPress site through a one-time handoff that expires after five minutes. The service keeps no user database, analytics database, or copy of the tokens. The durable copy lives on the WordPress site that requested it. Disconnecting revokes the Google connection and removes the local credentials.

Advanced users can still bring their own Google OAuth client. Convenience should not remove control.

The Plugin Has a Proper Home Now

The other visible change is outside WordPress.

cpanalyzer.com is now a real product site rather than a domain pointing toward a plugin listing. It explains the workflow, the Google permissions, the privacy model, and the difference between collecting data and storing it. The visual language comes directly from the plugin icon: deep purple, cyan data signals, soft layers, and the small yellow spark.

The homepage includes an interactive product scene and motion charts, but the design is not there to disguise a thin product. Its job is to make a fairly technical tool understandable in a minute: connect the signals, find the pages at risk, and leave with a prioritized fix plan.

The privacy policy and terms now live alongside the product, including a plain-language explanation of exactly what the OAuth service does. That work was part of earning Google verification, but it also made the product better. If a tool asks for analytics access, “trust me” is not documentation.

What the Current Workflow Looks Like

The complete loop is now straightforward:

  1. Install Content Performance Analyzer from WordPress.org.
  2. Import published posts and pages with the built-in picker.
  3. Run a content-only scan immediately, with no credentials, to find thin pages, heading problems, missing alt text, schema issues, canonicals, and noindex directives.
  4. Connect Google to add GA4 and Search Console evidence, then choose the properties from dropdowns.
  5. Optionally enable PageSpeed Insights, which works through the hosted service without requiring an API key, or use your own key.
  6. Optionally add an OpenAI, Groq, or Gemini key for grounded fix plans and one-click AI actions.
  7. Review the diagnosis, not just the decline: ranking, zero-click, demand, non-search, technical, tracking, seasonality, or a recent edit.
  8. Fix the highest-value pages, export the report if needed, and let later scans surface what changed.

Every product feature is free. There is no premium tier, URL cap, or account to create with me. Optional AI and search services use credentials you control, while the stored results remain on your site and appear inside the WordPress dashboard.

What I Actually Built

I thought I was building a faster content audit.

What I ended up building is a small decision system: one that gathers evidence from tools that normally disagree in separate browser tabs, tries to rule out the wrong explanation, and then turns the surviving explanation into work a person can review.

That is a much harder problem than drawing a downward arrow. It is also much closer to the job.

The plugin is not finished in the grand, ceremonial sense software is never finished. But it is now refined enough that I trust the shape of it: read-only data, explicit permissions, diagnoses that admit uncertainty, AI with bounded jobs, background processing that recovers from real API behavior, and no premium lock waiting behind the result.

You can get it free on WordPress.org and see the full product at cpanalyzer.com.

Install it on a site with a messy content library. Those are more useful than clean demos. If it identifies the wrong cause, misses an obvious opportunity, or gives you a recommendation you would never act on, tell me. That is the feedback that turned the first version into this one.