Content Audit Template: Keep, Update, Merge or Remove
Which columns does a content audit template need, and where does each one come from?
Updated
A content audit template works when every column has a free source and a rule that turns it into one action. Set the thresholds first, apply the rules in order, and use the CSV only after you know where each number comes from.
Google's rules limit what pruning can do. Redirects, noindex and removal each send a different signal, so pick the response from what the reader should do next.
Related guides: content strategy for topic clusters and funnel stages, Complete SEO Checklist and its cannibalization task, programmatic SEO checklist and its sunset workflow, SEO audit tool for crawl and technical columns, free SEO tools for the gaps your crawl leaves.
Content Audit Template Columns: What Each One Holds
Build the sheet with one row per URL, and key each row on the canonical URL. Search Console attributes clicks, impressions and position to the canonical URL, not to the duplicate.
After a merge and a 301 redirect, the old URL's rows fade and the target's rows rise. Track the target URL in the sheet, and keep the old URL until its rows stop appearing.
The seven groups are inventory, Search Console, GA4, links, judgment, decision and process. The judgment and decision columns are yours to fill. The rest come from a crawler, Search Console, GA4 or your CMS.
For the crawl and technical columns, start with the SEO audit tool, then add the crawler export.
All 31 columns, what each holds and where to pull it free
Units: clicks and impressions are counts. click_change_pct is a plain percent number, such as -35.4. ga4_engagement_rate is a decimal, such as 0.61 for 61 percent, as GA4 returns it.
| Column | Group | What it holds | Where to pull it free | Source |
|---|---|---|---|---|
| url | Inventory | Address of one page. One row per URL. | Crawler export. Screaming Frog free covers up to 500 URLs; compare the list with the sitemap. | Screaming Frog FAQ |
| canonical_url | Inventory | The version Google treats as preferred. This is the join key to Search Console. | Canonical column in the crawler export. | Search Console Help |
| http_status | Inventory | Status code the page returns now. | Status code column in the crawler export. | Google HTTP status guide |
| indexable | Inventory | Yes or no, after noindex, canonical and robots blocks. | Indexability column in the crawler export. | Google noindex guide |
| title | Inventory | Page title, used to spot duplicates. | Title column in the crawler export. | Crawler export |
| content_type | Inventory | Guide, post, landing page or docs. | Label it from the URL folder or your CMS content type. | Your own rule |
| published_date | Inventory | First public date, in YYYY-MM-DD format. | CMS export. | Google helpful content guide |
| last_updated | Inventory | Date of the last real edit, not a typo fix. | CMS revision history. | Google helpful content guide |
| gsc_clicks_90d | Search Console | Clicks in the last 90 days, per page. | Performance report, Pages tab, last 3 months, or the API with the page dimension. | Search Console API guide |
| gsc_impressions_90d | Search Console | Impressions in the same 90 days. | Same export. | Search Console metrics help |
| gsc_avg_position | Search Console | Average position of the page across its queries. | Same export. | Search Console metrics help |
| gsc_clicks_prior | Search Console | Clicks in the same 90 days one year earlier. The window must fall inside 16 months. | Same report with the earlier date range. | Google Analytics Search Console help |
| click_change_pct | Search Console | Percent change from the earlier window, as a plain number such as -35.4. | Sheet formula: current minus prior, divided by prior. Leave it blank when prior is 0. | Shila |
| top_query | Search Console | The query that brings the most clicks to the page. | API request with page and query dimensions. Some rows can drop out. | Search Console API guide |
| queries_ranking | Search Console | Number of query rows the page appears in. | Count of rows per page in the query export. Anonymized queries are missing. | Search Console API blog |
| cannibalizing_url | Search Console | Another of your URLs that ranks for the same top query. | Group URLs by top query. Any query with two or more of your pages is a candidate. | Distribb |
| index_status | Search Console | Page indexing reason, such as Crawled - currently not indexed. | Page indexing report, or URL Inspection for URLs beyond the report list. | Search Console Help |
| ga4_organic_sessions | GA4 | Sessions with Organic Search as the default channel group, by landing page. | GA4 report by landing page, filtered on Organic Search. | GA4 API schema |
| ga4_engagement_rate | GA4 | Engaged sessions divided by sessions, as a decimal such as 0.61. | engagementRate field in GA4. | GA4 API schema |
| ga4_key_events | GA4 | Key events with the page as landing page. | GA4 key events by landing page. Counts start on the date the event was marked as a key event. | GA4 API schema |
| referring_domains | Links | Number of domains that link to the page. | Ahrefs Free for sites you own, or the Search Console Links report. | Ahrefs Free |
| internal_inlinks | Links | Number of internal links that point to the page. | Inlinks column in the crawler export. | Crawler export |
| quality_score_1_5 | Judgment | Your score from 1 to 5 against Google's content questions. | You score it with the three questions in the ladder section. | Google helpful content guide |
| needed_by_users | Judgment | Y when customers need the page even though search does not. | You decide, with input from sales and support. | Shila |
| action | Decision | keep, update, merge, redirect, noindex, remove or wait. | Apply the ladder in order. | Distribb |
| target_url | Decision | The page a merge or redirect sends the URL to. | You choose it, and it must answer the same need. | Google site move guide |
| final_status | Decision | Status after the change: 200, 301, 404, 410, or 200 with noindex. | You set it when the change ships. | Google HTTP status guide |
| reason | Decision | One line that names the rule and the number that fired it. | You write it. | Your own rule |
| owner | Process | Person who owns the change. | You assign it. | Your own rule |
| priority | Process | 1 to 3, with 1 first. | You assign it. | Your own rule |
| review_date | Process | First date to check the page after the change. | Set it after the data lag, as the last section explains. | Search Console API guide |
Phase 1: Build the URL list
| Task | Why it matters | How to check | Source |
|---|---|---|---|
| Crawl every URL you can reach | The status, canonical and indexability columns come from the crawl. | Count the crawled URLs and compare the count with the sitemap. A large gap means the crawl missed a section. | Screaming Frog FAQ |
| Plan for the free crawl limit | The free Screaming Frog version stops at 500 URLs per crawl and cannot save crawls. | Above 500 URLs, split the crawl by folder, export before you close the tool, or buy a licence at £199 a year. | Screaming Frog FAQ |
| Set the join key | Search Console reports canonical full URLs, while GA4 landing pages are paths only. | Add the host to GA4 paths. Then match trailing slashes, www and letter case before you count a page as having no data. | GA4 API schema |
| Find pages with data but no crawl row | A page that earns clicks but has no crawl row may be an orphan, a redirect or a dropped URL. | Compare the Search Console page list with the crawl list, and inspect each gap by hand. | Google guide to combining the tools |
| Fill the gaps with free sources | The crawl cannot supply traffic, links or judgment columns. | Start with the free SEO tools list on this site, then use the source named in the columns table for each gap. | Free SEO tools |
Pull Each Column for Free and Check the Limits
Google recommends one query per day of data, so pull each day separately from the API. The interface export stops at 1,000 rows. The API allows up to 50,000 rows per day per site per search type.
The API default is 1,000 rows. Set rowLimit anywhere from 1 to 25,000, then use startRow to pull the next block, such as rows 25,001 to 50,000.
Page with startRow until a response comes back empty, so the last block is not missed.
Anonymized queries stay out of the tables, but chart totals still count them. Requests that combine page and query can drop rows, so treat the query column as a partial view.
Search Console keeps 16 months of data. Two full 12-month windows need 24 months, so a 12-month against prior-12-month comparison cannot come from Search Console alone. Compare the last 90 days with the same 90 days a year earlier, which fits inside the window.
A daily BigQuery bulk export keeps your own copy from the day you turn it on. It holds all performance data except anonymized queries.
GA4 landing pages are paths, so add the host before you join them to Search Console URLs. A GA4 Data API report returns 10,000 rows by default, and a limit of 250,000 raises it.
A standard GA4 property gets 200,000 core tokens per day, 40,000 per hour and 10 concurrent requests. Token cost rises with rows, columns, filter complexity and date range.
The default sampling setting for standard GA4 properties is 10m events. Results can group the least common values under an (other) row.
GA4 data thresholds are system defined, and you cannot change them. Data retention settings affect explorations and funnel reports, not standard reports.
The Search Console Links report is a sample, and its tables stop at 1,000 rows. Ahrefs Free is free for websites you add to it, and it shows which websites and pages link to yours.
Distribb says referring domains per URL are the one thing you cannot get free at any scale. Treat that as vendor advice, and plan for the limits of each free source.
The Page indexing report gives totals but may list only up to 1,000 URLs. URL Inspection allows 2,000 queries per day and 600 per minute per site, so a 10,000-URL sheet needs at least 5 days of inspection.
The free Screaming Frog SEO Spider crawls up to 500 URLs per crawl and cannot save crawls. Its licence costs £199 a year.
Search Console and GA4 totals never match exactly. Google says the trends follow the same pattern, and clicks and sessions are the most comparable pair.
Phase 2: Pull the data
| Task | Why it matters | How to check | Source |
|---|---|---|---|
| Pull by day | Google recommends one query per day of data, which keeps each request inside the daily limits. | Check the newest date with data before you start, because performance data arrives after a short lag. | Search Console API guide |
| Page the API with startRow | A single request stops at the row limit, so the rest of the rows need more requests. | If the row count equals rowLimit, request the next block with a higher startRow. | Search Console API blog |
| Pull GA4 by landing page | Sessions and engagement come per page, and the default sampling setting can change the totals. | Filter the default channel group to Organic Search, then look for an (other) row. Sessions in that row are missing from the page list. | GA4 sampling help |
| Pull referring domains | The link column feeds the dead-page rule in the ladder. | Use Ahrefs Free for sites you own. Use the Links report only when its table shows fewer than 1,000 rows. | Ahrefs Free |
| Inspect the URLs beyond the report list | The index status column needs URL Inspection when the Page indexing report stops short. | Inspect in batches that stay within the daily quota of 2,000 queries per site. | Search Console limits |
Set Your Thresholds Before You Sort Anything
Set every threshold before you sort the sheet. None of these numbers comes from Google. Each one is a vendor rule of thumb or a template default, so change it for your site.
Distribb built its thresholds from its own blog audit and calls them rules of thumb, not a validated model.
Distribb reads 90 days of Search Console data, and it uses 12 months when traffic is strongly seasonal.
Sites with high domain authority should raise every impression threshold. A new site should wait longer before it deletes anything.
Shila calls its thresholds starting points, not laws. On a small site, 30 clicks a year can be a meaningful page.
Placeholder thresholds for the sheet
Enter these as editable placeholders on a second tab. Each starting value comes from a vendor rule or a template default, so set your own value before you use the action column.
| Placeholder | Starting value | Vendor rule it adapts | What to set it to | Source |
|---|---|---|---|---|
| min_age_months | 6 | Distribb waits on pages younger than 6 months with under 20 impressions. Shila monitors pages published under 6 months. | Set it higher for a new site, as Distribb advises. | Distribb |
| link_min_ref_domains | 1 | Template default. No vendor sets this number. Distribb keeps or redirects pages with referring domains. | Set it to 1 to keep any linked page. | Distribb |
| position_band_low | 4 | Distribb updates pages from position 4 to 15 that have enough impressions. | Set it to the best position where a push still pays. | Distribb |
| position_band_high | 15 | Upper edge of the Distribb band. Shila uses 5 to 20 for a similar call. | Use 20 to match Shila's band. | Shila |
| update_min_impressions | 200 | Distribb updates pages in the band with more than 200 impressions. | Raise it for a high-authority site. | Distribb |
| drop_pct | -30 | Shila updates pages that lost 30% or more of clicks year over year and still rank in the top 20. This template compares 90 days with the same 90 days a year earlier. | Set the drop that is large enough for your team to act on. | Shila |
| dead_max_impressions | 20 | Distribb treats pages with under 20 impressions as candidates for removal or redirect, once they are old enough. | Raise it for a high-authority site. | Distribb |
| dead_min_age_months | 6 | Distribb removes or redirects pages older than 6 months with no links. | Keep it at least as high as min_age_months. | Distribb |
Decide Keep, Update, Merge, Redirect, Noindex or Remove, in Order
Apply the rules in this order, and stop at the first rule that matches. A page with backlinks and no traffic is a redirect candidate, never a delete.
- Wait: the page is younger than
min_age_months. Give it time before you make any other call. - Merge: another of your URLs ranks for the same top query and earns more clicks in the same window. Move the unique content into that page first, then redirect with a 301.
- Noindex: customers need the page, and its impressions are at or below
dead_max_impressions. Search should not show it. - Update: the average position falls between
position_band_lowandposition_band_high, and impressions are at or aboveupdate_min_impressions. - Update: clicks fell by
drop_pctor more, and the average position is 20 or better. - Redirect or remove: impressions are at or below
dead_max_impressions, and the page is at leastdead_min_age_monthsold. If the page has referring domains at or abovelink_min_ref_domains, or any key event, and a live page answers the same need, redirect it to that page. Otherwise, remove it with a 404 or 410. - Keep: no rule above matched.
A page answers the same need when a live page covers the same question for the same reader. A page on a related topic does not count. For a whole-site view of cannibalization, the complete SEO checklist has a one-line task, and this ladder goes deeper.
Google's content questions help decide update or merge. Ask whether the page adds substantial value compared with other pages in search results.
Score quality_score_1_5 from 1 to 5 with three of Google's questions. Ask whether the content gives original information, reporting, research or analysis, and whether it gives a substantial, complete description of the topic. Ask whether it avoids copying or rewriting other sources.
Phase 3: Apply the ladder
| Task | Why it matters | How to check | Source |
|---|---|---|---|
| Group URLs by top query | Cannibalization shows up as two or more of your pages on one query. | Any query with two or more of your pages goes on the merge check list. | Distribb |
| Score the page quality | The update or merge call depends on whether the page adds value compared with other results. | Score each page against the three Google questions, then enter the score in quality_score_1_5. | Google helpful content guide |
| Mark the pages customers need | Stops you from deleting pages that customers still use, even when search traffic is low. | Ask sales and support which pages customers open, then set needed_by_users to Y for those pages. | Shila |
| Check links before any removal | Deleting a page with backlinks throws away the link value it earns. | Filter for referring_domains above 0 and ga4_key_events above 0 before you set remove. | Distribb |
Helpful Content Rules That Limit Pruning and Freshness Edits
Pruning does not raise the rest of the site by itself. Google says adding or removing a lot of content to make a site seem fresh will not help rankings.
Keep the visible date honest. Google asks whether page dates were changed to seem fresh when the content has not substantially changed.
Scaled content abuse covers many pages made mainly to manipulate rankings, however they are made. Send those pages to removal or merge, not to update.
Google lists producing lots of content on many topics in hope that some of it performs as a warning sign. So does summarizing what others say without adding much value.
Word count is not a threshold. Google says it has no preferred word count, so do not cut pages by length alone.
Start the review from the drops. Google suggests auditing the pages most affected by a drop, and the search types they lost.
Google says the helpful content system became part of its core ranking systems.
For template pages, the programmatic SEO checklist has a sunset workflow for pages that get no traffic. Use it before you remove a template set.
Merge and Redirect: When to Consolidate and When Not To
Merge when two pages answer the same question. Semrush uses this label for pages that cover very similar topics and rank for similar keywords. Plan topic clusters on the content strategy page before you merge pages inside a cluster.
Google ranks its consolidation signals. Redirects are a strong signal, rel=canonical is a strong signal, and sitemap inclusion is a weak one. The methods stack.
Do not use noindex to choose a canonical within one site. Google says noindex blocks the page from Search completely, so use rel=canonical.
Do not use robots.txt for canonicalization. Google may still index URLs that robots.txt disallows, without their content.
Redirect several old URLs to one page only when that page holds the consolidated content. Google warns that redirecting many old URLs to one irrelevant page may be treated as a soft 404.
Distribb tells readers to redirect a page that has referring domains, even to a loosely related page. Google's guidance points the other way, so this checklist follows Google. Redirect only to a page that answers the same need, and return a 404 or 410 when none does.
Keep each redirect in place for as long as possible. When you chain a second redirect, point the first URL straight at the final target, as Distribb advises.
Phase 4: Merge, redirect or remove
| Task | Why it matters | How to check | Source |
|---|---|---|---|
| Move unique content first | The target must hold the facts the old page held. | Compare the headings of both pages. Every heading from the old page should appear in the target before the redirect goes live. | Google site move guide |
| Redirect straight to the final target | Redirect chains add hops and blur the signal Google receives. | Follow each old URL and confirm it reaches the final page in one hop. Googlebot follows up to 10 hops. | Google HTTP status guide |
| Fix the internal links | Internal links to removed pages become 404s. | Crawl the site again after each batch, and point internal links at the target. | Distribb |
| Keep the redirect in place | Google says to keep redirects for as long as possible. | Log each redirect and its date in the sheet. Do not remove a redirect because the page looks quiet. | Google site move guide |
| Check the index report | A merged URL should show as redirected, not as an error. | Expect Page with redirect for merged URLs. Investigate any other reason. | Search Console Help |
404, 410, 301, Noindex or Password: Which Response to Use
What Google documents for each response
Pick the response from what the reader should do next. Each code sends Google a different signal, so match the code to the action in the ladder.
| Response | What Google documents | Use it when | Source |
|---|---|---|---|
| 404 Not Found | Google treats all 4xx codes except 429 the same, and removes an indexed URL from the index. | The page is gone and no live page replaces it. | Google HTTP status guide |
| 410 Gone | Google treats 410 the same as 404, and removes an indexed URL from the index. | The page is gone for good, and you want the removal to read as permanent. | Google HTTP status guide |
| 301 Moved Permanently | Google uses a 301 as a strong signal that the target should be processed. | A live page answers the same need. | Google HTTP status guide |
| Noindex | Google drops the page from results regardless of its links. The page must stay crawlable, or the tag is never seen. | Customers need the page, but search should not show it. | Google noindex guide |
| Password or removed content | Google lists removing or updating the content, password-protecting it, or adding noindex. Removal requests last for a limited time. | Nobody should reach the content, including through old links. | Google removal guide |
| 200 with an error message | An empty page or an error message on a 200 response is treated as a soft 404. | Never. A page that is truly missing should return a 404. | Google HTTP status guide |
Whether a 410 leaves the index faster is not settled. Seer Interactive quotes a Mueller comment from 2018 that a 410 can fall out a little faster, on the order of a couple of days.
Google's own documentation lists both codes under the same treatment, so do not plan a timeline around the difference.
A 404 is not necessarily a problem when the page was removed with no replacement. If the page moved, use a 301 redirect to the new location. Googlebot keeps crawling a removed URL less and less often, and you cannot tell it to forget a URL.
Permanent redirects show the new target in results, so use one only when the redirect will not be reverted.
Download the Content Audit Template CSV and Load It Today
Download the content audit template CSV. Three invented example rows show the ladder.
The three example rows are invented. Their numbers are not data, and each row has owner set to example. Replace them before you use the sheet.
Keep the placeholder thresholds on a second tab, and point the action column at those cells. Apply the ladder in order, then check the reason column for each row.
Three invented example rows and the rule each one triggers
| Example | Invented inputs | Action | Rule that fires |
|---|---|---|---|
| Example 1: email deliverability basics | Position 9.4, 4,200 impressions, 310 clicks against 480 a year earlier (a change of -35.4 percent), published about 19 months ago. | update | Rule 4: the position sits inside the band and impressions are above 200. Rule 4 applies before rule 5. |
| Example 2: older post on the same query | 58 clicks against 310 for example 1, the same top query, published in 2024. | merge into example 1, then 301 | Rule 2: another URL on the same top query earns more clicks. |
| Example 3: 2019 webinar recap | 3 impressions, no clicks in the window, no referring domains, no key events, published in 2019. | remove with 410 | Rule 6: impressions are at or below 20, the page is old enough, and it has no links or key events. |
Measure Each Action After the Search Data Lags
Re-pull Search Console after the lag, and use the same window before and after the change. A pull on the day of the change shows little new data.
Compare clicks and sessions, the two most comparable metrics. Totals will not match exactly, but the trends should follow the same pattern.
Measure each action by the pages it changed, not by the whole site. One page's result should not hide the rest of the group.
Annotate each change with its date in the sheet. A later reader can then match each trend to the change that caused it.
Phase 5: Measure the result
| Task | Why it matters | How to check | Source |
|---|---|---|---|
| Set review_date | Gives each action a fixed date to check. | Set it after the data lag, and use the same window for the before and after pulls. | Search Console API guide |
| Re-pull the same window | Keeps the before and after numbers comparable. | Check that the start and end dates match the earlier pull. Search Console keeps 16 months, so the earlier window must fall inside it. | Google Analytics Search Console help |
| Compare clicks and sessions | These are the two most comparable metrics across the two tools. | Join the exports on the landing page path, then compare the direction of each trend. | Google guide to combining the tools |
| Check the index status | Confirms that the response took effect. | Expect Page with redirect on merged URLs, and check that removed URLs no longer show as indexed. | Search Console Help |
Common Questions
Search Console keeps only 16 months. How do I compare a page against last year?
Search Console keeps 16 months of data, so a 12-month against prior-12-month comparison cannot come from Search Console alone. Compare the last 90 days with the same 90 days a year earlier, which fits inside that window. Turn on a daily BigQuery bulk export to keep your own copy from the day you enable it. The export leaves out anonymized queries.
My export stops at 1,000 rows. Is the rest of the data gone?
No, but the interface export stops at 1,000 rows. The API returns up to 50,000 rows per day per site per search type. Request one day at a time, set rowLimit to 25,000, and page with startRow until a response comes back empty. Anonymized queries never appear in the tables, and requests that combine page and query can drop rows, so treat query-level figures as a partial view.
Should I remove a dead page with a 404 or a 410?
Google documents 404 and 410 the same way: the content does not exist, and an indexed URL leaves the index. John Mueller said, as Search Engine Roundtable reported, that the difference is too small to prefer one for SEO. Seer Interactive quotes an older Mueller comment saying a 410 can fall out a little faster, on the order of a couple of days. Pick the code your server returns cleanly, and never serve an error message on a 200 page, which Google treats as a soft 404.
Can I redirect a retired page to the home page to keep its links?
Google warns that redirecting many old URLs to one irrelevant destination, such as the home page, may be treated as a soft 404. A redirect fits when the target now holds the consolidated content. Distribb advises redirecting to a loosely related page when referring domains exist, but this checklist follows Google. When no live page answers the same need, return a 404 or 410, and list the linking domains so their owners can update the link.
When is noindex the right call instead of a redirect or removal?
Use noindex when customers still need a page but search should not show it, such as old release notes. Google drops a noindex page from results regardless of the links it has. The page must stay crawlable, because a robots.txt block hides the noindex tag. Do not use noindex to pick between duplicates. Google prefers rel=canonical for that, since noindex blocks the page completely.
Will pruning old posts make the rest of the site rank better?
Google says adding or removing a lot of content to make a site look fresh will not help rankings, so pruning for freshness is a weak reason on its own. Remove or merge pages that are wrong, duplicated or off topic, and measure each action on its own pages. Google treats scaled content abuse, many pages made mainly to manipulate rankings, as a removal or merge case rather than an update case.
Next step
Run the Search Console and GA4 pulls for one folder first, then apply the ladder there before you change the whole site. For the wider plan, read the SEO guide for practitioners.