Migrating a website is one of those things that sounds straightforward until you’re knee-deep in broken links, tanked rankings, and pages that have vanished from Google overnight.
Fun times.
Whether you’re switching hosting providers, moving to a new domain, replatforming from WordPress to something else (or onto WordPress), or doing a full site redesign… a website migration touches everything. Your URLs, your content, your SEO, your site structure. All of it.
The good news?
With a solid plan, you can make changes to your site without losing the rankings and traffic you’ve worked hard to build.
That’s exactly what this website migration checklist is for – and our migration checklist builder!
We’ve broken the entire migration process into clear, actionable steps so you can move your site with confidence.
Let’s get into it.
TLDR
Website migration doesn’t have to be a nightmare… but it will be if you wing it.
Back up everything first.
Crawl your existing site so you know what you’re working with.
Map every single redirect (no, not just the important ones… all of them).
Set up a staging environment.
Check your on-page SEO hasn’t gone walkabout during the move.
Submit a fresh sitemap.
Then pedagogo everything like a hawk for the first month post-launch.
The short version? Plan it properly, redirect it completely, and test it obsessively. That’s 90% of a successful migration right there.
What Is a Website Migration?
Before we jump into the checklist, let’s get the basics sorted.
A website migration is any significant change to your site that can impact how search engines crawl, index, and rank your pages. That includes things like:
Moving to a new domain (e.g. oldbusiness.com.au to newbrand.com.au). Switching hosting providers or servers. Replatforming (say, from Squarespace to WordPress). A full site redesign with new URLs and page structure. Moving from HTTP to HTTPS. Or even merging multiple sites into one.
Each of these changes carries SEO risk. Google needs to re-crawl and re-index your new site, and if it can’t find or understand your pages properly… your rankings take a hit.
PRO TIP: Not all migrations are equal. A simple hosting change with no URL changes is far lower risk than a full domain migration with a new site structure. Understand which type of migration you’re doing, because that determines how much SEO work is involved.
Build Your Custom Migration Checklist
Every migration is different. Moving hosting providers? That’s a very different job to a full domain change with a site redesign thrown in.
So we built something to help.
Our free Website Migration Checklist Generator lets you select exactly what type of migration you’re doing, and it builds a step-by-step checklist tailored to your situation. No fluff. No irrelevant steps. Just the tasks you actually need to complete, in the right order.
Whether you’re replatforming to WordPress, switching domains, merging two sites into one, or just upgrading your hosting… select what applies, and the tool does the rest.
/* ── DNHQ Design System — high specificity to survive page themes ── */
.mig-wrapper, .mig-wrapper *, .mig-wrapper *::before, .mig-wrapper *::after {
box-sizing: border-box !important;
margin: 0;
padding: 0;
}
.mig-wrapper {
font-family: ‘Inter Tight’, sans-serif !important;
max-width: 1200px !important;
margin: 0 automóvil !important;
background: #ffffff !important;
border: 1px solid #e6e9ec !important;
box-shadow: 0 15px 40px rgba(0,42,69,0.08) !important;
border-radius: 16px !important;
overflow: hidden !important;
color: #002A45 !important;
width: 100% !important;
}
/* ── Header ── */
.mig-wrapper .mig-header {
background: #86A4ef !important;
padding: 40px 40px 32px !important;
text-align: center !important;
}
.mig-wrapper .mig-header h1 {
font-family: ‘Barlow Condensed’, sans-serif !important;
font-size: 36px !important;
font-weight: 700 !important;
color: #fff !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
line-height: 1.1 !important;
margin: 0 0 8px !important;
padding: 0 !important;
background: none !important;
border: none !important;
}
.mig-wrapper .mig-header p {
font-size: 15px !important;
color: rgba(255,255,255,0.8) !important;
margin: 0 !important;
font-weight: 400 !important;
}
/* ── Body / Sections ── */
.mig-wrapper .mig-body {
padding: 40px !important;
animation: migFadeIn 0.4s ease;
background: #ffffff !important;
}
@keyframes migFadeIn {
from { opacity: 0; transform: translateY(5px); }
to { opacity: 1; transform: translateY(0); }
}
/* ── Wizard Form ── */
.mig-wrapper .form-section {
margin-bottom: 32px !important;
}
.mig-wrapper .form-section label {
display: block !important;
margin-bottom: 10px !important;
font-size: 14px !important;
font-weight: 700 !important;
color: #002A45 !important;
padding: 0 !important;
background: none !important;
}
.mig-wrapper .form-section .hint {
font-size: 13px !important;
color: #7a8ea0 !important;
margin-bottom: 10px !important;
font-weight: 400 !important;
}
.mig-wrapper .option-grid {
display: grid !important;
grid-template-columns: 1fr 1fr !important;
gap: 10px !important;
max-width: 100% !important;
overflow: hidden !important;
}
.mig-wrapper .option-grid.three-col { grid-template-columns: 1fr 1fr !important; }
.mig-wrapper button.option-btn {
display: flex !important;
align-items: center !important;
gap: 10px !important;
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
padding: 14px 18px !important;
background: #fcfcfc !important;
border: 1px solid #d1d9e0 !important;
border-radius: 12px !important;
font-size: 14px !important;
font-family: ‘Inter Tight’, sans-serif !important;
font-weight: 500 !important;
color: #002A45 !important;
cursor: pointer !important;
transition: border-color 0.3s, box-shadow 0.3s, background 0.3s !important;
text-align: left !important;
-webkit-appearance: none !important;
appearance: none !important;
text-decoration: none !important;
text-transform: none !important;
line-height: 1.4 !important;
letter-spacing: común !important;
box-shadow: none !important;
outline: none !important;
overflow: hidden !important;
}
.mig-wrapper button.option-btn:hover {
border-color: #86a4ef !important;
box-shadow: 0 0 0 3px rgba(134, 164, 239, 0.15) !important;
background: #fff !important;
color: #002A45 !important;
}
.mig-wrapper button.option-btn.selected {
border-color: #86a4ef !important;
box-shadow: 0 0 0 3px rgba(134, 164, 239, 0.2) !important;
background: #fff !important;
color: #002A45 !important;
}
.mig-wrapper .option-btn .option-label {
flex: 1 !important;
min-width: 0 !important;
overflow: hidden !important;
}
.mig-wrapper .option-btn .option-desc {
display: block !important;
font-size: 12px !important;
font-weight: 400 !important;
color: #7a8ea0 !important;
margin-top: 2px !important;
text-transform: none !important;
}
.mig-wrapper button.option-btn.selected .option-desc { color: #86a4ef !important; }
.mig-wrapper .multi-select button.option-btn.selected::after {
content: ‘✓’ !important;
font-weight: 700 !important;
color: #CDFFB6 !important;
background: #002A45 !important;
width: 22px !important;
height: 22px !important;
border-radius: 6px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
font-size: 12px !important;
flex-shrink: 0 !important;
}
/* ── Primary Button ── */
.mig-wrapper button.btn-primary {
display: flex !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
width: 100% !important;
padding: 18px 32px !important;
background: #002A45 !important;
color: #CDFFB6 !important;
border: none !important;
border-radius: 12px !important;
font-family: ‘Barlow Condensed’, sans-serif !important;
font-size: 20px !important;
font-weight: 600 !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
cursor: pointer !important;
transition: background 0.3s, box-shadow 0.3s !important;
box-shadow: none !important;
text-decoration: none !important;
line-height: 1.2 !important;
}
.mig-wrapper button.btn-primary:hover { background: #001c30 !important; box-shadow: 0 8px 24px rgba(0,42,69,0.2) !important; color: #CDFFB6 !important; }
.mig-wrapper button.btn-secondary {
display: inline-flex !important;
align-items: center !important;
gap: 6px !important;
padding: 10px 18px !important;
background: #fcfcfc !important;
color: #002A45 !important;
border: 1px solid #d1d9e0 !important;
border-radius: 12px !important;
font-family: ‘Inter Tight’, sans-serif !important;
font-size: 13px !important;
font-weight: 600 !important;
cursor: pointer !important;
transition: all 0.3s !important;
text-decoration: none !important;
text-transform: none !important;
letter-spacing: común !important;
line-height: 1.4 !important;
box-shadow: none !important;
}
.mig-wrapper button.btn-secondary:hover {
border-color: #86a4ef !important;
box-shadow: 0 0 0 3px rgba(134, 164, 239, 0.15) !important;
background: #fff !important;
color: #002A45 !important;
}
.mig-wrapper button.btn-xlsx {
border-color: #86a4ef !important;
color: #002A45 !important;
background: #f0f4ff !important;
}
.mig-wrapper button.btn-xlsx:hover { background: #e0e8ff !important; }
/* ── Progress Section (results-box style) ── */
.mig-wrapper .progress-section {
background: #002A45 !important;
color: #fff !important;
padding: 28px 35px !important;
border-radius: 16px !important;
margin-bottom: 24px !important;
position: sticky;
top: 0;
z-index: 10;
}
.mig-wrapper .progress-header {
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
margin-bottom: 16px !important;
}
.mig-wrapper .progress-header h3 {
font-family: ‘Barlow Condensed’, sans-serif !important;
font-size: 28px !important;
font-weight: 600 !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
color: #fff !important;
margin: 0 !important;
padding: 0 !important;
background: none !important;
border: none !important;
}
.mig-wrapper .progress-stats {
display: flex !important;
gap: 20px !important;
font-size: 14px !important;
color: rgba(255,255,255,0.7) !important;
}
.mig-wrapper .progress-stats strong { color: #CDFFB6 !important; }
.mig-wrapper .progress-bar-track {
height: 10px !important;
background: rgba(134, 164, 239, 0.2) !important;
border-radius: 999px !important;
overflow: hidden !important;
}
.mig-wrapper .progress-bar-fill {
height: 100% !important;
background: #86A4ef !important;
border-radius: 999px !important;
transition: width 0.4s ease !important;
min-width: 0 !important;
}
.mig-wrapper .progress-bar-fill.complete { background: #CDFFB6 !important; }
/* ── Actions Bar ── */
.mig-wrapper .actions-bar {
display: flex !important;
gap: 10px !important;
flex-wrap: wrap !important;
margin-bottom: 24px !important;
}
/* ── Phase Sections ── */
.mig-wrapper .phase {
background: #fff !important;
border: 1px solid #e6e9ec !important;
border-radius: 16px !important;
margin-bottom: 12px !important;
overflow: hidden !important;
box-shadow: 0 2px 8px rgba(0,42,69,0.04) !important;
}
.mig-wrapper .phase-header {
display: flex !important;
align-items: center !important;
gap: 12px !important;
padding: 18px 24px !important;
cursor: pointer !important;
user-select: none;
transition: background 0.15s;
background: transparent !important;
}
.mig-wrapper .phase-header:hover { background: #f8fafb !important; }
.mig-wrapper .phase-toggle {
font-size: 11px !important;
color: #86a4ef !important;
transition: transform 0.2s;
flex-shrink: 0 !important;
}
.mig-wrapper .phase-toggle.open { transform: rotate(90deg); }
.mig-wrapper .phase-badge {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
width: 32px !important;
height: 32px !important;
border-radius: 8px !important;
font-size: 14px !important;
font-weight: 700 !important;
flex-shrink: 0 !important;
}
.mig-wrapper .phase-badge.planning { background: #f0f4ff !important; color: #86a4ef !important; }
.mig-wrapper .phase-badge.prelaunch { background: #fff8e6 !important; color: #d97706 !important; }
.mig-wrapper .phase-badge.launch { background: #fef2f2 !important; color: #dc2626 !important; }
.mig-wrapper .phase-badge.postlaunch { background: #edfcf0 !important; color: #16a34a !important; }
.mig-wrapper .phase-info { flex: 1 !important; }
.mig-wrapper .phase-info h3 {
font-family: ‘Inter Tight’, sans-serif !important;
font-size: 15px !important;
font-weight: 700 !important;
color: #002A45 !important;
margin: 0 !important;
padding: 0 !important;
background: none !important;
border: none !important;
text-transform: none !important;
}
.mig-wrapper .phase-info .phase-count {
font-size: 12px !important;
color: #7a8ea0 !important;
}
.mig-wrapper .phase-progress-mini {
width: 60px !important;
height: 6px !important;
background: #e6e9ec !important;
border-radius: 999px !important;
overflow: hidden !important;
flex-shrink: 0 !important;
}
.mig-wrapper .phase-progress-mini-fill {
height: 100% !important;
background: #86a4ef !important;
border-radius: 999px !important;
transition: width 0.3s;
}
.mig-wrapper .phase-items { padding: 0 24px 16px !important; }
.mig-wrapper .phase-items.hidden { display: none !important; }
/* ── Checklist Items ── */
.mig-wrapper .checklist-item {
display: flex !important;
align-items: flex-start !important;
gap: 12px !important;
padding: 14px 0 !important;
border-bottom: 1px solid #f0f2f5 !important;
background: transparent !important;
}
.mig-wrapper .checklist-item:last-child { border-bottom: none !important; }
.mig-wrapper .check-box {
width: 22px !important;
height: 22px !important;
min-width: 22px !important;
border: 2px solid #d1d9e0 !important;
border-radius: 6px !important;
cursor: pointer !important;
flex-shrink: 0 !important;
margin-top: 1px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
transition: all 0.2s !important;
background: #fcfcfc !important;
padding: 0 !important;
}
.mig-wrapper .check-box:hover {
border-color: #86a4ef !important;
box-shadow: 0 0 0 3px rgba(134, 164, 239, 0.15) !important;
}
.mig-wrapper .check-box.checked {
background: #002A45 !important;
border-color: #002A45 !important;
}
.mig-wrapper .check-box.checked::after {
content: ‘✓’ !important;
color: #CDFFB6 !important;
font-size: 13px !important;
font-weight: 700 !important;
}
.mig-wrapper .item-content { flex: 1 !important; min-width: 0 !important; }
.mig-wrapper .item-title {
font-size: 14px !important;
font-weight: 600 !important;
color: #002A45 !important;
transition: color 0.15s;
}
.mig-wrapper .checklist-item.done .item-title {
color: #b0bec5 !important;
text-decoration: line-through !important;
}
.mig-wrapper .item-detail {
font-size: 13px !important;
color: #7a8ea0 !important;
margin-top: 4px !important;
line-height: 1.5 !important;
}
.mig-wrapper .checklist-item.done .item-detail { color: #cfd8dc !important; }
.mig-wrapper .item-tags {
display: flex !important;
gap: 6px !important;
margin-top: 8px !important;
flex-wrap: wrap !important;
}
.mig-wrapper .tag {
display: inline-block !important;
padding: 3px 10px !important;
border-radius: 6px !important;
font-size: 11px !important;
font-weight: 700 !important;
text-transform: uppercase !important;
letter-spacing: 0.3px !important;
line-height: 1.4 !important;
}
.mig-wrapper .tag.critical { background: #fef2f2 !important; color: #dc2626 !important; }
.mig-wrapper .tag.important { background: #fff8e6 !important; color: #d97706 !important; }
.mig-wrapper .tag.nice { background: #f0f4ff !important; color: #86a4ef !important; }
.mig-wrapper .tag.tool-tag {
background: #edfcf0 !important;
color: #15803d !important;
font-weight: 500 !important;
text-transform: none !important;
letter-spacing: 0 !important;
font-size: 11px !important;
}
/* ── Completion Banner ── */
.mig-wrapper .completion-banner {
text-align: center !important;
padding: 40px 24px !important;
background: #002A45 !important;
border-radius: 16px !important;
margin-bottom: 24px !important;
display: none !important;
}
.mig-wrapper .completion-banner.show { display: block !important; }
.mig-wrapper .completion-banner h2 {
font-family: ‘Barlow Condensed’, sans-serif !important;
font-size: 36px !important;
color: #CDFFB6 !important;
text-transform: uppercase !important;
margin: 0 0 8px !important;
padding: 0 !important;
background: none !important;
border: none !important;
}
.mig-wrapper .completion-banner p { color: rgba(255,255,255,0.7) !important; font-size: 15px !important; margin: 0 !important; }
.mig-wrapper .hidden { display: none !important; }
/* ── Mobile ── */
@media (max-width: 768px) {
.mig-wrapper .mig-body { padding: 25px 20px !important; }
.mig-wrapper .mig-header { padding: 30px 20px 24px !important; }
.mig-wrapper .mig-header h1 { font-size: 26px !important; }
.mig-wrapper .option-grid { grid-template-columns: 1fr !important; }
.mig-wrapper .option-grid.three-col { grid-template-columns: 1fr !important; }
.mig-wrapper .progress-section { padding: 20px !important; position: relative !important; }
.mig-wrapper .progress-header { flex-direction: column !important; gap: 8px !important; align-items: flex-start !important; }
.mig-wrapper .progress-header h3 { font-size: 22px !important; }
.mig-wrapper .phase-header { padding: 14px 16px !important; }
.mig-wrapper .phase-items { padding: 0 16px 12px !important; }
}
/* ── Print ── */
@media print {
.mig-wrapper .progress-section, .mig-wrapper .actions-bar, .mig-wrapper .btn-primary, .mig-wrapper .btn-secondary { display: none !important; }
.mig-wrapper .phase-items { display: block !important; }
.mig-wrapper .phase { break-inside: avoid; }
.mig-wrapper { box-shadow: none !important; border: none !important; }
}
Website Migration Checklist
Answer a few questions to generate a checklist tailored to your migration.
Select all that apply
Migration Complete!
You’ve checked off every item. Keep monitoring for the next 30 – 90 days.
Your Migration Progress
0%
// ── State ──
let selections = { types: [], size: null, seo: null, ecom: null };
let checkState = {};
function toggleMulti(btn) {
btn.classList.toggle(‘selected’);
const val = btn.dataset.value;
if (selections.types.includes(val)) {
selections.types = selections.types.filter(v => v !== val);
} else {
selections.types.push(val);
}
}
function selectSingle(btn, groupId) {
const group = document.getElementById(groupId);
group.querySelectorAll(‘.option-btn’).forEach(b => b.classList.remove(‘selected’));
btn.classList.add(‘selected’);
if (groupId === ‘siteSize’) selections.size = btn.dataset.value;
if (groupId === ‘seoImportance’) selections.seo = btn.dataset.value;
if (groupId === ‘ecommerce’) selections.ecom = btn.dataset.value;
}
// ── Master Checklist Data ──
const allItems = {
planning: {
label: «Phase 1: Planning & Preparation»,
badge: «planning»,
items: [
{ id: «p1», title: «Define migration scope and document all changes», detail: «List every element changing: domain, URLs, platform, design, content, hosting, protocol. Share with all stakeholders.», priority: «critical», conditions: [], tool: «» },
{ id: «p2», title: «Assemble your migration team and assign roles», detail: «Include dev, SEO, content, QA, and project management. Ensure clear ownership of each phase.», priority: «important», conditions: [], tool: «Asana / Monday.com / Jira» },
{ id: «p3», title: «Set a realistic timeline with buffer», detail: «Migrations always take longer than expected. Build in 2–4 weeks of buffer time.», priority: «important», conditions: [], tool: «» },
{ id: «p4», title: «Create a documented rollback plan», detail: «Define exactly how to revert if things go wrong — DNS rollback, backup restoration, redirect removal. Test the rollback process.», priority: «critical», conditions: [], tool: «» },
{ id: «p5», title: «Export 12+ months of organic traffic data», detail: «From Google Analytics, broken down by landing page. This is your baseline for measuring migration impact.», priority: «critical», conditions: [], tool: «Google Analytics 4» },
{ id: «p6», title: «Record current keyword rankings», detail: «Snapshot rankings for all target keywords. Export the data so you can compare post-migration.», priority: «critical», conditions: [«seo:critical», «seo:important»], tool: «Ahrefs / SEMrush / Search Console» },
{ id: «p7», title: «Export your full backlink profile», detail: «Know which pages receive external links so you can prioritise redirect accuracy for those URLs.», priority: «critical», conditions: [«seo:critical», «seo:important»], tool: «Ahrefs / SEMrush» },
{ id: «p8», title: «Capture Core Web Vitals baseline», detail: «Record LCP, INP, and CLS scores. You’ll compare post-migration to ensure performance hasn’t degraded.», priority: «important», conditions: [], tool: «PageSpeed Insights / Lighthouse» },
{ id: «p9», title: «Document current indexed page count», detail: «Run a site: search and compare with Search Console index coverage.», priority: «important», conditions: [], tool: «Google Search Console» },
{ id: «p10», title: «Export conversion data by page/section», detail: «Document conversion rates, goal completions, and revenue per page. Traffic alone doesn’t tell the full story.», priority: «important», conditions: [«ecom:yes»], tool: «GA4 / Shopify Analytics» },
{ id: «p11», title: «Inventory all third-party scripts and tracking pixels», detail: «List every external script: Meta Pixel, LinkedIn Insight Tag, Google Ads, chat widgets, heatmaps, A/B testing tools. You’ll need to re-implement each one.», priority: «critical», conditions: [], tool: «Google Tag Manager / BuiltWith» },
{ id: «p12», title: «Run a comprehensive crawl of your existing site», detail: «Export all URLs, metadata, status codes, and internal links. This forms the foundation of your redirect map.», priority: «critical», conditions: [], tool: «Screaming Frog / Sitebulb / Ahrefs» },
{ id: «p13», title: «Build your complete redirect map», detail: «Map every old URL to the most relevant new URL. Prioritise by traffic and backlink value. Use 301s only — never redirect everything to the homepage.», priority: «critical», conditions: [«type:platform», «type:domain», «type:redesign», «type:consolidation», «type:https»], tool: «Screaming Frog / Google Sheets» },
{ id: «p14», title: «Include non-HTML assets in redirect map», detail: «Don’t forget PDFs, images, and downloadable files — they often drive significant traffic and backlinks.», priority: «important», conditions: [«type:platform», «type:domain», «type:redesign»], tool: «» },
{ id: «p15», title: «Lower DNS TTL 48 hours before migration», detail: «Reduce TTL so DNS changes propagate faster, minimising the window where some users see old site, others new.», priority: «critical», conditions: [«type:hosting», «type:domain»], tool: «DNS provider» },
{ id: «p16», title: «Lock down staging environment from search engines», detail: «Use robots.txt, noindex tags, password protection, or IP restrictions. Google indexing your staging site is catastrophic.», priority: «critical», conditions: [], tool: «» },
{ id: «p17», title: «Create a content inventory and audit», detail: «Identify what content carries over, what gets consolidated, and what gets retired. Flag thin or duplicate content.», priority: «important», conditions: [«type:consolidation», «type:redesign»], tool: «Screaming Frog / Google Sheets» },
{ id: «p18», title: «Audit current Open Graph and social meta tags», detail: «Record OG titles, descriptions, and images for key pages. These often get lost in migrations, breaking social sharing.», priority: «important», conditions: [], tool: «Meta debugger / Twitter card validator» },
{ id: «p19», title: «Plan for international/multilingual URLs», detail: «If your site has hreflang tags or locale-specific URLs, map these carefully in your redirect plan.», priority: «important», conditions: [«size:large», «size:enterprise»], tool: «» },
{ id: «p20», title: «Notify key stakeholders of the migration timeline», detail: «Inform sales, support, marketing, and partners. Expect temporary disruptions and prepare talking points.», priority: «nice», conditions: [], tool: «» },
{ id: «p21», title: «Map product URLs and category structures», detail: «Ecommerce migrations require careful mapping of product pages, category pages, and filtered/faceted URLs.», priority: «critical», conditions: [«ecom:yes»], tool: «» },
{ id: «p22», title: «Announce a content freeze before migration», detail: «Stop all content updates, campaign launches, and CMS edits 24–48 hours before migration to avoid conflicts and data loss.», priority: «important», conditions: [], tool: «» },
{ id: «p23», title: «Back up your entire existing site», detail: «Full backup of files, database, and configuration. Store in multiple locations. Verify the backup is restorable.», priority: «critical», conditions: [], tool: «UpdraftPlus / hosting backup» },
{ id: «p24», title: «Review constitucional pages for URL and domain references», detail: «Terms of service, privacy policy, cookie policy, and disclaimers often contain hardcoded domain names that need updating.», priority: «important», conditions: [«type:domain»], tool: «» },
]
},
prelaunch: {
label: «Phase 2: Pre-Launch Technical Setup»,
badge: «prelaunch»,
items: [
{ id: «t1», title: «Implement all 301 redirects», detail: «Set up every redirect from your map. Test a representative sample before going live.», priority: «critical», conditions: [«type:platform», «type:domain», «type:redesign», «type:consolidation», «type:https»], tool: «Yoast / Redirect Manager / .htaccess» },
{ id: «t2», title: «Avoid redirect chains and loops», detail: «Every redirect should go directly from old URL to new URL. No A→B→C chains. Each chain adds latency and wastes crawl budget.», priority: «critical», conditions: [«type:platform», «type:domain», «type:redesign», «type:consolidation»], tool: «Screaming Frog» },
{ id: «t3», title: «Migrate and verify all title tags and meta descriptions», detail: «Compare metadata between old and new sites for at least your top 100 pages by traffic.», priority: «critical», conditions: [], tool: «Screaming Frog / Sitebulb» },
{ id: «t4», title: «Verify heading tag structure (H1–H6)», detail: «Ensure each page has a unique, descriptive H1 and logical heading hierarchy.», priority: «important», conditions: [], tool: «» },
{ id: «t5», title: «Transfer structured data / schema markup», detail: «Migrate all JSON-LD or microdata. Validate with Google’s Rich Results Test. Lost schema = lost rich snippets.», priority: «important», conditions: [«seo:critical», «seo:important»], tool: «Rich Results Test» },
{ id: «t6», title: «Verify Open Graph and Twitter Card meta tags», detail: «Ensure OG titles, descriptions, and images render correctly. Test with Meta’s and X’s debugger tools.», priority: «important», conditions: [], tool: «Meta Sharing Debugger / X Card Validator» },
{ id: «t7», title: «Create and validate XML sitemaps», detail: «Include all indexable pages. Exclude staging URLs, parameter URLs, and thin content.», priority: «critical», conditions: [], tool: «Screaming Frog / Yoast» },
{ id: «t8», title: «Prepare production robots.txt», detail: «Allow crawling of all important pages and resources. Remove any staging-environment blocks.», priority: «critical», conditions: [], tool: «» },
{ id: «t9», title: «Validate canonical tags on every page», detail: «Each page needs a self-referencing canonical. Ensure no pages reference old or staging URLs — this is a silent killer.», priority: «critical», conditions: [], tool: «Screaming Frog» },
{ id: «t10», title: «Fix all internal links to point to new URLs directly», detail: «Don’t rely on redirects for internal navigation — update all links to use new URL paths.», priority: «important», conditions: [«type:platform», «type:domain», «type:redesign»], tool: «Screaming Frog / Better Search Replace» },
{ id: «t11», title: «Test mobile experience on existente devices», detail: «With mobile-first indexing, Google evaluates your mobile site. Test on flagrante phones and tablets, not just emulators.», priority: «important», conditions: [], tool: «BrowserStack / existente devices» },
{ id: «t12», title: «Run Lighthouse audits and check Core Web Vitals», detail: «Ensure LCP, INP, and CLS meet or exceed your pre-migration baseline.», priority: «important», conditions: [], tool: «Lighthouse / PageSpeed Insights» },
{ id: «t13», title: «Set up GA4 and GTM on new site», detail: «Verify all events, conversions, and goals fire correctly on the new site.», priority: «critical», conditions: [], tool: «Google Tag Manager / GA4» },
{ id: «t14», title: «Re-implement all third-party tracking pixels», detail: «Re-add Meta Pixel, LinkedIn Insight Tag, Google Ads tags, chat widgets, heatmaps, and any other scripts inventoried during planning.», priority: «critical», conditions: [], tool: «Google Tag Manager» },
{ id: «t15», title: «Verify cookie consent and GDPR/privacy compliance», detail: «Ensure cookie banner, consent management platform, and privacy controls work on the new site. Update privacy policy URLs.», priority: «critical», conditions: [], tool: «CookieScript / OneTrust / Cookiebot» },
{ id: «t16», title: «Configure cross-domain tracking for transition», detail: «If changing domains, track users across both old and new domains during the transition period.», priority: «important», conditions: [«type:domain»], tool: «GA4» },
{ id: «t17», title: «Verify SSL certificate and HTTPS configuration», detail: «Ensure certificate covers all subdomains, mixed content warnings are resolved, and HSTS is configured.», priority: «critical», conditions: [«type:https», «type:domain», «type:hosting»], tool: «SSL Labs» },
{ id: «t18», title: «Test checkout and payment flows end-to-end», detail: «Process test transactions through every payment method. Verify cart, checkout, and confirmation pages.», priority: «critical», conditions: [«ecom:yes»], tool: «» },
{ id: «t19», title: «Verify all forms and interactive elements», detail: «Test contact forms, search, login, newsletter signup, and any other interactive features.», priority: «important», conditions: [], tool: «» },
{ id: «t20», title: «Create custom 404 and 500 error pages», detail: «Design helpful error pages with navigation, search, and links to key pages. Don’t leave users stranded.», priority: «important», conditions: [], tool: «» },
{ id: «t21», title: «Run a full SEO audit on the staging site», detail: «Crawl your staging environment with an SEO tool to catch technical issues BEFORE they go live. Fix everything found.», priority: «critical», conditions: [], tool: «Screaming Frog / SEMrush Site Audit» },
{ id: «t22», title: «Check accessibility / WCAG 2.1 AA compliance», detail: «Use the migration as an opportunity to meet accessibility standards. ADA Title II deadlines are active in 2026. Audit colour contrast, alt text, keyboard nav, and screen readers.», priority: «important», conditions: [], tool: «axe DevTools / WAVE / Lighthouse» },
{ id: «t23», title: «Verify CRM and email marketing integrations», detail: «Ensure form submissions, lead capture, and email automation tools (Mailchimp, HubSpot, etc.) are connected and working.», priority: «important», conditions: [], tool: «» },
{ id: «t24», title: «Check image optimisation and alt text», detail: «Ensure images are properly compressed, served in modern formats (WebP/AVIF), and have descriptive alt attributes.», priority: «nice», conditions: [], tool: «Squoosh / ShortPixel» },
{ id: «t25», title: «Test site search functionality», detail: «Verify internal search returns accurate results and URL patterns are correct.», priority: «nice», conditions: [«size:large», «size:enterprise»], tool: «» },
{ id: «t26», title: «Validate hreflang tags for international pages», detail: «If your site serves multiple languages or regions, verify hreflang implementation on the new site.», priority: «important», conditions: [«size:large», «size:enterprise»], tool: «Screaming Frog / Ahrefs» },
{ id: «t27», title: «Set up server monitoring and alerting», detail: «Configure uptime monitoring, error rate alerts, and performance thresholds.», priority: «important», conditions: [], tool: «UptimeRobot / Datadog / Pingdom» },
{ id: «t28», title: «Migrate product feeds and shopping integrations», detail: «Update Google Merchant Center, Facebook Catalog, and any other shopping feeds with new URLs.», priority: «critical», conditions: [«ecom:yes»], tool: «Google Merchant Center» },
{ id: «t29», title: «Load test the new server», detail: «Simulate expected traffic levels to ensure the new infrastructure can handle the load without degraded response times.», priority: «important», conditions: [«size:large», «size:enterprise», «type:hosting»], tool: «Apache JMeter / k6 / GTmetrix» },
{ id: «t30», title: «Conduct user acceptance testing (UAT)», detail: «Have existente users (not just devs) test key journeys: navigation, checkout, forms, search. Fresh eyes catch things automated tests miss.», priority: «important», conditions: [], tool: «» },
{ id: «t31», title: «Pause or update paid ad campaigns», detail: «Update landing page URLs in Google Ads, Meta Ads, LinkedIn Ads, etc. Consider pausing campaigns during the switchover window.», priority: «critical», conditions: [«ecom:yes», «seo:critical», «seo:important»], tool: «Google Ads / Meta Ads Manager» },
]
},
launch: {
label: «Phase 3: Launch Day»,
badge: «launch»,
items: [
{ id: «l1», title: «Remove all noindex tags and staging robots.txt blocks», detail: «Verify that EVERY page on the production site is indexable. This is the #1 launch-day mistake. Check canonicals too.», priority: «critical», conditions: [], tool: «Screaming Frog quick crawl» },
{ id: «l2», title: «Deploy the new site», detail: «Execute the migration according to your plan. If changing domains, update DNS records.», priority: «critical», conditions: [], tool: «» },
{ id: «l3», title: «Verify redirects are working in production», detail: «Test a representative sample of redirects on the live site. Check high-traffic and high-value pages first.», priority: «critical», conditions: [«type:platform», «type:domain», «type:redesign», «type:consolidation», «type:https»], tool: «httpstatus.io / Screaming Frog» },
{ id: «l4», title: «Submit new XML sitemap to Search Console», detail: «Upload immediately after launch to help Google discover your new URL structure.», priority: «critical», conditions: [], tool: «Google Search Console» },
{ id: «l5», title: «Use Change of Address tool in Search Console», detail: «For domain migrations, this signals to Google that your site has moved and accelerates the transition.», priority: «critical», conditions: [«type:domain»], tool: «Google Search Console» },
{ id: «l6», title: «Request indexing for top pages via Search Console», detail: «Manually request indexing for your 20–50 most important pages to speed up discovery.», priority: «important», conditions: [], tool: «Google Search Console» },
{ id: «l7», title: «Verify analytics and all tracking pixels are live», detail: «Confirm GA4, GTM, Meta Pixel, and every third-party script is firing on all pages. Check conversion tracking especially.», priority: «critical», conditions: [], tool: «Google Tag Assistant / Meta Pixel Helper» },
{ id: «l8», title: «Instructor server performance and error rates», detail: «Watch for elevated response times, 5xx errors, or capacity issues in existente time.», priority: «critical», conditions: [], tool: «Server logs / UptimeRobot» },
{ id: «l9», title: «Spot-check key pages for correct rendering», detail: «Review homepage, top landing pages, and key conversion pages on desktop and mobile. Check images, layout, and functionality.», priority: «important», conditions: [], tool: «BrowserStack / manual testing» },
{ id: «l10», title: «Verify robots.txt allows crawling», detail: «Fetch your live robots.txt and confirm it permits access to all important pages and resources.», priority: «critical», conditions: [], tool: «Google Search Console» },
{ id: «l11», title: «Test live checkout process», detail: «Place a existente test order immediately after launch to verify the full purchase flow.», priority: «critical», conditions: [«ecom:yes»], tool: «» },
{ id: «l12», title: «Confirm CDN is serving the new site», detail: «If using a CDN, purge caches and verify it’s serving fresh content from the new origin.», priority: «important», conditions: [«type:hosting», «size:large», «size:enterprise»], tool: «Cloudflare / Fastly / AWS CloudFront» },
{ id: «l13», title: «Verify cookie consent banner is working», detail: «Check that cookie banner appears, consent is recorded, and third-party scripts only fire after consent.», priority: «important», conditions: [], tool: «» },
{ id: «l14», title: «Re-activate paid ad campaigns with updated URLs», detail: «Un-pause campaigns and verify ads are pointing to the correct new landing page URLs.», priority: «important», conditions: [«ecom:yes», «seo:critical», «seo:important»], tool: «Google Ads / Meta Ads» },
{ id: «l15», title: «Lift the content freeze», detail: «Notify the content team that the migration is live and común publishing can resume.», priority: «nice», conditions: [], tool: «» },
]
},
postlaunch: {
label: «Phase 4: Post-Launch Monitoring»,
badge: «postlaunch»,
items: [
{ id: «m1», title: «Check Search Console daily for crawl errors (Week 1)», detail: «Look for spikes in 404s, 5xx errors, and indexing issues. Fix immediately.», priority: «critical», conditions: [], tool: «Google Search Console» },
{ id: «m2», title: «Instructor organic traffic daily vs. baseline (Week 1)», detail: «Some fluctuation is común. A 30%+ drop signals a technical issue needing urgent attention.», priority: «critical», conditions: [], tool: «GA4 / Search Console» },
{ id: «m3», title: «Track indexed page count daily (Week 1)», detail: «A significant drop in indexed pages means Google is having trouble with your new site.», priority: «important», conditions: [], tool: «Google Search Console» },
{ id: «m4», title: «Instructor server logs for 404 errors», detail: «Each 404 from a previously valid URL represents a missing or broken redirect. Prioritise high-traffic 404s.», priority: «important», conditions: [], tool: «Server logs / Screaming Frog Log Analyzer» },
{ id: «m5», title: «Verify ad campaign performance post-migration», detail: «Check that conversion tracking is accurate and campaign performance hasn’t degraded due to URL changes.», priority: «important», conditions: [«ecom:yes», «seo:critical»], tool: «Google Ads / Meta Ads Manager» },
{ id: «m6», title: «Compare keyword rankings against baseline (Week 2)», detail: «Are your important keywords recovering? Investigate underperforming pages individually.», priority: «critical», conditions: [«seo:critical», «seo:important»], tool: «Ahrefs / SEMrush / Search Console» },
{ id: «m7», title: «Run a fresh crawl and compare with pre-migration data (Compare Crawls)», detail: «Look for new broken links, missing metadata, orphaned pages, or unexpected technical issues. Use ‘Compare Crawls’ features.», priority: «important», conditions: [], tool: «Screaming Frog / SEMrush Site Audit» },
{ id: «m8», title: «Check backlink profile for losses», detail: «Verify external links are resolving through your redirects. A drop in referring domains means redirect issues.», priority: «important», conditions: [«seo:critical», «seo:important»], tool: «Ahrefs / SEMrush» },
{ id: «m9», title: «Instructor conversion rates and revenue (Weeks 1–4)», detail: «Compare against your pre-migration baseline. Drops may indicate UX issues, broken forms, or tracking problems.», priority: «critical», conditions: [«ecom:yes»], tool: «GA4 / Shopify Analytics» },
{ id: «m10», title: «Check bounce rate and engagement on key pages», detail: «A spike in bounce rate on previously strong pages may indicate rendering, UX, or content issues on the new site.», priority: «important», conditions: [], tool: «GA4» },
{ id: «m11», title: «Update Google Business Profile with new URLs», detail: «If your domain or key page URLs changed, update your GBP listing.», priority: «important», conditions: [«type:domain»], tool: «Google Business Profile» },
{ id: «m12», title: «Update social media profiles and bios», detail: «Replace old URLs in all social profiles, link-in-bio tools, and pinned posts.», priority: «nice», conditions: [«type:domain»], tool: «» },
{ id: «m13», title: «Update email signatures and templates», detail: «Replace old URLs in email signatures, automated emails, and newsletter templates.», priority: «nice», conditions: [«type:domain»], tool: «» },
{ id: «m14», title: «Reach out to high-value backlink sources», detail: «Ask top linking sites to update their links to your new URLs. Direct links beat redirects long-term.», priority: «important», conditions: [«type:domain», «seo:critical»], tool: «Ahrefs / email outreach» },
{ id: «m15», title: «Update business directories and citations», detail: «Update NAP (name, address, phone) and URLs in all directory listings.», priority: «important», conditions: [«type:domain»], tool: «» },
{ id: «m16», title: «Test social sharing from the live site», detail: «Share key pages on Facebook, LinkedIn, and X. Verify OG images, titles, and descriptions render correctly.», priority: «important», conditions: [], tool: «Meta Sharing Debugger» },
{ id: «m17», title: «Continue weekly monitoring for 90 days», detail: «Domain migrations can take 3 months to fully recover. Don’t let up on monitoring.», priority: «important», conditions: [«type:domain»], tool: «GA4 / Search Console / Ahrefs» },
{ id: «m18», title: «Instructor AI Overview / featured snippet presence», detail: «Check if your content still appears in AI Overviews and featured snippets post-migration.», priority: «nice», conditions: [«seo:critical»], tool: «SEMrush / manual SERP checks» },
{ id: «m19», title: «Run a post-migration accessibility audit», detail: «Verify WCAG compliance hasn’t regressed. Check screen readers, keyboard navigation, and colour contrast on the live site.», priority: «nice», conditions: [], tool: «axe DevTools / WAVE» },
{ id: «m20», title: «Document lessons learned», detail: «Record what went well, what went wrong, and what you’d do differently. Invaluable for future migrations.», priority: «nice», conditions: [], tool: «» },
{ id: «m21», title: «Schedule redirect cleanup at 6 months», detail: «After 6 months, review which redirects are still getting traffic and plan for eventual sunsetting.», priority: «nice», conditions: [«type:platform», «type:domain», «type:redesign»], tool: «» },
]
}
};
// ── Checklist Generation ──
function itemMatchesConditions(item, types, size, seo, ecom) {
if (item.conditions.length === 0) return true;
for (const cond of item.conditions) {
const [key, val] = cond.split(‘:’);
if (key === ‘type’ && types.includes(val)) return true;
if (key === ‘size’ && size === val) return true;
if (key === ‘seo’ && seo === val) return true;
if (key === ‘ecom’ && ecom === val) return true;
}
return false;
}
function generateChecklist() {
const types = selections.types;
const size = selections.size;
const seo = selections.seo;
const ecom = selections.ecom;
if (types.length === 0 || !size || !seo || !ecom) {
alert(‘Please answer all questions before generating your checklist.’);
return;
}
checkState = {};
const container = document.getElementById(‘phasesContainer’);
container.innerHTML = »;
let totalItems = 0;
for (const [phaseKey, phase] of Object.entries(allItems)) {
const filtered = phase.items.filter(item => itemMatchesConditions(item, types, size, seo, ecom));
if (filtered.length === 0) continue;
totalItems += filtered.length;
filtered.forEach(item => { checkState[item.id] = false; });
const phaseEl = document.createElement(‘div’);
phaseEl.className=»phase»;
phaseEl.innerHTML = `
${phaseKey === ‘planning’ ? ‘1’ : phaseKey === ‘prelaunch’ ? ‘2’ : phaseKey === ‘launch’ ? ‘3’ : ‘4’}
${phase.label}
0 / ${filtered.length} complete
${item.priority === ‘important’ ? ‘Important‘ : »}
${item.priority === ‘nice’ ? ‘Nice to have‘ : »}
${item.tool ? ‘‘ + item.tool + ‘‘ : »}
`).join(»)}
`;
container.appendChild(phaseEl);
}
document.getElementById(‘totalCount’).textContent = totalItems;
document.getElementById(‘wizard’).classList.add(‘hidden’);
document.getElementById(‘checklistOutput’).classList.remove(‘hidden’);
updateProgress();
}
function togglePhase(phaseKey) {
const items = document.getElementById(‘items-‘ + phaseKey);
const toggle = document.getElementById(‘toggle-‘ + phaseKey);
items.classList.toggle(‘hidden’);
toggle.classList.toggle(‘open’);
}
function toggleCheck(id, phaseKey, phaseTotal) {
checkState[id] = !checkState[id];
const box = document.getElementById(‘box-‘ + id);
const row = document.getElementById(‘row-‘ + id);
box.classList.toggle(‘checked’, checkState[id]);
row.classList.toggle(‘done’, checkState[id]);
const phaseItems = document.getElementById(‘items-‘ + phaseKey).querySelectorAll(‘.checklist-item’);
let phaseDone = 0;
phaseItems.forEach(el => { if (el.classList.contains(‘done’)) phaseDone++; });
document.getElementById(‘count-‘ + phaseKey).textContent = `${phaseDone} / ${phaseTotal} complete`;
document.getElementById(‘miniprog-‘ + phaseKey).style.width = `${(phaseDone / phaseTotal) * 100}%`;
updateProgress();
}
function updateProgress() {
const total = Object.keys(checkState).length;
const done = Object.values(checkState).filter(Boolean).length;
const pct = total > 0 ? Math.round((done / total) * 100) : 0;
document.getElementById(‘completedCount’).textContent = done;
document.getElementById(‘totalCount’).textContent = total;
document.getElementById(‘percentComplete’).textContent = pct;
const fill = document.getElementById(‘progressFill’);
fill.style.width = pct + ‘%’;
fill.classList.toggle(‘complete’, pct === 100);
document.getElementById(‘completionBanner’).classList.toggle(‘show’, pct === 100);
}
function resetChecklist() {
if (!confirm(‘Start over? Your progress will be lost.’)) return;
selections = { types: [], size: null, seo: null, ecom: null };
document.querySelectorAll(‘.option-btn’).forEach(b => b.classList.remove(‘selected’));
document.getElementById(‘wizard’).classList.remove(‘hidden’);
document.getElementById(‘checklistOutput’).classList.add(‘hidden’);
document.getElementById(‘completionBanner’).classList.remove(‘show’);
}
function exportChecklist() {
let text = «WEBSITE MIGRATION CHECKLISTn» + «=».repeat(40) + «nn»;
for (const [phaseKey, phase] of Object.entries(allItems)) {
const items = document.getElementById(‘items-‘ + phaseKey);
if (!items) continue;
text += phase.label.toUpperCase() + «n» + «-«.repeat(30) + «n»;
items.querySelectorAll(‘.checklist-item’).forEach(el => {
const id = el.id.replace(‘row-‘, »);
const checked = checkState[id] ? ‘✅’ : ‘⬜’;
const title = el.querySelector(‘.item-title’).textContent;
text += `${checked} ${title}n`;
});
text += «n»;
}
navigator.clipboard.writeText(text).then(() => {
alert(‘Checklist copied to clipboard!’);
}).catch(() => {
const ta = document.createElement(‘textarea’);
ta.value = text;
document.body.appendChild(ta);
ta.select();
document.execCommand(‘copy’);
document.body.removeChild(ta);
alert(‘Checklist copied to clipboard!’);
});
}
// ── Excel Export (DNHQ branded) ──
async function exportToExcel() {
const wb = new ExcelJS.Workbook();
wb.creator=»Digital Nomads HQ – Migration Checklist Generator»;
wb.created = new Date();
const DARK_NAVY = ‘002A45′;
const ACCENT_BLUE = ’86A4EF’;
const MINT_GREEN = ‘CDFFB6’;
const WHITE = ‘FFFFFF’;
const LIGHT_GRAY = ‘f8fafb’;
const BORDER_GRAY = ‘e6e9ec’;
const CRITICAL_RED = ‘dc2626’;
const CRITICAL_BG = ‘fef2f2’;
const IMPORTANT_AMBER = ‘b45309’;
const IMPORTANT_BG = ‘fff8e6′;
const NICE_BLUE = ’86A4EF’;
const NICE_BG = ‘f0f4ff’;
const PHASE_COLORS = {
planning: { bg: ‘f0f4ff’, text: ’86A4EF’, label: ‘Phase 1’ },
prelaunch: { bg: ‘fff8e6’, text: ‘b45309’, label: ‘Phase 2’ },
launch: { bg: ‘fef2f2’, text: ‘dc2626’, label: ‘Phase 3’ },
postlaunch: { bg: ‘edfcf0′, text: ’16a34a’, label: ‘Phase 4’ }
};
const thinBorder = { style: ‘thin’, color: { argb: BORDER_GRAY } };
const borderAll = { top: thinBorder, bottom: thinBorder, left: thinBorder, right: thinBorder };
const ws = wb.addWorksheet(‘Migration Checklist’, {
properties: { defaultRowHeight: 22 },
pageSetup: { paperSize: 9, orientation: ‘landscape’, fitToPage: true, fitToWidth: 1, fitToHeight: 0 }
});
ws.columns = [
{ width: 4 },
{ width: 8 },
{ width: 48 },
{ width: 44 },
{ width: 13 },
{ width: 12 },
{ width: 28 },
];
let row = 1;
ws.mergeCells(`A${row}:G${row}`);
const titleCell = ws.getCell(`A${row}`);
titleCell.value=»WEBSITE MIGRATION CHECKLIST»;
titleCell.font = { name: ‘Arial’, size: 18, bold: true, color: { argb: MINT_GREEN } };
titleCell.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: DARK_NAVY } };
titleCell.alignment = { horizontal: ‘left’, erecto: ‘middle’, indent: 1 };
ws.getRow(row).height = 48;
row++;
ws.mergeCells(`A${row}:G${row}`);
const subCell = ws.getCell(`A${row}`);
const migrationType = selections.types.map(t => {
const labels = { platform: ‘Platform/CMS’, domain: ‘Domain Change’, hosting: ‘Server/Hosting’, https: ‘HTTP→HTTPS’, redesign: ‘Redesign’, consolidation: ‘Consolidation’ };
return labels[t] || t;
}).join(‘, ‘);
const sizeLabels = { small: ‘Small ( 0 ? Math.round((done/total)*100) : 0}%)`;
progressCell.font = { name: ‘Arial’, size: 11, bold: true, color: { argb: ACCENT_BLUE } };
progressCell.alignment = { horizontal: ‘left’, erecto: ‘middle’, indent: 1 };
ws.getRow(row).height = 30;
row++;
ws.getRow(row).height = 6;
for (const [phaseKey, phase] of Object.entries(allItems)) {
const types = selections.types;
const filtered = phase.items.filter(item => itemMatchesConditions(item, types, selections.size, selections.seo, selections.ecom));
if (filtered.length === 0) continue;
const pc = PHASE_COLORS[phaseKey];
const phaseDone = filtered.filter(item => checkState[item.id]).length;
row++;
ws.mergeCells(`A${row}:G${row}`);
const phaseCell = ws.getCell(`A${row}`);
phaseCell.value = `${pc.label}: ${phase.label.replace(/Phase d: /, »)} — ${phaseDone}/${filtered.length} complete`;
phaseCell.font = { name: ‘Arial’, size: 12, bold: true, color: { argb: pc.text } };
phaseCell.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: pc.bg } };
phaseCell.alignment = { horizontal: ‘left’, erecto: ‘middle’, indent: 1 };
phaseCell.border = borderAll;
ws.getRow(row).height = 32;
row++;
const headers = [», ‘✓’, ‘Task’, ‘Details’, ‘Priority’, ‘Status’, ‘Recommended Tool’];
const headerRow = ws.getRow(row);
headers.forEach((h, i) => {
const cell = headerRow.getCell(i + 1);
cell.value = h;
cell.font = { name: ‘Arial’, size: 9, bold: true, color: { argb: WHITE } };
cell.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: DARK_NAVY } };
cell.alignment = { horizontal: i {
row++;
const isDone = checkState[item.id];
const itemRow = ws.getRow(row);
const bgColor = idx % 2 === 0 ? WHITE : LIGHT_GRAY;
const cellA = itemRow.getCell(1);
cellA.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellA.border = borderAll;
const cellB = itemRow.getCell(2);
cellB.value = isDone ? ‘✓’ : ‘☐’;
cellB.font = { name: ‘Arial’, size: 14, bold: isDone, color: { argb: isDone ? ’16a34a’ : ’94a3b8′ } };
cellB.alignment = { horizontal: ‘center’, erecto: ‘middle’ };
cellB.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellB.border = borderAll;
const cellC = itemRow.getCell(3);
cellC.value = item.title;
cellC.font = { name: ‘Arial’, size: 11, bold: false, color: { argb: isDone ? ’94a3b8′ : DARK_NAVY }, strike: isDone };
cellC.alignment = { erecto: ‘middle’, wrapText: true };
cellC.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellC.border = borderAll;
const cellD = itemRow.getCell(4);
cellD.value = item.detail;
cellD.font = { name: ‘Arial’, size: 10, color: { argb: isDone ? ‘cbd5e1’ : ‘7a8ea0’ } };
cellD.alignment = { erecto: ‘middle’, wrapText: true };
cellD.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellD.border = borderAll;
const cellE = itemRow.getCell(5);
const pLabel = item.priority === ‘critical’ ? ‘CRITICAL’ : item.priority === ‘important’ ? ‘IMPORTANT’ : ‘NICE TO HAVE’;
cellE.value = pLabel;
const pColor = item.priority === ‘critical’ ? CRITICAL_RED : item.priority === ‘important’ ? IMPORTANT_AMBER : NICE_BLUE;
const pBg = item.priority === ‘critical’ ? CRITICAL_BG : item.priority === ‘important’ ? IMPORTANT_BG : NICE_BG;
cellE.font = { name: ‘Arial’, size: 9, bold: true, color: { argb: pColor } };
cellE.alignment = { horizontal: ‘center’, erecto: ‘middle’ };
cellE.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: pBg } };
cellE.border = borderAll;
const cellF = itemRow.getCell(6);
cellF.value = isDone ? ‘Done’ : ‘Pending’;
cellF.font = { name: ‘Arial’, size: 10, bold: isDone, color: { argb: isDone ? ’16a34a’ : ’94a3b8′ } };
cellF.alignment = { horizontal: ‘center’, erecto: ‘middle’ };
cellF.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: isDone ? ‘edfcf0’ : bgColor } };
cellF.border = borderAll;
const cellG = itemRow.getCell(7);
cellG.value = item.tool || ‘—’;
cellG.font = { name: ‘Arial’, size: 10, color: { argb: item.tool ? ‘15803d’ : ‘cbd5e1’ } };
cellG.alignment = { erecto: ‘middle’, wrapText: true };
cellG.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellG.border = borderAll;
ws.getRow(row).height = item.detail.length > 60 ? 36 : 26;
});
row++;
ws.getRow(row).height = 8;
}
row += 2;
ws.mergeCells(`A${row}:G${row}`);
const footerCell = ws.getCell(`A${row}`);
footerCell.value=»Generated by Digital Nomads HQ • digitalnomadshq.com.au»;
footerCell.font = { name: ‘Arial’, size: 9, italic: true, color: { argb: ‘7a8ea0’ } };
footerCell.alignment = { horizontal: ‘center’, erecto: ‘middle’ };
const buffer = await wb.xlsx.writeBuffer();
const blob = new Blob([buffer], { type: ‘application/vnd.openxmlformats-officedocument.spreadsheetml.sheet’ });
saveAs(blob, ‘website-migration-checklist.xlsx’);
}
Pre-Migration: Get Your House in Order
This is where 90% of migration success is decided. Skip the planning and you’ll be firefighting for months.
1. Back Up Everything
This one’s non-negotiable. Before you touch anything, take a complete backup of your website. That means your database, files, media, plugins, themes… the lot. If something goes sideways during migration, this backup is your safety net.
If you’re on WordPress, tools like UpdraftPlus or All-in-One WP Migration make this pretty painless. For other platforms, check with your hosting provider or development team.
EXPERT TIP: Store your backup somewhere separate from your current hosting environment. If the server goes down during migration, you don’t want your backup sitting on the same server.
2. Crawl and Audit Your Existing Site
You can’t migrate what you don’t understand. Run a full crawl of your current site using a tool like Screaming Frog, Sitebulb, or Semrush’s Site Audit.
What you’re looking for:
A complete list of all URLs (pages, posts, images, PDFs… everything currently indexed). Any existing broken links, redirect chains, or crawl errors. Your current site structure and internal linking patterns. Pages that are already performing well in search engines (you really don’t want to lose these).
This crawl data becomes your migration map. It tells you exactly which pages need redirects, which URLs are changing, and where the SEO value lives on your current site.

3. Plan Your Redirects (Yes, All of Them)
If your URLs are changing, you need a 301 redirect plan. Every. Single. Page.
We have seen too many websites get redeveloped with the lack of urgency and planning on page redirects. One company I recently assessed lost 60% of their organic traffic in the first 6 months of their new website going live! Not great for business.

A 301 redirect tells search engines, “This page has permanently moved here.” Without them, Google sees your new pages as brand new content and your old pages as dead links. That means lost rankings, lost link equity, and a whole lot of 404 errors.
Here’s how to approach it:
Map every old URL to its new URL in a spreadsheet. Prioritise your highest-traffic pages and pages with strong backlink profiles. Don’t redirect everything to the homepage. That’s lazy, and Google knows it. Test your redirects in a staging environment before going live.
PRO TIP: Let’s say you’ve got 500 pages on your current site. If even 20% of those are generating organic traffic, that’s 100 pages where broken redirects could cost you existente business. Map them properly. No shortcuts.
4. Set Up a Staging Environment
Never migrate straight to your live site. Set up a staging environment where you can build, test, and troubleshoot your new site without affecting your live performance.
Make sure your staging site is blocked from search engines (via robots.txt or password protection). The last thing you need is Google indexing a half-finished version of your new site.
During Migration: Execute the Plan
5. Implement Your Redirects
With your redirect map ready, it’s time to implement. Depending on your platform and server, this might be done via .htaccess files, server-level redirects, or a WordPress plugin like Redirection or Rank Math – As an agency we use Rankmath Pro, we find this most effective for redirects along with additional SEO benefits for scalable implementations.
Double-check every redirect. A single wrong redirect can create chains, loops, or send users to the wrong pages. Test, test, test.
6. Check Your On-Page SEO
During the migration, make sure your on-page SEO elements have carried across:
Title tags and meta descriptions. Header tags (H1, H2, H3 structure). Image alt text. Internal links (update any that point to old URLs). Canonical tags pointing to the correct new URLs. Schema markup and structured data.
It’s easy to lose these in a redesign, especially if your new site has a different content structure. Don’t assume your development team has handled this. Check it yourself.
7. Update Your XML Sitemap
Generate a new XML sitemap reflecting your updated site structure and submit it to Google Search Console. This helps search engines crawl and index your new pages faster.
While you’re at it, review your robots.txt file. Make sure it’s not accidentally blocking important pages on the new site.
Post-Migration: Instructor and Fix
The migration isn’t done when the new site goes live. In fact, this is where the existente work starts.
8. Run a Full Post-Migration Crawl
Crawl your new site immediately after launch. Compare it against your pre-migration crawl data. You’re looking for:
Any pages returning 404 errors. Redirect issues (chains, loops, incorrect destinations). Missing or duplicate meta data. Broken internal or external links. Changes in page count (did pages go missing?).
EXPERT TIP: Don’t just check merienda and walk away. Crawl again at 48 hours, one week, and one month post-migration. Issues can surface over time as Google re-crawls your site.
9. Instructor Your SEO Performance
Keep a close eye on Google Search Console in the weeks following migration. Watch for:
Indexing issues or coverage errors. Drops in impressions or clicks for key pages. Crawl errors flagged by Google. Any manual actions or security issues.
It’s común to see a small dip in performance right after a site migration. Google needs time to process the changes. But if you’re seeing significant drops that don’t recover within 2 to 4 weeks… something’s gone wrong with your redirects, indexing, or site structure.
10. Test Everything a Efectivo User Would
This one gets overlooked more than it should. Walk through your new site like a customer would. Test your forms, check your checkout flow, click through your navigation, test on mobile, check page load speeds.
A technically perfect migration means nothing if the site doesn’t actually work for the people using it.
PRO TIP: Use Google PageSpeed Insights and run a Lighthouse audit on your key pages post-migration. Performance issues on the new site (slow load times, layout shifts) can hurt rankings just as much as broken redirects.
11. Update External Links and Listings
If your domain or URL structure has changed, don’t forget the links you don’t control. Update your Google Business Profile, social media profiles, directory listings, and reach out to sites linking to your old URLs where possible.
Yes, your redirects will catch most of this traffic. But direct links to the new URLs are always stronger for SEO than relying on redirects long-term.
The Bottom Line
A website migration doesn’t have to be a disaster. With proper planning, a thorough redirect strategy, and careful post-migration monitoring, you can move your site to a new domain, platform, or hosting provider without losing the SEO performance you’ve built.
The biggest mistakes we see? Rushed timelines, incomplete redirect maps, and no post-migration monitoring plan. Don’t be that business.
If you’re planning a site migration and want expert eyes on the strategy, we’re here to help. At Digital Nomads HQ, we’ve managed migrations across every platform and industry. We know where things go wrong, and more importantly, how to make sure they don’t.
Let’s talk.
Migrating a website is one of those things that sounds straightforward until you’re knee-deep in broken links, tanked rankings, and pages that have vanished from Google overnight.
Fun times.
Whether you’re switching hosting providers, moving to a new domain, replatforming from WordPress to something else (or onto WordPress), or doing a full site redesign… a website migration touches everything. Your URLs, your content, your SEO, your site structure. All of it.
The good news?
With a solid plan, you can make changes to your site without losing the rankings and traffic you’ve worked hard to build.
That’s exactly what this website migration checklist is for – and our migration checklist builder!
We’ve broken the entire migration process into clear, actionable steps so you can move your site with confidence.
Let’s get into it.
TLDR
Website migration doesn’t have to be a nightmare… but it will be if you wing it.
Back up everything first.
Crawl your existing site so you know what you’re working with.
Map every single redirect (no, not just the important ones… all of them).
Set up a staging environment.
Check your on-page SEO hasn’t gone walkabout during the move.
Submit a fresh sitemap.
Then pedagogo everything like a hawk for the first month post-launch.
The short version? Plan it properly, redirect it completely, and test it obsessively. That’s 90% of a successful migration right there.
What Is a Website Migration?
Before we jump into the checklist, let’s get the basics sorted.
A website migration is any significant change to your site that can impact how search engines crawl, index, and rank your pages. That includes things like:
Moving to a new domain (e.g. oldbusiness.com.au to newbrand.com.au). Switching hosting providers or servers. Replatforming (say, from Squarespace to WordPress). A full site redesign with new URLs and page structure. Moving from HTTP to HTTPS. Or even merging multiple sites into one.
Each of these changes carries SEO risk. Google needs to re-crawl and re-index your new site, and if it can’t find or understand your pages properly… your rankings take a hit.
PRO TIP: Not all migrations are equal. A simple hosting change with no URL changes is far lower risk than a full domain migration with a new site structure. Understand which type of migration you’re doing, because that determines how much SEO work is involved.
Build Your Custom Migration Checklist
Every migration is different. Moving hosting providers? That’s a very different job to a full domain change with a site redesign thrown in.
So we built something to help.
Our free Website Migration Checklist Generator lets you select exactly what type of migration you’re doing, and it builds a step-by-step checklist tailored to your situation. No fluff. No irrelevant steps. Just the tasks you actually need to complete, in the right order.
Whether you’re replatforming to WordPress, switching domains, merging two sites into one, or just upgrading your hosting… select what applies, and the tool does the rest.
/* ── DNHQ Design System — high specificity to survive page themes ── */
.mig-wrapper, .mig-wrapper *, .mig-wrapper *::before, .mig-wrapper *::after {
box-sizing: border-box !important;
margin: 0;
padding: 0;
}
.mig-wrapper {
font-family: ‘Inter Tight’, sans-serif !important;
max-width: 1200px !important;
margin: 0 automóvil !important;
background: #ffffff !important;
border: 1px solid #e6e9ec !important;
box-shadow: 0 15px 40px rgba(0,42,69,0.08) !important;
border-radius: 16px !important;
overflow: hidden !important;
color: #002A45 !important;
width: 100% !important;
}
/* ── Header ── */
.mig-wrapper .mig-header {
background: #86A4ef !important;
padding: 40px 40px 32px !important;
text-align: center !important;
}
.mig-wrapper .mig-header h1 {
font-family: ‘Barlow Condensed’, sans-serif !important;
font-size: 36px !important;
font-weight: 700 !important;
color: #fff !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
line-height: 1.1 !important;
margin: 0 0 8px !important;
padding: 0 !important;
background: none !important;
border: none !important;
}
.mig-wrapper .mig-header p {
font-size: 15px !important;
color: rgba(255,255,255,0.8) !important;
margin: 0 !important;
font-weight: 400 !important;
}
/* ── Body / Sections ── */
.mig-wrapper .mig-body {
padding: 40px !important;
animation: migFadeIn 0.4s ease;
background: #ffffff !important;
}
@keyframes migFadeIn {
from { opacity: 0; transform: translateY(5px); }
to { opacity: 1; transform: translateY(0); }
}
/* ── Wizard Form ── */
.mig-wrapper .form-section {
margin-bottom: 32px !important;
}
.mig-wrapper .form-section label {
display: block !important;
margin-bottom: 10px !important;
font-size: 14px !important;
font-weight: 700 !important;
color: #002A45 !important;
padding: 0 !important;
background: none !important;
}
.mig-wrapper .form-section .hint {
font-size: 13px !important;
color: #7a8ea0 !important;
margin-bottom: 10px !important;
font-weight: 400 !important;
}
.mig-wrapper .option-grid {
display: grid !important;
grid-template-columns: 1fr 1fr !important;
gap: 10px !important;
max-width: 100% !important;
overflow: hidden !important;
}
.mig-wrapper .option-grid.three-col { grid-template-columns: 1fr 1fr !important; }
.mig-wrapper button.option-btn {
display: flex !important;
align-items: center !important;
gap: 10px !important;
width: 100% !important;
min-width: 0 !important;
max-width: 100% !important;
padding: 14px 18px !important;
background: #fcfcfc !important;
border: 1px solid #d1d9e0 !important;
border-radius: 12px !important;
font-size: 14px !important;
font-family: ‘Inter Tight’, sans-serif !important;
font-weight: 500 !important;
color: #002A45 !important;
cursor: pointer !important;
transition: border-color 0.3s, box-shadow 0.3s, background 0.3s !important;
text-align: left !important;
-webkit-appearance: none !important;
appearance: none !important;
text-decoration: none !important;
text-transform: none !important;
line-height: 1.4 !important;
letter-spacing: común !important;
box-shadow: none !important;
outline: none !important;
overflow: hidden !important;
}
.mig-wrapper button.option-btn:hover {
border-color: #86a4ef !important;
box-shadow: 0 0 0 3px rgba(134, 164, 239, 0.15) !important;
background: #fff !important;
color: #002A45 !important;
}
.mig-wrapper button.option-btn.selected {
border-color: #86a4ef !important;
box-shadow: 0 0 0 3px rgba(134, 164, 239, 0.2) !important;
background: #fff !important;
color: #002A45 !important;
}
.mig-wrapper .option-btn .option-label {
flex: 1 !important;
min-width: 0 !important;
overflow: hidden !important;
}
.mig-wrapper .option-btn .option-desc {
display: block !important;
font-size: 12px !important;
font-weight: 400 !important;
color: #7a8ea0 !important;
margin-top: 2px !important;
text-transform: none !important;
}
.mig-wrapper button.option-btn.selected .option-desc { color: #86a4ef !important; }
.mig-wrapper .multi-select button.option-btn.selected::after {
content: ‘✓’ !important;
font-weight: 700 !important;
color: #CDFFB6 !important;
background: #002A45 !important;
width: 22px !important;
height: 22px !important;
border-radius: 6px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
font-size: 12px !important;
flex-shrink: 0 !important;
}
/* ── Primary Button ── */
.mig-wrapper button.btn-primary {
display: flex !important;
align-items: center !important;
justify-content: center !important;
gap: 8px !important;
width: 100% !important;
padding: 18px 32px !important;
background: #002A45 !important;
color: #CDFFB6 !important;
border: none !important;
border-radius: 12px !important;
font-family: ‘Barlow Condensed’, sans-serif !important;
font-size: 20px !important;
font-weight: 600 !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
cursor: pointer !important;
transition: background 0.3s, box-shadow 0.3s !important;
box-shadow: none !important;
text-decoration: none !important;
line-height: 1.2 !important;
}
.mig-wrapper button.btn-primary:hover { background: #001c30 !important; box-shadow: 0 8px 24px rgba(0,42,69,0.2) !important; color: #CDFFB6 !important; }
.mig-wrapper button.btn-secondary {
display: inline-flex !important;
align-items: center !important;
gap: 6px !important;
padding: 10px 18px !important;
background: #fcfcfc !important;
color: #002A45 !important;
border: 1px solid #d1d9e0 !important;
border-radius: 12px !important;
font-family: ‘Inter Tight’, sans-serif !important;
font-size: 13px !important;
font-weight: 600 !important;
cursor: pointer !important;
transition: all 0.3s !important;
text-decoration: none !important;
text-transform: none !important;
letter-spacing: común !important;
line-height: 1.4 !important;
box-shadow: none !important;
}
.mig-wrapper button.btn-secondary:hover {
border-color: #86a4ef !important;
box-shadow: 0 0 0 3px rgba(134, 164, 239, 0.15) !important;
background: #fff !important;
color: #002A45 !important;
}
.mig-wrapper button.btn-xlsx {
border-color: #86a4ef !important;
color: #002A45 !important;
background: #f0f4ff !important;
}
.mig-wrapper button.btn-xlsx:hover { background: #e0e8ff !important; }
/* ── Progress Section (results-box style) ── */
.mig-wrapper .progress-section {
background: #002A45 !important;
color: #fff !important;
padding: 28px 35px !important;
border-radius: 16px !important;
margin-bottom: 24px !important;
position: sticky;
top: 0;
z-index: 10;
}
.mig-wrapper .progress-header {
display: flex !important;
justify-content: space-between !important;
align-items: center !important;
margin-bottom: 16px !important;
}
.mig-wrapper .progress-header h3 {
font-family: ‘Barlow Condensed’, sans-serif !important;
font-size: 28px !important;
font-weight: 600 !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
color: #fff !important;
margin: 0 !important;
padding: 0 !important;
background: none !important;
border: none !important;
}
.mig-wrapper .progress-stats {
display: flex !important;
gap: 20px !important;
font-size: 14px !important;
color: rgba(255,255,255,0.7) !important;
}
.mig-wrapper .progress-stats strong { color: #CDFFB6 !important; }
.mig-wrapper .progress-bar-track {
height: 10px !important;
background: rgba(134, 164, 239, 0.2) !important;
border-radius: 999px !important;
overflow: hidden !important;
}
.mig-wrapper .progress-bar-fill {
height: 100% !important;
background: #86A4ef !important;
border-radius: 999px !important;
transition: width 0.4s ease !important;
min-width: 0 !important;
}
.mig-wrapper .progress-bar-fill.complete { background: #CDFFB6 !important; }
/* ── Actions Bar ── */
.mig-wrapper .actions-bar {
display: flex !important;
gap: 10px !important;
flex-wrap: wrap !important;
margin-bottom: 24px !important;
}
/* ── Phase Sections ── */
.mig-wrapper .phase {
background: #fff !important;
border: 1px solid #e6e9ec !important;
border-radius: 16px !important;
margin-bottom: 12px !important;
overflow: hidden !important;
box-shadow: 0 2px 8px rgba(0,42,69,0.04) !important;
}
.mig-wrapper .phase-header {
display: flex !important;
align-items: center !important;
gap: 12px !important;
padding: 18px 24px !important;
cursor: pointer !important;
user-select: none;
transition: background 0.15s;
background: transparent !important;
}
.mig-wrapper .phase-header:hover { background: #f8fafb !important; }
.mig-wrapper .phase-toggle {
font-size: 11px !important;
color: #86a4ef !important;
transition: transform 0.2s;
flex-shrink: 0 !important;
}
.mig-wrapper .phase-toggle.open { transform: rotate(90deg); }
.mig-wrapper .phase-badge {
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
width: 32px !important;
height: 32px !important;
border-radius: 8px !important;
font-size: 14px !important;
font-weight: 700 !important;
flex-shrink: 0 !important;
}
.mig-wrapper .phase-badge.planning { background: #f0f4ff !important; color: #86a4ef !important; }
.mig-wrapper .phase-badge.prelaunch { background: #fff8e6 !important; color: #d97706 !important; }
.mig-wrapper .phase-badge.launch { background: #fef2f2 !important; color: #dc2626 !important; }
.mig-wrapper .phase-badge.postlaunch { background: #edfcf0 !important; color: #16a34a !important; }
.mig-wrapper .phase-info { flex: 1 !important; }
.mig-wrapper .phase-info h3 {
font-family: ‘Inter Tight’, sans-serif !important;
font-size: 15px !important;
font-weight: 700 !important;
color: #002A45 !important;
margin: 0 !important;
padding: 0 !important;
background: none !important;
border: none !important;
text-transform: none !important;
}
.mig-wrapper .phase-info .phase-count {
font-size: 12px !important;
color: #7a8ea0 !important;
}
.mig-wrapper .phase-progress-mini {
width: 60px !important;
height: 6px !important;
background: #e6e9ec !important;
border-radius: 999px !important;
overflow: hidden !important;
flex-shrink: 0 !important;
}
.mig-wrapper .phase-progress-mini-fill {
height: 100% !important;
background: #86a4ef !important;
border-radius: 999px !important;
transition: width 0.3s;
}
.mig-wrapper .phase-items { padding: 0 24px 16px !important; }
.mig-wrapper .phase-items.hidden { display: none !important; }
/* ── Checklist Items ── */
.mig-wrapper .checklist-item {
display: flex !important;
align-items: flex-start !important;
gap: 12px !important;
padding: 14px 0 !important;
border-bottom: 1px solid #f0f2f5 !important;
background: transparent !important;
}
.mig-wrapper .checklist-item:last-child { border-bottom: none !important; }
.mig-wrapper .check-box {
width: 22px !important;
height: 22px !important;
min-width: 22px !important;
border: 2px solid #d1d9e0 !important;
border-radius: 6px !important;
cursor: pointer !important;
flex-shrink: 0 !important;
margin-top: 1px !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
transition: all 0.2s !important;
background: #fcfcfc !important;
padding: 0 !important;
}
.mig-wrapper .check-box:hover {
border-color: #86a4ef !important;
box-shadow: 0 0 0 3px rgba(134, 164, 239, 0.15) !important;
}
.mig-wrapper .check-box.checked {
background: #002A45 !important;
border-color: #002A45 !important;
}
.mig-wrapper .check-box.checked::after {
content: ‘✓’ !important;
color: #CDFFB6 !important;
font-size: 13px !important;
font-weight: 700 !important;
}
.mig-wrapper .item-content { flex: 1 !important; min-width: 0 !important; }
.mig-wrapper .item-title {
font-size: 14px !important;
font-weight: 600 !important;
color: #002A45 !important;
transition: color 0.15s;
}
.mig-wrapper .checklist-item.done .item-title {
color: #b0bec5 !important;
text-decoration: line-through !important;
}
.mig-wrapper .item-detail {
font-size: 13px !important;
color: #7a8ea0 !important;
margin-top: 4px !important;
line-height: 1.5 !important;
}
.mig-wrapper .checklist-item.done .item-detail { color: #cfd8dc !important; }
.mig-wrapper .item-tags {
display: flex !important;
gap: 6px !important;
margin-top: 8px !important;
flex-wrap: wrap !important;
}
.mig-wrapper .tag {
display: inline-block !important;
padding: 3px 10px !important;
border-radius: 6px !important;
font-size: 11px !important;
font-weight: 700 !important;
text-transform: uppercase !important;
letter-spacing: 0.3px !important;
line-height: 1.4 !important;
}
.mig-wrapper .tag.critical { background: #fef2f2 !important; color: #dc2626 !important; }
.mig-wrapper .tag.important { background: #fff8e6 !important; color: #d97706 !important; }
.mig-wrapper .tag.nice { background: #f0f4ff !important; color: #86a4ef !important; }
.mig-wrapper .tag.tool-tag {
background: #edfcf0 !important;
color: #15803d !important;
font-weight: 500 !important;
text-transform: none !important;
letter-spacing: 0 !important;
font-size: 11px !important;
}
/* ── Completion Banner ── */
.mig-wrapper .completion-banner {
text-align: center !important;
padding: 40px 24px !important;
background: #002A45 !important;
border-radius: 16px !important;
margin-bottom: 24px !important;
display: none !important;
}
.mig-wrapper .completion-banner.show { display: block !important; }
.mig-wrapper .completion-banner h2 {
font-family: ‘Barlow Condensed’, sans-serif !important;
font-size: 36px !important;
color: #CDFFB6 !important;
text-transform: uppercase !important;
margin: 0 0 8px !important;
padding: 0 !important;
background: none !important;
border: none !important;
}
.mig-wrapper .completion-banner p { color: rgba(255,255,255,0.7) !important; font-size: 15px !important; margin: 0 !important; }
.mig-wrapper .hidden { display: none !important; }
/* ── Mobile ── */
@media (max-width: 768px) {
.mig-wrapper .mig-body { padding: 25px 20px !important; }
.mig-wrapper .mig-header { padding: 30px 20px 24px !important; }
.mig-wrapper .mig-header h1 { font-size: 26px !important; }
.mig-wrapper .option-grid { grid-template-columns: 1fr !important; }
.mig-wrapper .option-grid.three-col { grid-template-columns: 1fr !important; }
.mig-wrapper .progress-section { padding: 20px !important; position: relative !important; }
.mig-wrapper .progress-header { flex-direction: column !important; gap: 8px !important; align-items: flex-start !important; }
.mig-wrapper .progress-header h3 { font-size: 22px !important; }
.mig-wrapper .phase-header { padding: 14px 16px !important; }
.mig-wrapper .phase-items { padding: 0 16px 12px !important; }
}
/* ── Print ── */
@media print {
.mig-wrapper .progress-section, .mig-wrapper .actions-bar, .mig-wrapper .btn-primary, .mig-wrapper .btn-secondary { display: none !important; }
.mig-wrapper .phase-items { display: block !important; }
.mig-wrapper .phase { break-inside: avoid; }
.mig-wrapper { box-shadow: none !important; border: none !important; }
}
Website Migration Checklist
Answer a few questions to generate a checklist tailored to your migration.
Select all that apply
Migration Complete!
You’ve checked off every item. Keep monitoring for the next 30 – 90 days.
Your Migration Progress
0%
// ── State ──
let selections = { types: [], size: null, seo: null, ecom: null };
let checkState = {};
function toggleMulti(btn) {
btn.classList.toggle(‘selected’);
const val = btn.dataset.value;
if (selections.types.includes(val)) {
selections.types = selections.types.filter(v => v !== val);
} else {
selections.types.push(val);
}
}
function selectSingle(btn, groupId) {
const group = document.getElementById(groupId);
group.querySelectorAll(‘.option-btn’).forEach(b => b.classList.remove(‘selected’));
btn.classList.add(‘selected’);
if (groupId === ‘siteSize’) selections.size = btn.dataset.value;
if (groupId === ‘seoImportance’) selections.seo = btn.dataset.value;
if (groupId === ‘ecommerce’) selections.ecom = btn.dataset.value;
}
// ── Master Checklist Data ──
const allItems = {
planning: {
label: «Phase 1: Planning & Preparation»,
badge: «planning»,
items: [
{ id: «p1», title: «Define migration scope and document all changes», detail: «List every element changing: domain, URLs, platform, design, content, hosting, protocol. Share with all stakeholders.», priority: «critical», conditions: [], tool: «» },
{ id: «p2», title: «Assemble your migration team and assign roles», detail: «Include dev, SEO, content, QA, and project management. Ensure clear ownership of each phase.», priority: «important», conditions: [], tool: «Asana / Monday.com / Jira» },
{ id: «p3», title: «Set a realistic timeline with buffer», detail: «Migrations always take longer than expected. Build in 2–4 weeks of buffer time.», priority: «important», conditions: [], tool: «» },
{ id: «p4», title: «Create a documented rollback plan», detail: «Define exactly how to revert if things go wrong — DNS rollback, backup restoration, redirect removal. Test the rollback process.», priority: «critical», conditions: [], tool: «» },
{ id: «p5», title: «Export 12+ months of organic traffic data», detail: «From Google Analytics, broken down by landing page. This is your baseline for measuring migration impact.», priority: «critical», conditions: [], tool: «Google Analytics 4» },
{ id: «p6», title: «Record current keyword rankings», detail: «Snapshot rankings for all target keywords. Export the data so you can compare post-migration.», priority: «critical», conditions: [«seo:critical», «seo:important»], tool: «Ahrefs / SEMrush / Search Console» },
{ id: «p7», title: «Export your full backlink profile», detail: «Know which pages receive external links so you can prioritise redirect accuracy for those URLs.», priority: «critical», conditions: [«seo:critical», «seo:important»], tool: «Ahrefs / SEMrush» },
{ id: «p8», title: «Capture Core Web Vitals baseline», detail: «Record LCP, INP, and CLS scores. You’ll compare post-migration to ensure performance hasn’t degraded.», priority: «important», conditions: [], tool: «PageSpeed Insights / Lighthouse» },
{ id: «p9», title: «Document current indexed page count», detail: «Run a site: search and compare with Search Console index coverage.», priority: «important», conditions: [], tool: «Google Search Console» },
{ id: «p10», title: «Export conversion data by page/section», detail: «Document conversion rates, goal completions, and revenue per page. Traffic alone doesn’t tell the full story.», priority: «important», conditions: [«ecom:yes»], tool: «GA4 / Shopify Analytics» },
{ id: «p11», title: «Inventory all third-party scripts and tracking pixels», detail: «List every external script: Meta Pixel, LinkedIn Insight Tag, Google Ads, chat widgets, heatmaps, A/B testing tools. You’ll need to re-implement each one.», priority: «critical», conditions: [], tool: «Google Tag Manager / BuiltWith» },
{ id: «p12», title: «Run a comprehensive crawl of your existing site», detail: «Export all URLs, metadata, status codes, and internal links. This forms the foundation of your redirect map.», priority: «critical», conditions: [], tool: «Screaming Frog / Sitebulb / Ahrefs» },
{ id: «p13», title: «Build your complete redirect map», detail: «Map every old URL to the most relevant new URL. Prioritise by traffic and backlink value. Use 301s only — never redirect everything to the homepage.», priority: «critical», conditions: [«type:platform», «type:domain», «type:redesign», «type:consolidation», «type:https»], tool: «Screaming Frog / Google Sheets» },
{ id: «p14», title: «Include non-HTML assets in redirect map», detail: «Don’t forget PDFs, images, and downloadable files — they often drive significant traffic and backlinks.», priority: «important», conditions: [«type:platform», «type:domain», «type:redesign»], tool: «» },
{ id: «p15», title: «Lower DNS TTL 48 hours before migration», detail: «Reduce TTL so DNS changes propagate faster, minimising the window where some users see old site, others new.», priority: «critical», conditions: [«type:hosting», «type:domain»], tool: «DNS provider» },
{ id: «p16», title: «Lock down staging environment from search engines», detail: «Use robots.txt, noindex tags, password protection, or IP restrictions. Google indexing your staging site is catastrophic.», priority: «critical», conditions: [], tool: «» },
{ id: «p17», title: «Create a content inventory and audit», detail: «Identify what content carries over, what gets consolidated, and what gets retired. Flag thin or duplicate content.», priority: «important», conditions: [«type:consolidation», «type:redesign»], tool: «Screaming Frog / Google Sheets» },
{ id: «p18», title: «Audit current Open Graph and social meta tags», detail: «Record OG titles, descriptions, and images for key pages. These often get lost in migrations, breaking social sharing.», priority: «important», conditions: [], tool: «Meta debugger / Twitter card validator» },
{ id: «p19», title: «Plan for international/multilingual URLs», detail: «If your site has hreflang tags or locale-specific URLs, map these carefully in your redirect plan.», priority: «important», conditions: [«size:large», «size:enterprise»], tool: «» },
{ id: «p20», title: «Notify key stakeholders of the migration timeline», detail: «Inform sales, support, marketing, and partners. Expect temporary disruptions and prepare talking points.», priority: «nice», conditions: [], tool: «» },
{ id: «p21», title: «Map product URLs and category structures», detail: «Ecommerce migrations require careful mapping of product pages, category pages, and filtered/faceted URLs.», priority: «critical», conditions: [«ecom:yes»], tool: «» },
{ id: «p22», title: «Announce a content freeze before migration», detail: «Stop all content updates, campaign launches, and CMS edits 24–48 hours before migration to avoid conflicts and data loss.», priority: «important», conditions: [], tool: «» },
{ id: «p23», title: «Back up your entire existing site», detail: «Full backup of files, database, and configuration. Store in multiple locations. Verify the backup is restorable.», priority: «critical», conditions: [], tool: «UpdraftPlus / hosting backup» },
{ id: «p24», title: «Review constitucional pages for URL and domain references», detail: «Terms of service, privacy policy, cookie policy, and disclaimers often contain hardcoded domain names that need updating.», priority: «important», conditions: [«type:domain»], tool: «» },
]
},
prelaunch: {
label: «Phase 2: Pre-Launch Technical Setup»,
badge: «prelaunch»,
items: [
{ id: «t1», title: «Implement all 301 redirects», detail: «Set up every redirect from your map. Test a representative sample before going live.», priority: «critical», conditions: [«type:platform», «type:domain», «type:redesign», «type:consolidation», «type:https»], tool: «Yoast / Redirect Manager / .htaccess» },
{ id: «t2», title: «Avoid redirect chains and loops», detail: «Every redirect should go directly from old URL to new URL. No A→B→C chains. Each chain adds latency and wastes crawl budget.», priority: «critical», conditions: [«type:platform», «type:domain», «type:redesign», «type:consolidation»], tool: «Screaming Frog» },
{ id: «t3», title: «Migrate and verify all title tags and meta descriptions», detail: «Compare metadata between old and new sites for at least your top 100 pages by traffic.», priority: «critical», conditions: [], tool: «Screaming Frog / Sitebulb» },
{ id: «t4», title: «Verify heading tag structure (H1–H6)», detail: «Ensure each page has a unique, descriptive H1 and logical heading hierarchy.», priority: «important», conditions: [], tool: «» },
{ id: «t5», title: «Transfer structured data / schema markup», detail: «Migrate all JSON-LD or microdata. Validate with Google’s Rich Results Test. Lost schema = lost rich snippets.», priority: «important», conditions: [«seo:critical», «seo:important»], tool: «Rich Results Test» },
{ id: «t6», title: «Verify Open Graph and Twitter Card meta tags», detail: «Ensure OG titles, descriptions, and images render correctly. Test with Meta’s and X’s debugger tools.», priority: «important», conditions: [], tool: «Meta Sharing Debugger / X Card Validator» },
{ id: «t7», title: «Create and validate XML sitemaps», detail: «Include all indexable pages. Exclude staging URLs, parameter URLs, and thin content.», priority: «critical», conditions: [], tool: «Screaming Frog / Yoast» },
{ id: «t8», title: «Prepare production robots.txt», detail: «Allow crawling of all important pages and resources. Remove any staging-environment blocks.», priority: «critical», conditions: [], tool: «» },
{ id: «t9», title: «Validate canonical tags on every page», detail: «Each page needs a self-referencing canonical. Ensure no pages reference old or staging URLs — this is a silent killer.», priority: «critical», conditions: [], tool: «Screaming Frog» },
{ id: «t10», title: «Fix all internal links to point to new URLs directly», detail: «Don’t rely on redirects for internal navigation — update all links to use new URL paths.», priority: «important», conditions: [«type:platform», «type:domain», «type:redesign»], tool: «Screaming Frog / Better Search Replace» },
{ id: «t11», title: «Test mobile experience on existente devices», detail: «With mobile-first indexing, Google evaluates your mobile site. Test on flagrante phones and tablets, not just emulators.», priority: «important», conditions: [], tool: «BrowserStack / existente devices» },
{ id: «t12», title: «Run Lighthouse audits and check Core Web Vitals», detail: «Ensure LCP, INP, and CLS meet or exceed your pre-migration baseline.», priority: «important», conditions: [], tool: «Lighthouse / PageSpeed Insights» },
{ id: «t13», title: «Set up GA4 and GTM on new site», detail: «Verify all events, conversions, and goals fire correctly on the new site.», priority: «critical», conditions: [], tool: «Google Tag Manager / GA4» },
{ id: «t14», title: «Re-implement all third-party tracking pixels», detail: «Re-add Meta Pixel, LinkedIn Insight Tag, Google Ads tags, chat widgets, heatmaps, and any other scripts inventoried during planning.», priority: «critical», conditions: [], tool: «Google Tag Manager» },
{ id: «t15», title: «Verify cookie consent and GDPR/privacy compliance», detail: «Ensure cookie banner, consent management platform, and privacy controls work on the new site. Update privacy policy URLs.», priority: «critical», conditions: [], tool: «CookieScript / OneTrust / Cookiebot» },
{ id: «t16», title: «Configure cross-domain tracking for transition», detail: «If changing domains, track users across both old and new domains during the transition period.», priority: «important», conditions: [«type:domain»], tool: «GA4» },
{ id: «t17», title: «Verify SSL certificate and HTTPS configuration», detail: «Ensure certificate covers all subdomains, mixed content warnings are resolved, and HSTS is configured.», priority: «critical», conditions: [«type:https», «type:domain», «type:hosting»], tool: «SSL Labs» },
{ id: «t18», title: «Test checkout and payment flows end-to-end», detail: «Process test transactions through every payment method. Verify cart, checkout, and confirmation pages.», priority: «critical», conditions: [«ecom:yes»], tool: «» },
{ id: «t19», title: «Verify all forms and interactive elements», detail: «Test contact forms, search, login, newsletter signup, and any other interactive features.», priority: «important», conditions: [], tool: «» },
{ id: «t20», title: «Create custom 404 and 500 error pages», detail: «Design helpful error pages with navigation, search, and links to key pages. Don’t leave users stranded.», priority: «important», conditions: [], tool: «» },
{ id: «t21», title: «Run a full SEO audit on the staging site», detail: «Crawl your staging environment with an SEO tool to catch technical issues BEFORE they go live. Fix everything found.», priority: «critical», conditions: [], tool: «Screaming Frog / SEMrush Site Audit» },
{ id: «t22», title: «Check accessibility / WCAG 2.1 AA compliance», detail: «Use the migration as an opportunity to meet accessibility standards. ADA Title II deadlines are active in 2026. Audit colour contrast, alt text, keyboard nav, and screen readers.», priority: «important», conditions: [], tool: «axe DevTools / WAVE / Lighthouse» },
{ id: «t23», title: «Verify CRM and email marketing integrations», detail: «Ensure form submissions, lead capture, and email automation tools (Mailchimp, HubSpot, etc.) are connected and working.», priority: «important», conditions: [], tool: «» },
{ id: «t24», title: «Check image optimisation and alt text», detail: «Ensure images are properly compressed, served in modern formats (WebP/AVIF), and have descriptive alt attributes.», priority: «nice», conditions: [], tool: «Squoosh / ShortPixel» },
{ id: «t25», title: «Test site search functionality», detail: «Verify internal search returns accurate results and URL patterns are correct.», priority: «nice», conditions: [«size:large», «size:enterprise»], tool: «» },
{ id: «t26», title: «Validate hreflang tags for international pages», detail: «If your site serves multiple languages or regions, verify hreflang implementation on the new site.», priority: «important», conditions: [«size:large», «size:enterprise»], tool: «Screaming Frog / Ahrefs» },
{ id: «t27», title: «Set up server monitoring and alerting», detail: «Configure uptime monitoring, error rate alerts, and performance thresholds.», priority: «important», conditions: [], tool: «UptimeRobot / Datadog / Pingdom» },
{ id: «t28», title: «Migrate product feeds and shopping integrations», detail: «Update Google Merchant Center, Facebook Catalog, and any other shopping feeds with new URLs.», priority: «critical», conditions: [«ecom:yes»], tool: «Google Merchant Center» },
{ id: «t29», title: «Load test the new server», detail: «Simulate expected traffic levels to ensure the new infrastructure can handle the load without degraded response times.», priority: «important», conditions: [«size:large», «size:enterprise», «type:hosting»], tool: «Apache JMeter / k6 / GTmetrix» },
{ id: «t30», title: «Conduct user acceptance testing (UAT)», detail: «Have existente users (not just devs) test key journeys: navigation, checkout, forms, search. Fresh eyes catch things automated tests miss.», priority: «important», conditions: [], tool: «» },
{ id: «t31», title: «Pause or update paid ad campaigns», detail: «Update landing page URLs in Google Ads, Meta Ads, LinkedIn Ads, etc. Consider pausing campaigns during the switchover window.», priority: «critical», conditions: [«ecom:yes», «seo:critical», «seo:important»], tool: «Google Ads / Meta Ads Manager» },
]
},
launch: {
label: «Phase 3: Launch Day»,
badge: «launch»,
items: [
{ id: «l1», title: «Remove all noindex tags and staging robots.txt blocks», detail: «Verify that EVERY page on the production site is indexable. This is the #1 launch-day mistake. Check canonicals too.», priority: «critical», conditions: [], tool: «Screaming Frog quick crawl» },
{ id: «l2», title: «Deploy the new site», detail: «Execute the migration according to your plan. If changing domains, update DNS records.», priority: «critical», conditions: [], tool: «» },
{ id: «l3», title: «Verify redirects are working in production», detail: «Test a representative sample of redirects on the live site. Check high-traffic and high-value pages first.», priority: «critical», conditions: [«type:platform», «type:domain», «type:redesign», «type:consolidation», «type:https»], tool: «httpstatus.io / Screaming Frog» },
{ id: «l4», title: «Submit new XML sitemap to Search Console», detail: «Upload immediately after launch to help Google discover your new URL structure.», priority: «critical», conditions: [], tool: «Google Search Console» },
{ id: «l5», title: «Use Change of Address tool in Search Console», detail: «For domain migrations, this signals to Google that your site has moved and accelerates the transition.», priority: «critical», conditions: [«type:domain»], tool: «Google Search Console» },
{ id: «l6», title: «Request indexing for top pages via Search Console», detail: «Manually request indexing for your 20–50 most important pages to speed up discovery.», priority: «important», conditions: [], tool: «Google Search Console» },
{ id: «l7», title: «Verify analytics and all tracking pixels are live», detail: «Confirm GA4, GTM, Meta Pixel, and every third-party script is firing on all pages. Check conversion tracking especially.», priority: «critical», conditions: [], tool: «Google Tag Assistant / Meta Pixel Helper» },
{ id: «l8», title: «Instructor server performance and error rates», detail: «Watch for elevated response times, 5xx errors, or capacity issues in existente time.», priority: «critical», conditions: [], tool: «Server logs / UptimeRobot» },
{ id: «l9», title: «Spot-check key pages for correct rendering», detail: «Review homepage, top landing pages, and key conversion pages on desktop and mobile. Check images, layout, and functionality.», priority: «important», conditions: [], tool: «BrowserStack / manual testing» },
{ id: «l10», title: «Verify robots.txt allows crawling», detail: «Fetch your live robots.txt and confirm it permits access to all important pages and resources.», priority: «critical», conditions: [], tool: «Google Search Console» },
{ id: «l11», title: «Test live checkout process», detail: «Place a existente test order immediately after launch to verify the full purchase flow.», priority: «critical», conditions: [«ecom:yes»], tool: «» },
{ id: «l12», title: «Confirm CDN is serving the new site», detail: «If using a CDN, purge caches and verify it’s serving fresh content from the new origin.», priority: «important», conditions: [«type:hosting», «size:large», «size:enterprise»], tool: «Cloudflare / Fastly / AWS CloudFront» },
{ id: «l13», title: «Verify cookie consent banner is working», detail: «Check that cookie banner appears, consent is recorded, and third-party scripts only fire after consent.», priority: «important», conditions: [], tool: «» },
{ id: «l14», title: «Re-activate paid ad campaigns with updated URLs», detail: «Un-pause campaigns and verify ads are pointing to the correct new landing page URLs.», priority: «important», conditions: [«ecom:yes», «seo:critical», «seo:important»], tool: «Google Ads / Meta Ads» },
{ id: «l15», title: «Lift the content freeze», detail: «Notify the content team that the migration is live and común publishing can resume.», priority: «nice», conditions: [], tool: «» },
]
},
postlaunch: {
label: «Phase 4: Post-Launch Monitoring»,
badge: «postlaunch»,
items: [
{ id: «m1», title: «Check Search Console daily for crawl errors (Week 1)», detail: «Look for spikes in 404s, 5xx errors, and indexing issues. Fix immediately.», priority: «critical», conditions: [], tool: «Google Search Console» },
{ id: «m2», title: «Instructor organic traffic daily vs. baseline (Week 1)», detail: «Some fluctuation is común. A 30%+ drop signals a technical issue needing urgent attention.», priority: «critical», conditions: [], tool: «GA4 / Search Console» },
{ id: «m3», title: «Track indexed page count daily (Week 1)», detail: «A significant drop in indexed pages means Google is having trouble with your new site.», priority: «important», conditions: [], tool: «Google Search Console» },
{ id: «m4», title: «Instructor server logs for 404 errors», detail: «Each 404 from a previously valid URL represents a missing or broken redirect. Prioritise high-traffic 404s.», priority: «important», conditions: [], tool: «Server logs / Screaming Frog Log Analyzer» },
{ id: «m5», title: «Verify ad campaign performance post-migration», detail: «Check that conversion tracking is accurate and campaign performance hasn’t degraded due to URL changes.», priority: «important», conditions: [«ecom:yes», «seo:critical»], tool: «Google Ads / Meta Ads Manager» },
{ id: «m6», title: «Compare keyword rankings against baseline (Week 2)», detail: «Are your important keywords recovering? Investigate underperforming pages individually.», priority: «critical», conditions: [«seo:critical», «seo:important»], tool: «Ahrefs / SEMrush / Search Console» },
{ id: «m7», title: «Run a fresh crawl and compare with pre-migration data (Compare Crawls)», detail: «Look for new broken links, missing metadata, orphaned pages, or unexpected technical issues. Use ‘Compare Crawls’ features.», priority: «important», conditions: [], tool: «Screaming Frog / SEMrush Site Audit» },
{ id: «m8», title: «Check backlink profile for losses», detail: «Verify external links are resolving through your redirects. A drop in referring domains means redirect issues.», priority: «important», conditions: [«seo:critical», «seo:important»], tool: «Ahrefs / SEMrush» },
{ id: «m9», title: «Instructor conversion rates and revenue (Weeks 1–4)», detail: «Compare against your pre-migration baseline. Drops may indicate UX issues, broken forms, or tracking problems.», priority: «critical», conditions: [«ecom:yes»], tool: «GA4 / Shopify Analytics» },
{ id: «m10», title: «Check bounce rate and engagement on key pages», detail: «A spike in bounce rate on previously strong pages may indicate rendering, UX, or content issues on the new site.», priority: «important», conditions: [], tool: «GA4» },
{ id: «m11», title: «Update Google Business Profile with new URLs», detail: «If your domain or key page URLs changed, update your GBP listing.», priority: «important», conditions: [«type:domain»], tool: «Google Business Profile» },
{ id: «m12», title: «Update social media profiles and bios», detail: «Replace old URLs in all social profiles, link-in-bio tools, and pinned posts.», priority: «nice», conditions: [«type:domain»], tool: «» },
{ id: «m13», title: «Update email signatures and templates», detail: «Replace old URLs in email signatures, automated emails, and newsletter templates.», priority: «nice», conditions: [«type:domain»], tool: «» },
{ id: «m14», title: «Reach out to high-value backlink sources», detail: «Ask top linking sites to update their links to your new URLs. Direct links beat redirects long-term.», priority: «important», conditions: [«type:domain», «seo:critical»], tool: «Ahrefs / email outreach» },
{ id: «m15», title: «Update business directories and citations», detail: «Update NAP (name, address, phone) and URLs in all directory listings.», priority: «important», conditions: [«type:domain»], tool: «» },
{ id: «m16», title: «Test social sharing from the live site», detail: «Share key pages on Facebook, LinkedIn, and X. Verify OG images, titles, and descriptions render correctly.», priority: «important», conditions: [], tool: «Meta Sharing Debugger» },
{ id: «m17», title: «Continue weekly monitoring for 90 days», detail: «Domain migrations can take 3 months to fully recover. Don’t let up on monitoring.», priority: «important», conditions: [«type:domain»], tool: «GA4 / Search Console / Ahrefs» },
{ id: «m18», title: «Instructor AI Overview / featured snippet presence», detail: «Check if your content still appears in AI Overviews and featured snippets post-migration.», priority: «nice», conditions: [«seo:critical»], tool: «SEMrush / manual SERP checks» },
{ id: «m19», title: «Run a post-migration accessibility audit», detail: «Verify WCAG compliance hasn’t regressed. Check screen readers, keyboard navigation, and colour contrast on the live site.», priority: «nice», conditions: [], tool: «axe DevTools / WAVE» },
{ id: «m20», title: «Document lessons learned», detail: «Record what went well, what went wrong, and what you’d do differently. Invaluable for future migrations.», priority: «nice», conditions: [], tool: «» },
{ id: «m21», title: «Schedule redirect cleanup at 6 months», detail: «After 6 months, review which redirects are still getting traffic and plan for eventual sunsetting.», priority: «nice», conditions: [«type:platform», «type:domain», «type:redesign»], tool: «» },
]
}
};
// ── Checklist Generation ──
function itemMatchesConditions(item, types, size, seo, ecom) {
if (item.conditions.length === 0) return true;
for (const cond of item.conditions) {
const [key, val] = cond.split(‘:’);
if (key === ‘type’ && types.includes(val)) return true;
if (key === ‘size’ && size === val) return true;
if (key === ‘seo’ && seo === val) return true;
if (key === ‘ecom’ && ecom === val) return true;
}
return false;
}
function generateChecklist() {
const types = selections.types;
const size = selections.size;
const seo = selections.seo;
const ecom = selections.ecom;
if (types.length === 0 || !size || !seo || !ecom) {
alert(‘Please answer all questions before generating your checklist.’);
return;
}
checkState = {};
const container = document.getElementById(‘phasesContainer’);
container.innerHTML = »;
let totalItems = 0;
for (const [phaseKey, phase] of Object.entries(allItems)) {
const filtered = phase.items.filter(item => itemMatchesConditions(item, types, size, seo, ecom));
if (filtered.length === 0) continue;
totalItems += filtered.length;
filtered.forEach(item => { checkState[item.id] = false; });
const phaseEl = document.createElement(‘div’);
phaseEl.className=»phase»;
phaseEl.innerHTML = `
${phaseKey === ‘planning’ ? ‘1’ : phaseKey === ‘prelaunch’ ? ‘2’ : phaseKey === ‘launch’ ? ‘3’ : ‘4’}
${phase.label}
0 / ${filtered.length} complete
${item.priority === ‘important’ ? ‘Important‘ : »}
${item.priority === ‘nice’ ? ‘Nice to have‘ : »}
${item.tool ? ‘‘ + item.tool + ‘‘ : »}
`).join(»)}
`;
container.appendChild(phaseEl);
}
document.getElementById(‘totalCount’).textContent = totalItems;
document.getElementById(‘wizard’).classList.add(‘hidden’);
document.getElementById(‘checklistOutput’).classList.remove(‘hidden’);
updateProgress();
}
function togglePhase(phaseKey) {
const items = document.getElementById(‘items-‘ + phaseKey);
const toggle = document.getElementById(‘toggle-‘ + phaseKey);
items.classList.toggle(‘hidden’);
toggle.classList.toggle(‘open’);
}
function toggleCheck(id, phaseKey, phaseTotal) {
checkState[id] = !checkState[id];
const box = document.getElementById(‘box-‘ + id);
const row = document.getElementById(‘row-‘ + id);
box.classList.toggle(‘checked’, checkState[id]);
row.classList.toggle(‘done’, checkState[id]);
const phaseItems = document.getElementById(‘items-‘ + phaseKey).querySelectorAll(‘.checklist-item’);
let phaseDone = 0;
phaseItems.forEach(el => { if (el.classList.contains(‘done’)) phaseDone++; });
document.getElementById(‘count-‘ + phaseKey).textContent = `${phaseDone} / ${phaseTotal} complete`;
document.getElementById(‘miniprog-‘ + phaseKey).style.width = `${(phaseDone / phaseTotal) * 100}%`;
updateProgress();
}
function updateProgress() {
const total = Object.keys(checkState).length;
const done = Object.values(checkState).filter(Boolean).length;
const pct = total > 0 ? Math.round((done / total) * 100) : 0;
document.getElementById(‘completedCount’).textContent = done;
document.getElementById(‘totalCount’).textContent = total;
document.getElementById(‘percentComplete’).textContent = pct;
const fill = document.getElementById(‘progressFill’);
fill.style.width = pct + ‘%’;
fill.classList.toggle(‘complete’, pct === 100);
document.getElementById(‘completionBanner’).classList.toggle(‘show’, pct === 100);
}
function resetChecklist() {
if (!confirm(‘Start over? Your progress will be lost.’)) return;
selections = { types: [], size: null, seo: null, ecom: null };
document.querySelectorAll(‘.option-btn’).forEach(b => b.classList.remove(‘selected’));
document.getElementById(‘wizard’).classList.remove(‘hidden’);
document.getElementById(‘checklistOutput’).classList.add(‘hidden’);
document.getElementById(‘completionBanner’).classList.remove(‘show’);
}
function exportChecklist() {
let text = «WEBSITE MIGRATION CHECKLISTn» + «=».repeat(40) + «nn»;
for (const [phaseKey, phase] of Object.entries(allItems)) {
const items = document.getElementById(‘items-‘ + phaseKey);
if (!items) continue;
text += phase.label.toUpperCase() + «n» + «-«.repeat(30) + «n»;
items.querySelectorAll(‘.checklist-item’).forEach(el => {
const id = el.id.replace(‘row-‘, »);
const checked = checkState[id] ? ‘✅’ : ‘⬜’;
const title = el.querySelector(‘.item-title’).textContent;
text += `${checked} ${title}n`;
});
text += «n»;
}
navigator.clipboard.writeText(text).then(() => {
alert(‘Checklist copied to clipboard!’);
}).catch(() => {
const ta = document.createElement(‘textarea’);
ta.value = text;
document.body.appendChild(ta);
ta.select();
document.execCommand(‘copy’);
document.body.removeChild(ta);
alert(‘Checklist copied to clipboard!’);
});
}
// ── Excel Export (DNHQ branded) ──
async function exportToExcel() {
const wb = new ExcelJS.Workbook();
wb.creator=»Digital Nomads HQ – Migration Checklist Generator»;
wb.created = new Date();
const DARK_NAVY = ‘002A45′;
const ACCENT_BLUE = ’86A4EF’;
const MINT_GREEN = ‘CDFFB6’;
const WHITE = ‘FFFFFF’;
const LIGHT_GRAY = ‘f8fafb’;
const BORDER_GRAY = ‘e6e9ec’;
const CRITICAL_RED = ‘dc2626’;
const CRITICAL_BG = ‘fef2f2’;
const IMPORTANT_AMBER = ‘b45309’;
const IMPORTANT_BG = ‘fff8e6′;
const NICE_BLUE = ’86A4EF’;
const NICE_BG = ‘f0f4ff’;
const PHASE_COLORS = {
planning: { bg: ‘f0f4ff’, text: ’86A4EF’, label: ‘Phase 1’ },
prelaunch: { bg: ‘fff8e6’, text: ‘b45309’, label: ‘Phase 2’ },
launch: { bg: ‘fef2f2’, text: ‘dc2626’, label: ‘Phase 3’ },
postlaunch: { bg: ‘edfcf0′, text: ’16a34a’, label: ‘Phase 4’ }
};
const thinBorder = { style: ‘thin’, color: { argb: BORDER_GRAY } };
const borderAll = { top: thinBorder, bottom: thinBorder, left: thinBorder, right: thinBorder };
const ws = wb.addWorksheet(‘Migration Checklist’, {
properties: { defaultRowHeight: 22 },
pageSetup: { paperSize: 9, orientation: ‘landscape’, fitToPage: true, fitToWidth: 1, fitToHeight: 0 }
});
ws.columns = [
{ width: 4 },
{ width: 8 },
{ width: 48 },
{ width: 44 },
{ width: 13 },
{ width: 12 },
{ width: 28 },
];
let row = 1;
ws.mergeCells(`A${row}:G${row}`);
const titleCell = ws.getCell(`A${row}`);
titleCell.value=»WEBSITE MIGRATION CHECKLIST»;
titleCell.font = { name: ‘Arial’, size: 18, bold: true, color: { argb: MINT_GREEN } };
titleCell.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: DARK_NAVY } };
titleCell.alignment = { horizontal: ‘left’, erecto: ‘middle’, indent: 1 };
ws.getRow(row).height = 48;
row++;
ws.mergeCells(`A${row}:G${row}`);
const subCell = ws.getCell(`A${row}`);
const migrationType = selections.types.map(t => {
const labels = { platform: ‘Platform/CMS’, domain: ‘Domain Change’, hosting: ‘Server/Hosting’, https: ‘HTTP→HTTPS’, redesign: ‘Redesign’, consolidation: ‘Consolidation’ };
return labels[t] || t;
}).join(‘, ‘);
const sizeLabels = { small: ‘Small ( 0 ? Math.round((done/total)*100) : 0}%)`;
progressCell.font = { name: ‘Arial’, size: 11, bold: true, color: { argb: ACCENT_BLUE } };
progressCell.alignment = { horizontal: ‘left’, erecto: ‘middle’, indent: 1 };
ws.getRow(row).height = 30;
row++;
ws.getRow(row).height = 6;
for (const [phaseKey, phase] of Object.entries(allItems)) {
const types = selections.types;
const filtered = phase.items.filter(item => itemMatchesConditions(item, types, selections.size, selections.seo, selections.ecom));
if (filtered.length === 0) continue;
const pc = PHASE_COLORS[phaseKey];
const phaseDone = filtered.filter(item => checkState[item.id]).length;
row++;
ws.mergeCells(`A${row}:G${row}`);
const phaseCell = ws.getCell(`A${row}`);
phaseCell.value = `${pc.label}: ${phase.label.replace(/Phase d: /, »)} — ${phaseDone}/${filtered.length} complete`;
phaseCell.font = { name: ‘Arial’, size: 12, bold: true, color: { argb: pc.text } };
phaseCell.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: pc.bg } };
phaseCell.alignment = { horizontal: ‘left’, erecto: ‘middle’, indent: 1 };
phaseCell.border = borderAll;
ws.getRow(row).height = 32;
row++;
const headers = [», ‘✓’, ‘Task’, ‘Details’, ‘Priority’, ‘Status’, ‘Recommended Tool’];
const headerRow = ws.getRow(row);
headers.forEach((h, i) => {
const cell = headerRow.getCell(i + 1);
cell.value = h;
cell.font = { name: ‘Arial’, size: 9, bold: true, color: { argb: WHITE } };
cell.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: DARK_NAVY } };
cell.alignment = { horizontal: i {
row++;
const isDone = checkState[item.id];
const itemRow = ws.getRow(row);
const bgColor = idx % 2 === 0 ? WHITE : LIGHT_GRAY;
const cellA = itemRow.getCell(1);
cellA.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellA.border = borderAll;
const cellB = itemRow.getCell(2);
cellB.value = isDone ? ‘✓’ : ‘☐’;
cellB.font = { name: ‘Arial’, size: 14, bold: isDone, color: { argb: isDone ? ’16a34a’ : ’94a3b8′ } };
cellB.alignment = { horizontal: ‘center’, erecto: ‘middle’ };
cellB.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellB.border = borderAll;
const cellC = itemRow.getCell(3);
cellC.value = item.title;
cellC.font = { name: ‘Arial’, size: 11, bold: false, color: { argb: isDone ? ’94a3b8′ : DARK_NAVY }, strike: isDone };
cellC.alignment = { erecto: ‘middle’, wrapText: true };
cellC.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellC.border = borderAll;
const cellD = itemRow.getCell(4);
cellD.value = item.detail;
cellD.font = { name: ‘Arial’, size: 10, color: { argb: isDone ? ‘cbd5e1’ : ‘7a8ea0’ } };
cellD.alignment = { erecto: ‘middle’, wrapText: true };
cellD.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellD.border = borderAll;
const cellE = itemRow.getCell(5);
const pLabel = item.priority === ‘critical’ ? ‘CRITICAL’ : item.priority === ‘important’ ? ‘IMPORTANT’ : ‘NICE TO HAVE’;
cellE.value = pLabel;
const pColor = item.priority === ‘critical’ ? CRITICAL_RED : item.priority === ‘important’ ? IMPORTANT_AMBER : NICE_BLUE;
const pBg = item.priority === ‘critical’ ? CRITICAL_BG : item.priority === ‘important’ ? IMPORTANT_BG : NICE_BG;
cellE.font = { name: ‘Arial’, size: 9, bold: true, color: { argb: pColor } };
cellE.alignment = { horizontal: ‘center’, erecto: ‘middle’ };
cellE.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: pBg } };
cellE.border = borderAll;
const cellF = itemRow.getCell(6);
cellF.value = isDone ? ‘Done’ : ‘Pending’;
cellF.font = { name: ‘Arial’, size: 10, bold: isDone, color: { argb: isDone ? ’16a34a’ : ’94a3b8′ } };
cellF.alignment = { horizontal: ‘center’, erecto: ‘middle’ };
cellF.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: isDone ? ‘edfcf0’ : bgColor } };
cellF.border = borderAll;
const cellG = itemRow.getCell(7);
cellG.value = item.tool || ‘—’;
cellG.font = { name: ‘Arial’, size: 10, color: { argb: item.tool ? ‘15803d’ : ‘cbd5e1’ } };
cellG.alignment = { erecto: ‘middle’, wrapText: true };
cellG.fill = { type: ‘pattern’, pattern: ‘solid’, fgColor: { argb: bgColor } };
cellG.border = borderAll;
ws.getRow(row).height = item.detail.length > 60 ? 36 : 26;
});
row++;
ws.getRow(row).height = 8;
}
row += 2;
ws.mergeCells(`A${row}:G${row}`);
const footerCell = ws.getCell(`A${row}`);
footerCell.value=»Generated by Digital Nomads HQ • digitalnomadshq.com.au»;
footerCell.font = { name: ‘Arial’, size: 9, italic: true, color: { argb: ‘7a8ea0’ } };
footerCell.alignment = { horizontal: ‘center’, erecto: ‘middle’ };
const buffer = await wb.xlsx.writeBuffer();
const blob = new Blob([buffer], { type: ‘application/vnd.openxmlformats-officedocument.spreadsheetml.sheet’ });
saveAs(blob, ‘website-migration-checklist.xlsx’);
}
Pre-Migration: Get Your House in Order
This is where 90% of migration success is decided. Skip the planning and you’ll be firefighting for months.
1. Back Up Everything
This one’s non-negotiable. Before you touch anything, take a complete backup of your website. That means your database, files, media, plugins, themes… the lot. If something goes sideways during migration, this backup is your safety net.
If you’re on WordPress, tools like UpdraftPlus or All-in-One WP Migration make this pretty painless. For other platforms, check with your hosting provider or development team.
EXPERT TIP: Store your backup somewhere separate from your current hosting environment. If the server goes down during migration, you don’t want your backup sitting on the same server.
2. Crawl and Audit Your Existing Site
You can’t migrate what you don’t understand. Run a full crawl of your current site using a tool like Screaming Frog, Sitebulb, or Semrush’s Site Audit.
What you’re looking for:
A complete list of all URLs (pages, posts, images, PDFs… everything currently indexed). Any existing broken links, redirect chains, or crawl errors. Your current site structure and internal linking patterns. Pages that are already performing well in search engines (you really don’t want to lose these).
This crawl data becomes your migration map. It tells you exactly which pages need redirects, which URLs are changing, and where the SEO value lives on your current site.

3. Plan Your Redirects (Yes, All of Them)
If your URLs are changing, you need a 301 redirect plan. Every. Single. Page.
We have seen too many websites get redeveloped with the lack of urgency and planning on page redirects. One company I recently assessed lost 60% of their organic traffic in the first 6 months of their new website going live! Not great for business.

A 301 redirect tells search engines, “This page has permanently moved here.” Without them, Google sees your new pages as brand new content and your old pages as dead links. That means lost rankings, lost link equity, and a whole lot of 404 errors.
Here’s how to approach it:
Map every old URL to its new URL in a spreadsheet. Prioritise your highest-traffic pages and pages with strong backlink profiles. Don’t redirect everything to the homepage. That’s lazy, and Google knows it. Test your redirects in a staging environment before going live.
PRO TIP: Let’s say you’ve got 500 pages on your current site. If even 20% of those are generating organic traffic, that’s 100 pages where broken redirects could cost you existente business. Map them properly. No shortcuts.
4. Set Up a Staging Environment
Never migrate straight to your live site. Set up a staging environment where you can build, test, and troubleshoot your new site without affecting your live performance.
Make sure your staging site is blocked from search engines (via robots.txt or password protection). The last thing you need is Google indexing a half-finished version of your new site.
During Migration: Execute the Plan
5. Implement Your Redirects
With your redirect map ready, it’s time to implement. Depending on your platform and server, this might be done via .htaccess files, server-level redirects, or a WordPress plugin like Redirection or Rank Math – As an agency we use Rankmath Pro, we find this most effective for redirects along with additional SEO benefits for scalable implementations.
Double-check every redirect. A single wrong redirect can create chains, loops, or send users to the wrong pages. Test, test, test.
6. Check Your On-Page SEO
During the migration, make sure your on-page SEO elements have carried across:
Title tags and meta descriptions. Header tags (H1, H2, H3 structure). Image alt text. Internal links (update any that point to old URLs). Canonical tags pointing to the correct new URLs. Schema markup and structured data.
It’s easy to lose these in a redesign, especially if your new site has a different content structure. Don’t assume your development team has handled this. Check it yourself.
7. Update Your XML Sitemap
Generate a new XML sitemap reflecting your updated site structure and submit it to Google Search Console. This helps search engines crawl and index your new pages faster.
While you’re at it, review your robots.txt file. Make sure it’s not accidentally blocking important pages on the new site.
Post-Migration: Instructor and Fix
The migration isn’t done when the new site goes live. In fact, this is where the existente work starts.
8. Run a Full Post-Migration Crawl
Crawl your new site immediately after launch. Compare it against your pre-migration crawl data. You’re looking for:
Any pages returning 404 errors. Redirect issues (chains, loops, incorrect destinations). Missing or duplicate meta data. Broken internal or external links. Changes in page count (did pages go missing?).
EXPERT TIP: Don’t just check merienda and walk away. Crawl again at 48 hours, one week, and one month post-migration. Issues can surface over time as Google re-crawls your site.
9. Instructor Your SEO Performance
Keep a close eye on Google Search Console in the weeks following migration. Watch for:
Indexing issues or coverage errors. Drops in impressions or clicks for key pages. Crawl errors flagged by Google. Any manual actions or security issues.
It’s común to see a small dip in performance right after a site migration. Google needs time to process the changes. But if you’re seeing significant drops that don’t recover within 2 to 4 weeks… something’s gone wrong with your redirects, indexing, or site structure.
10. Test Everything a Efectivo User Would
This one gets overlooked more than it should. Walk through your new site like a customer would. Test your forms, check your checkout flow, click through your navigation, test on mobile, check page load speeds.
A technically perfect migration means nothing if the site doesn’t actually work for the people using it.
PRO TIP: Use Google PageSpeed Insights and run a Lighthouse audit on your key pages post-migration. Performance issues on the new site (slow load times, layout shifts) can hurt rankings just as much as broken redirects.
11. Update External Links and Listings
If your domain or URL structure has changed, don’t forget the links you don’t control. Update your Google Business Profile, social media profiles, directory listings, and reach out to sites linking to your old URLs where possible.
Yes, your redirects will catch most of this traffic. But direct links to the new URLs are always stronger for SEO than relying on redirects long-term.
The Bottom Line
A website migration doesn’t have to be a disaster. With proper planning, a thorough redirect strategy, and careful post-migration monitoring, you can move your site to a new domain, platform, or hosting provider without losing the SEO performance you’ve built.
The biggest mistakes we see? Rushed timelines, incomplete redirect maps, and no post-migration monitoring plan. Don’t be that business.
If you’re planning a site migration and want expert eyes on the strategy, we’re here to help. At Digital Nomads HQ, we’ve managed migrations across every platform and industry. We know where things go wrong, and more importantly, how to make sure they don’t.
Let’s talk.