Guru-to-Notion migration requires HTML-to-block parsing, handling Notion's 3 req/sec rate limit, 100-block append ceiling, and a two-pass approach for internal link rewriting.
There is no native Guru-to-Notion importer — no built-in connector, no migration wizard. Guru stores knowledge as flat HTML Cards inside a Collection → Folder hierarchy. Notion stores every element as a discrete JSON block with its own ID, nested inside pages that can double as relational database rows. Every Card must be parsed, decomposed, and reassembled via Notion's block API. The migration requires HTML-to-block parsing, chunking to Notion's 100-block append ceiling, handling the 3 req/sec rate limit, and a two-pass approach for internal link rewriting.
Read this first
Pair-specific gotchas that catch teams out. Each one has cost somebody a weekend.
Key architectural mismatch
Guru Card content is stored as HTML. Notion's API expects block-level JSON objects. Every Card must be parsed, decomposed into individual blocks (paragraphs, headings, lists, code blocks, images), and reassembled via Notion's block API — which has hard limits on nesting depth, array size, and payload weight.
Notion limitation
Notion doesn't have true custom objects. Everything is a database with typed properties. You can model any Guru data structure — but you lose Guru's verification workflow, trust scores, and AI-powered answer features. Notion also recommends a maximum of 500 properties or 50 KB schema size per database. Plan for which organizational processes need to be rebuilt in Notion after migration.
Why include both "Verifier" (Person) and "Verifier Email" (Email)? The Person property
Why include both "Verifier" (Person) and "Verifier Email" (Email)? The Person property only resolves if the Guru verifier's email matches a Notion workspace member. The Email property always stores the original value regardless of membership, so you never lose the audit trail.
Automate where possible
If you're building a custom ETL, add assertions to your migration script that compare source and target counts and flag discrepancies before you mark a Collection as complete.
Nesting clarification
The documented 2-level nesting limit applies to a single append request, not to the page itself. Deep content trees are still possible — you must create the top two levels first, capture the returned block IDs, then append deeper levels in subsequent requests. This multiplies API calls significantly but achieves the correct structure. (developers.notion.com)
Guru API rate limits are not publicly documented
Multiple sources confirm Guru enforces rate limits per account but doesn't publish specific numeric thresholds. The API returns HTTP 429 when limits are exceeded. Build in conservative delays (200–300ms between requests) and implement backoff logic.
The runbook
Work top to bottom. Tick steps as you go — your progress is saved in this browser.
01 Discovery Decide what content deserves to move before you plan how to move it.
Objective A content inventory with a keep/rewrite/retire decision on every article and an agreed URL strategy.
Keep these open
-
Inventory all content in Guru
Count articles, categories, attachments, images and embedded media, and pull page views and last-updated dates for each article. Usage data is what makes the next decision defensible rather than political.
Data Profiler Get real record counts instead of estimating from memory -
Make a keep, rewrite or retire call on every article
Most knowledge bases are half stale. Migrating everything imports the staleness and doubles the work; use views and last-updated to triage, and get the owning team to confirm. This usually removes 30-50% of scope.
Migrating stale content is the most common knowledge-base migration mistake — it costs effort and actively degrades the new site.
-
Agree the URL and redirect strategy
Decide the Notion URL structure and whether you can serve 301 redirects from the old paths. Public help centres carry real search traffic and inbound links; losing it is a measurable commercial impact.
Without 301 redirects from old article URLs you lose accumulated search ranking and every external link and bookmark breaks.
-
Map the information architecture
Document the current category tree and design the target one, checking whether Notion supports your nesting depth. Deeply nested hierarchies frequently have to be flattened, which changes navigation for everyone.
-
Confirm permissions, audiences and localisation scope
Establish which content is public, internal or restricted, and how Notion models that. Then confirm how many locales you have and whether translation relationships between articles survive the move.
Don't move on until
- Full content inventory with page views and last-updated dates
- Keep / rewrite / retire decision recorded per article
- URL and redirect strategy agreed with whoever owns SEO
02 Data Audit Audit the markup, the links and the assets — that is where KB migrations break.
Objective A content export with markup, internal links and every embedded asset accounted for.
Keep these open
-
Export content and assess markup fidelity
Export articles in the richest format available and inspect what survived: tables, code blocks, callouts, nested lists, anchors and embedded video. Rich formatting is where fidelity is lost, and it is lost quietly.
HTML-to-Markdown conversion routinely mangles nested lists, tables and code blocks. Inspect the output rather than trusting the converter.
Data Profiler Profile the Guru export for nulls, outliers and type drift -
Inventory every internal link and cross-reference
Extract all internal links, anchor links and article cross-references. These break by default: the target URL structure differs, so every internal link needs rewriting as part of the load, not afterwards.
Internal links left pointing at old URLs turn the new knowledge base into a maze of 404s on day one.
-
Inventory images, attachments and embedded media
List every asset with its URL, size and type, and confirm each still resolves. Assets hosted on the old platform's CDN will 404 the moment you decommission it, so they must be rehosted, not referenced.
Images referenced from the source platform's CDN break when the old account closes. Download and rehost every asset.
-
Find and fix broken links and orphans
Crawl for existing broken internal and external links, and find articles no category links to. Fix them before migrating — a migration is a bad time to discover pre-existing rot.
-
Check for PII and internal information in public content
Scan for customer names, internal hostnames, credentials in code samples and screenshots containing real data. Republishing these on a public help centre is a disclosure, and screenshots are the usual culprit.
PII & Compliance Scanner Find regulated fields before they land in a new system -
Normalise metadata
Standardise authors, tags, timestamps to UTC, and locale codes. Author mapping needs a decision for people who have left — attribution to a deleted user usually fails the import.
Guru → Notion specifics
- Extracts
- verificationState, verificationInterval, lastVerifiedBy, lastVerifiedDate, and nextVerificationDate from every Card via the Guru REST API.
- Block appends
- ~1,000 calls (most Cards fit in one append)
- Link rewriting pass
- ~500 calls (for Cards with internal links)
Don't move on until
- Content exported with markup fidelity assessed
- Every internal link and asset reference inventoried
- Broken links and missing assets fixed or logged
03 Field Mapping Map structure, metadata, permissions and — above all — URLs.
Objective A mapping covering article fields, taxonomy, permissions and a complete old-to-new URL map.
Keep these open
-
Map the article schema
Map title, body, excerpt, author, dates, status, tags, SEO metadata and any custom properties. Confirm which fields Notion lets you set on import versus which it computes — computed dates are a common surprise.
Schema Mapper Opens pre-loaded with the Guru → Notion field pair -
Map the taxonomy and hierarchy
Map categories, sections and tags to the target structure, resolving any nesting-depth limit explicitly. If you must flatten, decide how the lost level is preserved — usually as a tag or a title prefix.
JSON to CSV Converter Flatten nested API responses into a reviewable sheet -
Map permissions and audience segmentation
Map public, logged-in, and role-restricted visibility to Notion's model. Verify the mapping deliberately: internal content accidentally published publicly is the highest-severity failure in this whole category.
Permission mapping errors publish internal documentation to the open web. Verify visibility on every restricted article after load.
-
Build the complete old-to-new URL map
Produce a row per article mapping the old URL to the new one, then confirm exactly where the 301s will be served — Notion, a CDN, or your own web layer. Without this artifact the redirect step cannot be executed at all.
-
Define the markup conversion and link-rewrite rules
Specify how each markup construct converts and how internal links are rewritten using the URL map. Write it as a repeatable transform, not manual edits — you will run it more than once.
Data Format Converter Reshape the export into the format Notion's importer expects -
Plan localisation and freeze the spec
Confirm how translated articles link to their source language in Notion, then version and sign off the mapping spec.
Don't move on until
- Article schema and taxonomy mapped
- Permission and audience model mapped to target equivalents
- Complete URL map produced and redirect method confirmed
04 Test Migration Pilot the hardest articles, then read them.
Objective A pilot load whose formatting, links, assets and search all hold up under human review.
Keep these open
-
Configure Notion with the agreed structure
Create the category tree, permission groups, locales and branding before loading. Articles loaded before their categories exist land uncategorised and have to be moved by hand.
-
Pick the most difficult articles as the pilot
Choose 20-50 articles for difficulty: the longest, the most heavily formatted, ones with tables and code blocks, deep internal linking, many images, embedded video, restricted visibility, and non-Latin scripts. Easy articles prove nothing.
-
Run the conversion and load with link rewriting
Apply the markup conversion, rewrite internal links from the URL map, upload and re-reference assets, then load. Log every conversion warning rather than suppressing it.
-
Read every pilot article side by side
Open source and target together and compare rendering. This step is manual on purpose: no automated check catches a table that collapsed into a paragraph or a code block that lost its indentation.
-
Click every link and load every asset
Verify each internal link resolves, each image loads from the new host, each attachment downloads and each embed plays. Assets still served from the old CDN are the defect that surfaces only after decommissioning.
Migration Validation Tool Diff the pilot batch against source before scaling up -
Test search and permissions
Search for known terms and confirm the right articles rank, then verify every restricted pilot article is invisible to an anonymous browser. Test permissions from a logged-out session, not an admin one.
Don't move on until
- Complex articles render correctly with formatting intact
- Every internal link and asset in the pilot resolves
- Search returns sensible results for the pilot content
05 Cutover Publish, redirect, and keep the search traffic.
Objective All in-scope content live in Notion with redirects serving and search engines informed.
Keep these open
-
Load the full content set ahead of the switch
Run the full conversion and load into Notion, unpublished or on a staging domain. Content migration differs from data migration here: you can stage the whole thing before anyone sees it.
-
Publish the runbook with the redirect step first-class
Sequence the freeze, final delta, publish, redirect activation, sitemap submission and link updates, with owners for each. Redirect activation is the step with lasting commercial consequences, so it gets explicit ownership.
-
Freeze editing and migrate the delta
Stop editing in Guru, then convert and load anything changed since the full load. Announce the freeze to every team that publishes — content teams are used to editing whenever they like.
-
Publish and verify permissions live
Publish the content set, then immediately verify restricted articles are not publicly reachable using an anonymous session. Do this before announcing the new site, not after.
Verify restricted content from a logged-out browser. An admin session will show you everything and tell you nothing.
Migration Validation Tool Confirm the final delta landed before you reopen -
Activate 301 redirects and submit the sitemap
Turn on the redirects from the URL map, then spot-check a sample of high-traffic old URLs and confirm each returns 301 to the right article. Submit the new sitemap and keep the old one reachable until search engines have recrawled.
Redirect chains and redirect loops both leak ranking. Verify each redirect resolves in a single hop.
-
Repoint in-product and support links
Update help links embedded in your product, in support macros, in email templates and in onboarding material. These are the links your existing customers actually use, and they are easy to forget.
Don't move on until
- All content loaded, categorised and correctly permissioned
- 301 redirects live and verified from a sample of old URLs
- Sitemap submitted and support links repointed
06 Validation Watch traffic, links and search rankings for weeks, not hours.
Objective Verified content completeness, healthy redirects, and search traffic recovered to baseline.
Keep these open
-
Reconcile content counts and assets
Compare article counts by category and status, plus asset counts, against source. Confirm every article in the keep list is present and every retired one genuinely is not.
Migration Validation Tool Reconcile Guru and Notion record-for-record -
Crawl the new site for broken links and assets
Run a full crawl for 404s, broken images and missing attachments, and fix everything it finds. Repeat the crawl after the fixes rather than assuming they worked.
-
Verify the redirects at scale
Test every mapped old URL for a single-hop 301 to the right destination. Chains and loops both leak ranking and are invisible unless you check the whole map, not a sample.
-
Monitor organic traffic and rankings for four to eight weeks
Track organic sessions, impressions and rankings for your top articles against baseline. A dip in the first two weeks is normal; one that has not recovered by week six is a redirect or indexing problem to investigate.
Do not decommission the old platform until search traffic has recovered — you may still need the old URLs to diagnose a ranking loss.
-
Verify search, permissions and feedback loops
Confirm on-site search returns good results for real queries, re-verify restricted content from a logged-out session, and check article feedback and analytics are collecting.
-
Sign off and decommission on a delay
Get acceptance against the Discovery criteria, keep Guru available read-only until traffic has recovered, take a final export, and only then close the account.
Guru → Notion specifics
- Resolves
- the verifier's email against the Notion workspace user list. If the email matches a workspace member, we populate the Person property. If it doesn't, we leave the Person property empty and populate the Verifier Email (Email) property as a fallback.
- No verification history
- Guru's API returns only the current verification state — the most recent verification event. If a Card has been verified multiple times, previous verifiers and dates are not available via the API. Only the latest verificationState, lastVerifiedBy, and lastVerifiedDate migrate.
- Unmapped verifiers
- If the Guru verifier's email does not correspond to a Notion workspace member, the Person property will be empty. Workaround: Always populate a separate Verifier Email (Email) property with the raw email address so the audit trail is preserved regardless of Notion membership.
- Archived Cards
- Guru's Collection export does not include archived Cards. If you restore archived Cards before extraction and pull them via the API, confirm whether the verificationState field is still populated — verification metadata on long-archived Cards may reflect the state at the time of archival, which could be stale.
- Verification workflow is not migrated
- Guru's automated trust-score decay, expiry-triggered notifications, and scheduled re-verification reminders have no Notion equivalent. The data (status, dates, interval) transfers, but the workflow must be rebuilt using Notion database automations, formula properties, or external reminder tools.
Don't move on until
- Article counts reconciled and no broken links remain
- Redirects returning 301 with no chains or loops
- Organic traffic recovered to within tolerance of baseline
Field mapping reference
The field-by-field mapping for each object. Use this as the starting point for your mapping spec.
Object Equivalent
| Guru field | Notion field | Notes |
|---|---|---|
| Collection | Top-level Page or Teamspace | One Notion page per Collection |
| Folder | Nested Page | Folders become child pages; preserve the hierarchy |
| Card | Page (under parent Folder page) | Card HTML → Notion blocks |
| Card Tags | Multi-select property | If Cards land in a Notion database |
| Verification Status | Status property | Map TRUSTED → Verified, NEEDS_VERIFICATION → Needs Review |
| Card Owner / Verifier | Person property | Requires mapping Guru user emails to Notion user IDs |
| Board / Board Group | Database View or Linked View | Boards are visual groupings; recreate as filtered database views |
Guru Guru Type
| Guru field | Notion field | Notes |
|---|---|---|
| preferredPhrase (Title) | String | Direct map |
| content | HTML | Parse HTML → Notion block JSON or Markdown |
| collection.name | String | Map to Collection grouping |
| tags | Array of strings | Direct map; normalize case |
| verificationState | Enum | Map TRUSTED → Verified |
| owner.email | String | Resolve to Notion user ID |
| dateCreated | ISO 8601 | Direct map |
| lastModified | ISO 8601 | Auto-populated by Notion |
| lastVerifiedDate | ISO 8601 | Custom "Last Verified" property |
| Card ID | String | Preserve as stable deduplication key |
| Attached files | CDN URLs in HTML | Download → re-upload |
| Internal Card Links | Guru URLs | ID mapping + rewrite in second pass |
Property Name Property Type
| Guru field | Notion field | Notes |
|---|---|---|
| Title | Title | Card name |
| Guru Card ID | Text | Stable deduplication key |
| Verification Status | Status | Options: "Verified" (← TRUSTED), "Needs Review" (← NEEDS_VERIFICATION) |
| Last Verified Date | Date | ISO-8601 from Guru |
| Verifier | Person | Mapped to Notion workspace member; see limitations below |
| Verifier Email (Fallback) | Always populated — serves as fallback when Person property can't resolve | |
| Verification Interval | Number | Days between scheduled reviews |
| Next Review Date | Date | Alternatively, use a Formula: Last Verified Date + Verification Interval days |
| Source Collection | Select | Original Guru Collection |
| Tags | Multi-select | Direct map; normalize case |
Risk matrix
Per-object risk for this pair. Plan extra validation around anything marked high.
| Object | Risk | Notes |
|---|---|---|
| Internal Card Links | high | All Guru URLs break without a Card ID → Notion Page ID mapping |
| Verification Workflows | high | No Notion equivalent — must rebuild with automations |
| Section Deep Links | high | Notion does not reliably preserve anchor links |
| Comments & Activity Log | high | No migration path for historical Card comments |
| Board / Board Groups | medium | Must be recreated as filtered database views in Notion |
| File Attachments | medium | Guru CDN URLs may expire — must download and re-upload |
| Folder Hierarchy | medium | Guru's 3-level folder nesting must be mapped to Notion pages |
| Card HTML Content | medium | Complex tables and callouts may lack direct Notion equivalents |
| Tags / Metadata | low | Map directly to Notion multi-select properties |
| Card Titles | low | Direct mapping to Notion page titles |
The hard parts
What makes this specific migration difficult, beyond the mechanics.
HTML-to-Block Parsing
Guru Cards are HTML. Notion expects block-level JSON objects. Every Card must be decomposed into individual blocks with strict size and nesting constraints.
Block Chunking
Notion limits appends to 100 blocks per request with a 500KB payload cap. Long Cards require multiple sequential API calls.
Rate Limit Management
Notion enforces 3 requests per second per integration token. A 1,000-Card migration requires 2,500+ API calls minimum.
Internal Link Rewriting
Every Guru Card URL must be rewritten to the corresponding Notion page link using a two-pass ID mapping approach.
Base64 Image Extraction
Inline base64 images in Guru Cards can exceed Notion's 500KB payload limit and must be extracted and externally hosted.
Tools used in this playbook
All free, all run entirely in your browser — nothing is uploaded.
FAQ
Can I import Guru data directly into Notion?
There is no native Guru-to-Notion importer. You can export Guru Collections as ZIP files with HTML content, convert to Markdown, then import via Notion's Settings → Import → Text & Markdown. Internal links, attachments, and folder hierarchy will not be preserved automatically. CSV imports do not carry relations, rollups, or formulas.
What Notion API limits matter most during migration?
Notion enforces an average of 3 requests per second per integration token (approximately 2,700 requests per 15-minute window). Block appends are limited to 100 children per request with a 500KB payload cap. Nesting is limited to 2 levels per single append request. Rich text objects max out at 2,000 characters. Rate-limited requests return HTTP 429 with a Retry-After header.
How do I handle deeply nested Guru content in Notion's API?
Notion's 2-level nesting limit applies per single append request, not per page. Deep content trees are achievable by creating the top two levels first, capturing returned block IDs, then appending deeper children in subsequent API calls. This multiplies API calls but produces the correct nested structure.
Does Guru have API rate limits for data extraction?
Yes, Guru enforces rate limits per account, but specific numeric thresholds are not publicly documented. The API returns HTTP 429 when limits are exceeded. Build in conservative delays (200–300ms between requests) and implement backoff logic.
How long does a Guru to Notion migration take?
For small teams with under 200 Cards using the manual ZIP export path, expect 1–2 days including cleanup. For API-based migrations of 1,000+ Cards, the engineering effort is 2–4 weeks for script development, testing, and validation. A managed migration service typically completes in days.