The Content Pruning Score That Cut 267 Posts to 103
The exact five-input formula and thresholds I used to cut 267 published posts to 103, plus the merge-direction mistake that nearly destroyed 18,120 words.
Table of contents
Score every page on five inputs — word count, presence of a table or code or original data, Search Console impressions, average position, and fit with the positioning you have actually committed to — weight them to 100, then keep at 60 and above, merge from 35 to 59, and delete below 35. One hard gate overrides the score: if the page does not fit your positioning, it goes, no matter how well it scores. I ran this over 279 classified posts in September 2026 and cut the published count from 267 to 103, a 61% cut. The wave-1 file executed 181 unpublish statements to get there.
The score is the easy half. The half that nearly cost me 18,120 words is below.
Why I needed a formula at all
I had 4,553 impressions and 22 clicks over 85 days. A 0.48% CTR across roughly 390 indexed URLs. The full autopsy is in 389 pages, 22 clicks, but the number that forced the formula was this one: 111 of 182 ranking pages earned five or fewer impressions in the quarter.
You cannot fix 111 pages by reading them. You read six, decide they are "fine, needs a refresh", and the sunk cost wins. A formula is a way of pre-committing to a decision before you re-read the thing you wrote.
The classification told me what I was actually looking at. About 150 of the 279 seeded posts averaged 380 words with no table, no code, no internal link, and no image. The whole seed corpus carried around 1,121 H2 headings against 39 H3s — every post was a flat list of section titles with three sentences under each.
Meanwhile the build-log posts and the ones with worked arithmetic in them ranked between positions 2.8 and 15.5. The generic "[industry] content marketing" posts ranked 46 to 81. Same author, same domain, same quarter. The corpus was telling me which half to kill.
The scoring model
Five inputs, normalised to 0-1, weighted to 100.
| Input | Weight | Normalisation | Why this weight |
|---|---|---|---|
| Evidence (table, code, chart, or original data) | 25 | binary | The single strongest split in my own ranking data |
| Demand (90-day impressions) | 20 | min(impr / 50, 1) | Caps fast: 50 impressions proves Google will show it |
| Proximity (average position) | 20 | (21 - pos) / 20, else 0 | Position 40 and position 80 are the same outcome: nothing |
| Fit (committed positioning) | 20 | 0 / 0.5 / 1 | Also a hard gate at 0 |
| Depth (word count) | 15 | min(words / 1200, 1) | Lowest weight on purpose — length is a symptom, not a cause |
Thresholds: 60+ keep and expand. 35-59 merge. Under 35 delete.
Why depth gets the smallest weight
Word count is the input everyone reaches for first and it deserves the least trust. A 380-word post is almost always thin, but a 1,900-word post is not automatically good. Most of my worst seed posts could have been 1,900 words with more of the same padding. Length correlates with quality only because effort correlates with both. Evidence is the better proxy for effort, which is why it carries 25.
Why position is capped at 20
Anything ranking below position 20 is functionally unranked. Treating position 45 as "better than 80" invites you to keep pages on the theory that they are climbing. My US impressions sat at average position 38.8 across 970 impressions and produced zero clicks. That is the empirical case for the cliff.
Why fit is both a weight and a gate
This is the one that does real work. A page can be long, well-evidenced, and ranking, and still be wrong for you. If I am selling content systems and agent architecture, a post about wedding photography pricing that ranks position 12 is a page I have to maintain, that dilutes the entity Google builds for me, and that will never produce a lead. Gate it to zero and it goes regardless of score.
Here is the model as runnable TypeScript, with the self-check I actually ran:
type Page = {
slug: string;
words: number;
hasEvidence: boolean; // table, code block, chart, or original data
impressions: number; // last 90 days, Search Console
position: number; // average position; use 100 if it does not rank
fit: 0 | 0.5 | 1; // fit with the positioning you have committed to
};
type Verdict = 'keep' | 'merge' | 'delete';
const clamp01 = (n: number) => Math.max(0, Math.min(1, n));
export function score(p: Page): number {
const depth = clamp01(p.words / 1200);
const evidence = p.hasEvidence ? 1 : 0;
const demand = clamp01(p.impressions / 50);
const proximity = p.position <= 20 ? clamp01((21 - p.position) / 20) : 0;
return Math.round(
15 * depth + 25 * evidence + 20 * demand + 20 * proximity + 20 * p.fit
);
}
export function verdict(p: Page): Verdict {
if (p.fit === 0) return 'delete'; // hard gate: off-positioning, any score
const s = score(p);
if (s >= 60) return 'keep';
if (s >= 35) return 'merge';
return 'delete';
}
// --- self-check: three shapes from my own corpus ---
import { strict as assert } from 'node:assert';
const buildLog: Page = { slug: 'build-log', words: 1600, hasEvidence: true, impressions: 40, position: 5, fit: 1 };
const seedPost: Page = { slug: 'seed-post', words: 380, hasEvidence: false, impressions: 2, position: 60, fit: 0 };
const midPost: Page = { slug: 'mid-post', words: 900, hasEvidence: false, impressions: 30, position: 14, fit: 1 };
assert.equal(score(buildLog), 92); assert.equal(verdict(buildLog), 'keep');
assert.equal(score(seedPost), 6); assert.equal(verdict(seedPost), 'delete');
assert.equal(score(midPost), 50); assert.equal(verdict(midPost), 'merge');
// the gate matters: a long, well-evidenced, ranking post still dies if fit is 0
assert.equal(verdict({ ...buildLog, fit: 0 }), 'delete');
console.log('ok');
Save it and run npx tsx score.ts. It prints ok.
The assertions exist to pin those three shapes while you fiddle with weights. Every time you are tempted to move a weight to save a specific post, the self-check tells you what else you just changed.
The part pruning advice leaves out: merge direction
Everything above produces a pile of "merge" verdicts. That pile is where the damage happens.
Of 48 merges my process proposed, 21 were pointed the wrong way. The pattern: a 1,684-word post gets folded into a 261-word stub, and the stub's URL is the one that survives because the stub happened to have a few more impressions. The redirect is technically correct. The content is gone. That is a deletion wearing a redirect, and it accounted for 18,120 words before I caught and reversed it.
It happens because the score ranks pages, and a merge needs two separate decisions that people collapse into one:
- —Which URL survives. A search-signal question: impressions, position, backlinks, age.
- —Which body survives. An editorial question: the union of both, edited.
Let the URL decision drag the body decision along behind it and you throw away the better writing about half the time. Mine was 44%.
The decision table
| Longer body | Better URL signals | Surviving URL | What you must do first |
|---|---|---|---|
| Same page | Same page | That page | Nothing. Redirect the other one |
| One page | The other page | The one with the signals | Rebuild the surviving body out of the longer one, then redirect |
| Either | Neither ranks | Either | Pick the better slug, redirect the other |
| Both thin | Either | Neither | Delete both; do not merge two stubs into one stub |
Row 2 is the row that gets skipped, and it is exactly where my 21 failures sat. Row 4 is the one people argue about: two 300-word posts merged produce a 600-word post that is still thin, plus a redirect to maintain forever. Delete them.
Sequencing: rebuild the target before you redirect into it
The order is not cosmetic. A 301 pointing at a page that does not substantively replace the original tends to get treated as a soft 404, which means the redirected URL is dropped from the index rather than consolidated. Glenn Gabe documented this across several 2016 migrations in Proof that 301 redirects to less-relevant pages are seen as soft 404s, citing John Mueller's statement that redirects to the homepage or to non-relevant pages can be treated as soft 404s.
So: publish the rebuilt target, let it get crawled, then redirect. Reversed, you spend the redirect's equity on a stub.
Whether those rebuild hours are worth spending at all is a programme-level question. The content ROI calculator I built takes your cost per published piece, the share of pieces that ever earn traffic, monthly sessions per ranking piece, months to maturity, and your session-to-lead and lead-to-customer rates, and returns the month the programme breaks even. If the whole programme does not pay back at your current cost per piece, rebuilding merge targets one at a time is not the intervention you need.
What the published case studies actually report
Three I could verify, with their real numbers:
- —QuickBooks, via Animalz: deleted about 2,000 blog posts, more than 40% of their Resource Center. Traffic up 20% within a few weeks, 44% by peak season, with a reported 72% increase in signups.
- —Home Science Tools, via Inflow: pruned roughly 200 pages, about 10% of the blog, in August 2018. By November: 104% increase in organic sessions, 102% increase in transactions, 64% increase in strategic content revenue. Note the initial dip in keyword footprint before the climb.
- —CNET, covered by Search Engine Land: deleted thousands of articles, and Google publicly pushed back. Danny Sullivan responded to the idea that Google dislikes old content with "That's not a thing!" Mueller called deleting original reporting a terrible idea and said blind deletion does not improve SEO.
Read the third one as the constraint on the first two. Pruning works when it removes pages that were never going to earn anything. It does not work as a freshness signal, and it will not substitute for having something to say. My own gate encodes the same idea: fit, not age.
What I could not find: any published dataset on merge direction outcomes specifically. Every pruning case study I read reports pages removed and traffic gained; none report how many of their merges were pointed at the wrong URL. My 21-of-48 is a sample of one site. Treat it as a reason to go and count your own.
Running it without breaking the site
Two classes of problem sat around the prune. Neither was caused by scoring and both are worth pre-empting.
Broken internal links. After the cut I found 32 broken internal links live on the site. Twenty-two of them existed because a seed file had been committed to the repo but never actually run against the database, so the links pointed at posts that had only ever existed in a .sql file. Crawl your own site after the prune. The database is the source of truth for what is published, and a .sql file sitting in the repo proves nothing about it.
Orphaned clusters and missing metadata. These predated the prune and I fixed them in a technical pass before the prune SQL was written: a 404 at /for was orphaning all 20 persona pages beneath it, 164 of 453 built pages shipped with no og:image, and the site emitted a separate anonymous Person entity on every page. They belong in the same window as a prune anyway. A prune changes which pages link to which, so any latent orphan gets quietly worse the moment you start unpublishing. I wrote up a related failure in the canonical hostname bug that cost three months of indexing.
The prune is one operation inside a larger loop — plan, publish, measure, cut. Without the loop you will regrow the same 279 posts in eighteen months. That loop is what I mean by a content system, and knowing whether it is working is its own discipline, covered in the five SEO metrics that matter.
FAQ
How do I decide what to delete versus what to merge?
Score first, then check the merge is even worth doing. Delete when the page has no evidence, no impressions, and no positioning fit: under 35 on the model above. Merge only when both pages target genuinely the same intent and at least one of them has search signals worth preserving. Two thin posts on the same topic should both be deleted, not merged into one thin post.
Should I 301 redirect or 410 deleted content?
Redirect when there is a genuinely equivalent page to send the reader to. Return 410 (or 404) when there is not. A redirect to a page that does not replace the original tends to be treated as a soft 404 anyway, per Mueller, so you gain nothing and add a redirect to maintain.
Will my traffic drop after content pruning?
Inflow's case study recorded an initial drop in organic keyword footprint before the 104% session increase over roughly 90 days. Expect the keyword count to fall, because you removed pages that ranked for something, and judge on clicks rather than keyword totals. My own site had 22 clicks to lose, so the downside was bounded.
How many pages should I prune at once?
I cut 61% in one pass, which is aggressive and only defensible because 111 of 182 ranking pages earned five or fewer impressions. If your corpus has genuine performers mixed in, work in waves and let each wave settle before the next, so you can attribute the change to something.
Sitting on a few hundred posts you are not sure about? Score them before you re-read them — the formula makes decisions your sunk-cost instinct will not. Try the content ROI calculator or get in touch.
Get the AI-SEO Content Checklist
A practical checklist for getting your own content cited by Google AI Overviews, ChatGPT, and Perplexity — not just ranked.
Browse all free guides →Run this on your own numbers
Content ROI & Payback Calculator — free, no signup, runs in your browser.
Want to implement this with guidance?
Santosh helps founders turn insights like this into real systems.
External Resources
Further Reading & Tools
Google Search Central
Official Google documentation on indexing, ranking, and Core Web Vitals
Ahrefs Blog
In-depth SEO research, keyword strategy, and link-building studies
Moz Learn SEO
Comprehensive SEO learning hub covering technical and on-page fundamentals
Search Engine Journal
SEO news, algorithm updates, and strategy guides