Home

Write Notion Page and Block Data to JSON File with Node.js Script

Write a Node.js script that connects to a Notion database and writes its page and block content to a local JSON file.

This is part of a four-part series on showing the potential of Notion as a CMS for complex websites:

  1. Using Notion Callouts to Generate Complex Components
  2. Accessing a Notion Database Using the API
  3. Write Notion Page and Block Data to JSON File with Node.js
  4. Transform Notion API Data into Component-Ready JSON

We're going to write a Node.js script that fetches pages from a Notion database and writes the result to a JSON file.

Because block information is not included in the page list response, we'll adjust the script to fetch blocks for each page and store them in a children property on the page object, before writing the end result to a JSON file.

Prerequisites

You'll need the following for this tutorial:

  • A database with a few pages, where at least one of the pages has some content (a few blocks). If you don't have a database, feel free to copy mine.
  • Notion integration with a connection established. This process is explained in the previous post in the series.
  • The id property of the database from Notion's API. This is not retrievable from the database's URL. This process is also covered in the previous post.
  • Blank Node.js script and a way to run the script.
  • The secret token from the Notion integration and a way to store environment variables. If you don't have environment variables

Setup Script

Make sure you have a blank file to add your script. Then there are just a couple other quick setup tasks.

Install Dependencies

We're going to install the Notion JavaScript SDK so that we can easily interact with their API.

npm install @notionhq/client

Add Environment Variables

Add the following environment variables, which should be accessible by the script:

  • NOTION_DATABASE_ID: The id property from the Notion database, retrieved via the API.
  • NOTION_API_KEY: Secret token from the Notion integration,

Retrieve Pages and Write to File

First, let's write a script that simply retrieves the pages from the database and writes them to a notion-export.json file in the same directory as the script.

const { Client } = require("@notionhq/client");
const fs = require("fs");
const path = require("path");

const notion = new Client({ auth: process.env.NOTION_API_KEY });

async function importPages() {
// Retrieve pages from the database.
let { results: pages } = await notion.databases.query({
database_id: process.env.NOTION_DATABASE_ID,
});

// TODO -> Attach blocks to pages

// Write the result to file.
const outputFile = path.join(__dirname, "notion-export.json");
fs.writeFileSync(outputFile, JSON.stringify(pages, null, 2));
console.log(`Wrote ${pages.length} pages to ${outputFile}`);
}

importPages();

After running the script, you should see a new notion-export.json file in the same directory as the script.

Open it up to inspect the results. Notice that it seems fairly sparse for how much information Notion likely has about a page. That will change when we add blocks to pages.

Attach Blocks to Pages

The script that retrieves the pages likely ran super fast. It only hit the database a single time. But, for blocks within a page, we have to call the API for every page, and again for every block with children.

warning

I recommend trying this on a small scale first. Use a database with a small number of pages, and pages with a small number of blocks. Your approach and code will likely have to change as your databases scale.

Here's the full script:

const { Client } = require("@notionhq/client");
const fs = require("fs");
const path = require("path");

const notion = new Client({ auth: process.env.NOTION_API_KEY });

async function getBlocks(block_id) {
let { results: children } = await notion.blocks.children.list({ block_id });
for (const child of children) {
const grandchildren = await getBlocks(child.id);
child.children = grandchildren;
}
return children;
}

async function importPages() {
// Retrieve pages from the database.
let { results: pages } = await notion.databases.query({
database_id: process.env.NOTION_DATABASE_ID,
});

// Attach blocks to pages
for (const page of pages) {
const blocks = await getBlocks(page.id);
page.children = blocks;
}

// Write the result to file.
const outputFile = path.join(__dirname, "notion-export.json");
fs.writeFileSync(outputFile, JSON.stringify(pages, null, 2));
console.log(`Wrote ${pages.length} pages to ${outputFile}`);
}

importPages();

Run it again and if your pages have blocks, you'll likely see a lot more content in the JSON file.

Example Code

Here is an example project with this code.


If you're following the four-part series, Part 4 is the next and final step of the process, which takes this raw content and transforms it into a more usable object.

Let's Connect

Keep Reading

Using Notion Callouts to Generate Complex Components

Exploring a theoretical approach to enabling Notion to serve as a CMS for complex websites with interactive components.

Mar 31, 2023

Transform Notion API Data into Component-Ready JSON

Take raw JSON output from the Notion API and transform it into properties that can be used by your website’s pages and components.

Apr 03, 2023

How I Begin New JavaScript Projects

These are the first steps I take when I start a new JavaScript project.

May 26, 2021