Migrating from Quip to Notion requires moving both document content and the comments attached to each document. Notion does not offer a direct Quip importer, so you must build a custom pipeline. This article explains how to export Quip data, transform it for Notion, and import comments using Notion’s API. By the end, you will have a repeatable process that preserves your team’s discussion history.
Key Takeaways: Quip-to-Notion Migration With Comments
- Quip Export > CSV + HTML: Export all documents and threads to obtain content and comment metadata.
- Notion API > Create Page: Use the Create Page endpoint to insert document content as Notion blocks.
- Notion API > Append Block Children: Add comment blocks after the document body using the Append Block Children endpoint.
- Rate Limit Handling: Insert a 1-second delay between API calls to avoid hitting Notion’s 3 requests per second limit.
Why a Custom Pipeline Is Necessary for Quip Migration
Quip stores documents and comments in a proprietary format that Notion cannot parse natively. Notion’s built-in importers support CSV, HTML, Markdown, and other common formats, but they do not recognize Quip’s export structure. To migrate comments, you must extract them from Quip’s thread export, map each comment to its parent document, and insert them as separate blocks in Notion. The pipeline uses Quip’s export API to download all data, a Python script to transform the data into Notion API requests, and batch processing to stay within rate limits.
What You Need Before Starting
You need a Quip account with admin privileges to export all documents and threads. You also need a Notion integration token from the Notion Integrations page. A basic understanding of Python and REST APIs is required. Install Python 3.8 or later and the requests library. Prepare a Notion database where each imported document becomes a page.
Steps to Build the Import Pipeline
- Export Quip Data
Go to Quip Admin Console > Export. Select Export All Data. Choose the JSON format. Wait for the export to complete. Download the archive. It contains folders for each document and a threads.json file with comment data. - Parse the Export Archive
Extract the archive. Open threads.json. Each thread object has a thread_id, title, html (document content), and comments array. Each comment object has author_id, created_at, and text. Store this data in a Python dictionary keyed by thread_id. - Create a Notion Integration
Go to Notion Integrations page. Click New Integration. Name it Quip Importer. Select the workspace. Copy the Internal Integration Secret token. Share the target database with the integration by opening the database page, clicking Share, and adding the integration name. - Write the Python Script
Create a new Python file. Import requests and json. Define the Notion API base URL as https://api.notion.com/v1. Set headers with Authorization: Bearer YOUR_TOKEN and Content-Type: application/json. Set Notion-Version to 2022-06-28. - Create a Page for Each Document
Loop through each thread in threads.json. Build a JSON payload for the Create Page endpoint. Set parent.database_id to your target database ID. Set properties.title.title[0].text.content to the thread title. Set children to an array of block objects converted from the thread HTML. Use Notion’s block types: paragraph, heading_1, heading_2, heading_3, bulleted_list_item, numbered_list_item, and to_do. Send a POST request to /pages. Store the returned page ID. - Migrate Comments
After creating the page, loop through the thread’s comments array. For each comment, build a block object of type paragraph with the comment text. Append a callout block with the author name and timestamp as rich_text. Send a PATCH request to /blocks/{page_id}/children with the comment blocks in the children array. This adds the comments below the document content. - Handle Rate Limits
Add a time.sleep(1) call after each API request. Notion allows 3 requests per second. A 1-second delay ensures you stay under the limit. For large exports, consider batching requests and using exponential backoff on 429 responses. - Run the Script and Verify
Execute the Python script. Monitor the console output for errors. Open the target Notion database. Confirm each page contains the document content followed by comment blocks. Check a few comments to ensure the author name and timestamp appear correctly.
Common Issues During Quip-to-Notion Migration
Quip HTML Contains Unsupported Tags
Quip exports include HTML tags like
Comments Not Appearing in the Correct Order
The comments array in threads.json is ordered by creation time ascending. If you append comments in the same order, they appear chronologically. If the order is wrong, sort the comments array by created_at before building the block list.
Rate Limit Errors (HTTP 429)
Notion returns 429 Too Many Requests when you exceed 3 requests per second. Increase the delay to 1.5 seconds or implement a retry loop. Use the Retry-After header value to wait the required time before retrying.
Page Creation Fails Due to Invalid Block Structure
Notion requires a valid block object for each child. Missing required fields like type or paragraph.rich_text cause a 400 error. Validate each block object against Notion’s block schema before sending the request. Use the Notion API playground to test sample payloads.
Notion API Methods for Migration Compared
| Item | Create Page | Append Block Children |
|---|---|---|
| Endpoint | POST /pages | PATCH /blocks/{block_id}/children |
| Purpose | Creates a new page in a database with initial content | Adds blocks to an existing page or block |
| Payload size limit | 4 MB | 4 MB per request |
| Rate limit | 3 requests per second | 3 requests per second |
| Best for | Inserting the main document body | Adding comments after the body |
You now have a working pipeline to migrate Quip documents and comments into Notion. Run the script on a small test set first to confirm the HTML conversion and comment placement. After validation, process the full export. To improve the pipeline, add error logging to a file and resend failed requests automatically. For very large exports, split the threads.json into batches of 50 threads to reduce memory usage.