Migrations are priced by the pound. Every page you haul to the new site costs money to move and attention to maintain forever after — and on a ten-year-old site, a third of the pages are usually doing nothing for anyone. A content audit is how you find out which third, with data instead of vibes, before the migration quote is written. Think of it as packing for a portage: everything you carry, you carry the whole way. You’ll need a spreadsheet, admin access to your analytics and Search Console, and an honest ninety minutes.
Export the full page inventory
First, the complete list of what exists — not what the menu shows, which is always a fraction of the truth. Crawl the site with Screaming Frog: the free version handles 500 URLs, which covers most small sites; bigger sites need the paid license or an export straight from the CMS. If you have CMS access, the database is the ground truth (three queries that tell you what you own):
# Drupal: published nodes by type
drush sqlq "SELECT type, COUNT(*) FROM node_field_data WHERE status=1 GROUP BY type"
# WordPress: published content by type
wp post list --post_status=publish --format=count
Get every URL into column A of a spreadsheet, one row per page. That row count is the number that anchors everything else — say it out loud once.
Pull traffic and search data for each URL
Now find out who actually visits. From GA4, export the last twelve months
of the Pages and screens report (twelve, not three — seasonal
businesses have seasonal pages). From Google Search Console, export the
Performance → Pages report, which adds clicks and impressions from
search and reaches back sixteen months. Match both against your inventory
by URL — a VLOOKUP or a pivot table gets it done. Add columns for
pageviews, search clicks, and last-updated date. Pages that appear in your
inventory but in neither export are your first candidates for the retire
pile: nobody’s reading them, and Google isn’t sending anyone.
Sort everything into keep, merge, and retire
Add a column called Decision with exactly three allowed values. Keep: earns traffic or serves a real purpose (legal pages and the contact page stay regardless of numbers). Merge: four thin pages about the same service become one good one. Retire: no traffic, no purpose, no legal reason to exist — the 2014 staff picnic gallery goes here. Be ruthless on retire and careful on merge; a page with search clicks is an asset the migration cannot lose, even when it’s ugly.
Map old URLs to new homes
For every keep and merge row, add a New URL column. Keeps may land on the same path or a cleaner one; merges all point at the single page that absorbs them. Retires get either a genuinely relevant parent page or a deliberate 410 — don’t point forty dead pages at the homepage, because search engines treat that as a soft 404 and users treat it as a shrug.
Plan redirects for everything that moves
Every row where the old URL and new URL differ needs a 301 redirect, written down now, while the mapping is fresh. Filter the sheet to those rows and export the two columns as your redirect map — the file becomes the migration team’s punch list, whether it lands in Drupal’s Redirect module, a WordPress plugin, or the server config.
Sanity-check the totals before you sign off
The audit is verified with arithmetic. Keep + merge + retire must equal your inventory count from step one — a gap means unaudited pages. Every keep and merge row must have a New URL; every changed URL must appear in the redirect map. Then spot-check the top twenty URLs by search clicks and confirm each one has a home you’d be happy to land on. If those three checks pass, you know exactly what you’re carrying across — and exactly what you’re finally allowed to leave on the far shore.