MigrationFox Docs

SharePoint Site Pages

Modern SharePoint pages are canvas layouts with typed web parts, not HTML documents. MigrationFox migrates them as structured data through the Microsoft Graph Pages API so that the destination preserves sections, columns, web-part configuration, banner layout, and publish state. This page is the reference for what gets preserved, what needs manual review, and how to handle the edge cases.

What this feature does

For every modern site page in the source Site Pages library, MigrationFox reads the full canvas structure from the Graph Pages API, rewrites internal references (list IDs, library IDs, Site Assets image URLs) to the destination equivalents, re-creates the page with matching layout on the destination, publishes it, and replays the promoted-news-post state if the source page was a news post. The result is a visually identical page on the destination, not a copy-paste of rendered HTML.

What a modern page is (and why it matters)

In classic SharePoint, a page was essentially an HTML document stored in the Pages library. You could almost get away with copying the .aspx file across tenants. Modern pages — everything created under the SitePages content type — are different. They are structured canvas layouts backed by a JSON schema. A page has:

When the browser opens a page, SharePoint deserializes the canvas JSON, looks up each web part by its type ID, and renders it. The HTML you see in devtools is the output, not the source of truth. The source of truth is the canvas JSON — which is why migrating pages as list-library files (copy the .aspx, paste it into the destination library) produces broken pages even when it appears to succeed. The canvas JSON lives in a hidden column that often exceeds list-field-length thresholds, embedded web parts reference source-tenant IDs that do not exist on the destination, and publish state is not part of the page file at all.

Web part serialization

The Graph pages endpoint returns each web part as a typed object with:

MigrationFox preserves all of these for first-party web parts. For third-party or custom parts, preservation is partial — the type reference is carried across, but the part only renders if the matching package is installed on the destination. The tables below spell out exactly what that means.

Fully portable first-party web parts

ElementPreservedNotes
Canvas sections & columnsYesFull layout fidelity including vertical sections.
Text web partsYesRich text, formatting, inline links.
Image web partsYesImage file re-uploaded into the destination Site Assets library; reference rewritten to the new URL.
Highlighted Content / List viewerYesSource list ID rewritten to destination list ID (requires the list to have been migrated earlier).
Quick Links, People, EventsYesInternal references rewritten where the targets were migrated.
Banner image + layoutYesIncluding the banner’s focal point coordinates.
Promoted / News post stateYesReplayed via the Graph promoteToNewsPost call.
Page permissions (unique)YesApplied against the cross-tenant UPN mapping.

Web parts that need manual review

ElementPreservedNotes
Third-party SPFx web partsReference onlyPackage must be installed on the destination App Catalog. Until then the web part renders as an error tile.
Custom SPFx developed in-houseReference onlySame model — the .sppkg has to be uploaded to the destination App Catalog and deployed to consuming sites by a tenant admin.
Page-level approvals / pending draftsPartialThe currently published version migrates; draft workflow state does not.
Page version historyNoGraph does not expose a supported write path for prior versions. Current canvas migrates; history does not.
Page comments and likesNoGraph has no supported write path for historical comments. Current comments do not carry.

Cross-tenant URL rewriting

Canvas preservation handles the structural side. URLs inside the content are a separate problem. A rich-text web part might contain something like <a href="https://acme.sharepoint.com/sites/hr/handbook/welcome.aspx">Read the handbook</a>. That URL lives inside the rendered HTML of the text web part, not as a typed reference the migration engine can identify with certainty. The destination tenant is newcompany.sharepoint.com, so the link is now broken.

MigrationFox takes a conservative approach:

Reference rewriting requires phase ordering

Web parts reference data by ID, not by name. A Highlighted Content web part rolling up “the last five documents from Policies” stores the GUID of the source Policies library, not the word “Policies.” For the web part to work on the destination, that GUID must be rewritten to the destination library’s GUID — which means the list has to have been migrated before the page. The clean phase order is: site columns & content types, lists & libraries, list items & files, list views, site pages, permissions. MigrationFox sequences these automatically when the full site migration runs end-to-end.

Media references

Images and other media embedded in pages live in the site’s Site Assets library, not in the Pages library itself. A page references them by URL. Cross-tenant migration needs three things in sequence:

  1. The Site Assets library on the destination is provisioned (provisioning is automatic for every site created through MigrationFox; manually created destinations need it to exist).
  2. The source image files are uploaded into the destination Site Assets library with matching relative paths.
  3. The image web part references are rewritten to point at the destination Site Assets URL.

MigrationFox does all three automatically when a page migration is initiated for a site that is fully in scope. If you migrate a page from a site whose Site Assets library was not in scope — for example, cherry-picking a single page into a destination site — the image references point at the source tenant. They render until the source tenant revokes access or is retired, then they break. The migration report lists every cross-tenant image reference so you know which pages need a media fix.

Known limits

A few page capabilities are not currently shipped. Plan around them rather than expecting them to come across silently.

How MigrationFox walks a page

For each page in the source Site Pages library, the sequence is:

1. GET /sites/{source-site}/pages/{page-id}
2. Read the canvas sections, columns, and web parts
3. Walk each web part:
   a. Copy text / image / link web parts, rewriting internal URLs
   b. Rewrite list-viewer web parts to point at the destination list ID
   c. Flag SPFx web parts whose package ID is not installed on the
      destination for human review
4. POST the reconstructed page object to /sites/{dest-site}/pages
5. POST /publish to make it live
6. If the source was a promoted news post, POST /promoteToNewsPost

Step 3b is where the earlier phase-ordering matters. Every list and library referenced by any web part must already exist on the destination with its new ID captured, so the rewrite can resolve. Step 5 is why a freshly migrated page appears live rather than as a draft — the publish call is part of the standard flow.

Troubleshooting

SymptomLikely causeFix
A page appears in the destination but the layout is flat — no sections, no web parts visible The page was migrated as a list-library file rather than through the Graph Pages API. This can happen if the source was scoped to just the Site Pages library contents, bypassing the canvas-aware flow. Scope the migration to the whole site, or explicitly use the Pages migration step on the affected site. The naive file-copy path is not the right tool for canvas pages.
Web part shows as a grey error tile on the destination The web part is a third-party SPFx package that is not installed in the destination App Catalog. Check the migration report’s SPFx pre-flight list. A tenant admin uploads the .sppkg to the destination App Catalog and deploys it to the consuming sites. The web part renders on next page load.
Highlighted Content web part renders empty on the destination The web part’s source list ID was not rewritten — typically because the list it references was not in scope for migration, so no destination list ID existed to rewrite to. Add the list to the migration scope and re-run, or edit the web part on the destination to point at whatever list should be the source now.
Hyperlinks in text web parts still point at the source tenant Cross-tenant URL rewriting is deliberately conservative — ambiguous cases are flagged rather than rewritten. Check the migration report for the full list of flagged URLs by page. A content owner edits each text web part to update the link.
Images show as broken (red X) on the destination page The image was referenced from a Site Assets library that was not in scope for the migration; the image file was not re-uploaded to the destination. Expand the migration scope to include Site Assets, or re-upload the missing images to the destination Site Assets library manually.
News post status is lost — page is there but no longer marked as a news post The promoteToNewsPost replay step failed, commonly because the destination site is a communication site that handles news differently, or because the credential lacks page-write scope. Re-run the pages phase for the affected site, or manually promote the page to a news post via the destination UI.
Page version history is empty on the destination Expected. Page version history is not preserved by design — Graph does not expose a supported write path for prior versions. Capture the version history as a sidecar on the source before migration if it is needed for records retention.

Related