Power tools for the Notion API

notion-helper is a Node.js library that makes working with the Notion API a breeze.

Easy to learn, zero dependencies, open-source, full JSDoc for IntelliSense.

Built by Thomas Frank.

Let's say you've got a JSON object that you want to turn into a page in a Notion database.

const album = {
    name: "A Pretty Face to Ruin Everything",
    artist: "Airplane Mode",
    release_date: "03/14/2020",
    cover: "https://i.imgur.com/d3BBFhF.jpeg",
    tracks: [
        "When the Lights Go Out",
        "West Coast",
        "Candy Store",
        "Pedestal",
        "She's Asleep",
        "The Ledge, Pt. 1",
        "Anastasia",
        "For the Moment",
        "I Know",
        "While My Guitar Gently Weeps",
        "The Ledge, Pt. 2",
        "Both Can Be True",
        "Forever, Again",
        "Everlong",
    ],
};
const album = {
    name: "A Pretty Face to Ruin Everything",
    artist: "Airplane Mode",
    release_date: "03/14/2020",
    cover: "https://i.imgur.com/d3BBFhF.jpeg",
    tracks: [
        "When the Lights Go Out",
        "West Coast",
        "Candy Store",
        "Pedestal",
        "She's Asleep",
        "The Ledge, Pt. 1",
        "Anastasia",
        "For the Moment",
        "I Know",
        "While My Guitar Gently Weeps",
        "The Ledge, Pt. 2",
        "Both Can Be True",
        "Forever, Again",
        "Everlong",
    ],
};
A Notion database page with the album's information.
A Notion database page with the album's information.
A Notion database page with the album's information.

notion-helper's createNotion() function allows you to build page objects with far less code.

It'll create multiple blocks from an array with loop(), handle date strings for you, and a lot more.

With notion-helper:

// Install the package

npm install notion-helper

// Use it in your code

import { createNotion } from "notion-helper";

const page = createNotion()
    .parentDb(database_id)
    .title("Name", album.name) // prop name, value
    .richText("Artist", album.artist)
    .date("Released", album.release_date)
    .heading1("Tracklist")
    .loop("numbered_list_item", album.tracks)
    .heading1("Album Art")
    .image(album.cover)
    .build(); // call build() at the end of the chain

// Send page.content as the request body
const response = notion.pages.create(page.content);
// Install the package

npm install notion-helper

// Use it in your code

import { createNotion } from "notion-helper";

const page = createNotion()
    .parentDb(database_id)
    .title("Name", album.name) // prop name, value
    .richText("Artist", album.artist)
    .date("Released", album.release_date)
    .heading1("Tracklist")
    .loop("numbered_list_item", album.tracks)
    .heading1("Album Art")
    .image(album.cover)
    .build(); // call build() at the end of the chain

// Send page.content as the request body
const response = notion.pages.create(page.content);

Without notion-helper:

const listItems = album.tracks.map((item) => ({
    numbered_list_item: {
        rich_text: [
            {
                text: {
                    content: item,
                },
            },
        ],
    },
}));

function getISODate(dateString) {
    return new Date(dateString).toISOString();
}

const page = {
    parent: {
        database_id: database_id,
    },
    properties: {
        Name: {
            title: [
                {
                    text: {
                        content: album.name,
                    },
                },
            ],
        },
        Artist: {
            rich_text: [
                {
                    text: {
                        content: album.artist,
                    },
                },
            ],
        },
        Released: {
            date: {
                start: getISODate(album.release_date),
            },
        },
    },
    children: [
        {
            heading_1: {
                rich_text: [
                    {
                        text: {
                            content: "Tracklist",
                        },
                    },
                ],
            },
        },
        ...listItems,
        {
            heading_1: {
                rich_text: [
                    {
                        text: {
                            content: "Album Art",
                        },
                    },
                ],
            },
        },
        {
            image: {
                external: {
                    url: album.cover,
                },
            },
        },
    ],
};

const response = notion.pages.create(page);
const listItems = album.tracks.map((item) => ({
    numbered_list_item: {
        rich_text: [
            {
                text: {
                    content: item,
                },
            },
        ],
    },
}));

function getISODate(dateString) {
    return new Date(dateString).toISOString();
}

const page = {
    parent: {
        database_id: database_id,
    },
    properties: {
        Name: {
            title: [
                {
                    text: {
                        content: album.name,
                    },
                },
            ],
        },
        Artist: {
            rich_text: [
                {
                    text: {
                        content: album.artist,
                    },
                },
            ],
        },
        Released: {
            date: {
                start: getISODate(album.release_date),
            },
        },
    },
    children: [
        {
            heading_1: {
                rich_text: [
                    {
                        text: {
                            content: "Tracklist",
                        },
                    },
                ],
            },
        },
        ...listItems,
        {
            heading_1: {
                rich_text: [
                    {
                        text: {
                            content: "Album Art",
                        },
                    },
                ],
            },
        },
        {
            image: {
                external: {
                    url: album.cover,
                },
            },
        },
    ],
};

const response = notion.pages.create(page);

createNotion() has other tricks up its sleeve, too…

Add supported options to blocks, like colors or a children array. In rich_text, build a rich text object from scratch with custom annotations.

Look familiar? Every block method can accept an object with the same property names from the Notion API itself. Here's an example.

Add supported options to blocks, like colors or a children array. In rich_text, build a rich text object from scratch with custom annotations.

Look familiar? Every block method can accept an object with the same property names from the Notion API itself. Here's an example.

import { createNotion, buildRichTextObj } from "notion-helper";

const page = createNotion()
    .parentDb(database_id)
    .title("Name", album.name)
    .heading1({
        rich_text: buildRichTextObj(
            "Tracklist",
            {
                color: "red",
                italic: true,
            }
        ),
        color: "green_background",
    })
    .build();

Add child blocks to any supported block by defining it with startParent(). This lets you build tables!

Pass a callback to loop() instead of a block type to define custom handling.

P.S. – See the number in that tracks object? Normally, the API will pitch a fit if you try to put that in a table cell. But notion-helper will just coerce it to a string for you. 🧶

import { createNotion } from "notion-helper";

const album = {
    name: "Mandatory Fun",
    artist: `"Weird Al" Yankovic`,
    release_date: "07/15/2014",
    tracks: [
        {
            "No.": 1,
            Title: "Handy",
            "Writer(s)":
                "Amethyst Kelly\nCharlotte Aitchison...",
            Length: "2:56",
        },
        /* ...more tracks... */
    ],
};

const page = createNotion()
    .parentDb(database_id)
    .title("Name", album.name)
    .heading1("Tracklist")
    .startParent("table", {
        has_column_header: true,
        rows: [["No", "Title", "Writer(s)", "Length"]],
    })
    .loop((page, track) => {
        page.tableRow([
            track["No."], track.Title, track["Writer(s)"], track.Length
        ])
    }, album.tracks)
    .endParent()
    .build();

The Notion API only supports 100 blocks in any block array sent in a single request.

createNotion() returns an additionalBlocks property with additional block chunks. Loop over this with Append Block Children calls to build pages with hundreds or thousands of blocks.

import { createNotion } from "notion-helper";

// Build a transcript array with 300 lines
const transcript = []

for (let i = 0; i < 300; i++) {
    const line = `This is sentence #${i}.`
    transcript.push(line)
}

// Create the page in Notion
const page = createNotion()
    .parentDb(database_id)
    .title("Name", "Long Transcript")
    .loop("paragraph", transcript)
    .build()

const pageResponse = await notion.pages.create(page.content)

for (let chunk of page.additionalBlocks) {
    const appended = await notion.blocks.children.append({
        block_id: pageResponse.id,
        children: chunk
    })
}

createNotion() can build full page objects, or it can go more granular and return a property object or an array of blocks you can use in a children property.

Simply add parentDb(), parentPage(), pageId(), or blockId() to the chain to create a page/block object.

Add only property methods to return a property object. (Examples: title(), richText(), relation(), date()…)

Add only block methods to return an array of blocks. (Examples: heading1(), paragraph(), bulletListItem()…)

import { createNotion } from "notion-helper";

// Create full page objects with a parent property, for page creation...
const page = createNotion().parentDb(database_id);

// or
const page = createNotion().parentPage(page_id);

// Create a page object with a page_id property, for updating props or doing reads...
const page = createNotion().pageId(page_id);

// Create a block object with a block_id property,
// for updating blocks or appending children...
const block = createNotion().blockId(block_id);

// Create a property object
const props = createNotion().title("Name", "Page title");

// Create an array of blocks
const blocks = createNotion().heading1("This is a heading")
    .paragraph("This is a paragraph!")

createNotion() includes methods for building/setting any kind of supported object, property, or block. It also includes some generic methods for fine-grained control.

Property Methods:

  • property(name, type, value)

  • title(name, value)

  • richText(name, value)

  • checkbox(name, value)

  • date(name, start, end)

  • email(name, value)

  • files(name, fileArray)

  • multiSelect(name, valuesArray)

  • number(name, value)

  • people(name, personArray)

  • phoneNumber(name, value)

  • relation(name, pageArray)

  • select(name, value)

  • status(name, value)

  • url(name, value)

Block Methods:

  • addBlock(blockType, options)

  • startParent(blockType, options)

  • endParent()

  • paragraph(options)

  • heading1(options)

  • heading2(options)

  • heading3(options)

  • bulletedListItem(options)

  • bullet(options) - alias function

  • numberedListItem(options)

  • num(options) - alias function

  • toDo(options)

  • toggle(options)

  • code(options)

  • quote(options)

  • callout(options)

  • divider()

  • image(options)

  • video(options)

  • file(options)

  • pdf(options)

  • bookmark(options)

  • embed(options)

  • tableOfContents(options)

  • table(options)

  • tableRow(options)

  • loop(blockTypeOrCallback, options)

Page/Block Object Methods:

  • parentDb()

  • parentPage()

  • pageId()

  • propertyId()

  • blockId()

  • cover()

  • icon()

Utility Methods:

  • build() - creates the final object.

  • reset() - resets the builder.

Need more control? Import the other functions.

notion-helper is a ground-up library that offers syntactic sugar at multiple levels. Everything at the highest levels (like createNotion() or quickPages()) builds off the lower-level functions.

This also means notion-helper truly is a helper for the Notion API, not a replacement SDK. It simply helps you build things with less code - page objects, blocks, properties, rich text objects, etc.

It's designed for use with the official SDK, which you should use for making your calls (or you can use fetch or something else).

Build rich text objects from the ground up by importing buildRichTextObj, then passing a string (or objects for Mentions). Optionally pass an annotation object, URL, and type.

import { buildRichTextObj } from 'notion-helper'

const line = "I will be king of the pirates!"

const richText = buildRichTextObj(line)

const higlighted = buildRichTextObj(line, { color: "yellow_background" })

const linked = buildRichTextObj(line, {}, "https://en.wikipedia.org/wiki/Monkey_D._Luffy")

// Or build equations

const equation = "\frac{{ - b \pm \sqrt {b^2 - 4ac} }}{{2a}}"

const richEquation = buildRichTextObj(equation, {}, null, "equation")

Build blocks by importing block. This object exposes a createBlock() method for each supported block type.

Each block type also has a shorthand function you can import.

import { block } from 'notion-helper'
import { buildRichTextObj } from 'notion-helper'

const image = "https://i.imgur.com/5vSShIw.jpeg"

const imageBlock = block.image.createBlock(image)

// or add a caption...

const captionedImageBlock = block.image.createBlock({
    url: image,
    caption: "A dog wearing sunglasses"
})

// caption coerces to rich text, but you can also pass your own!
// buildRichTextObj() always returns an array, so make use of flat()

const richCaptionedImageBlock = block.image.createBlock({
    url: image,
    caption: [ 
        buildRichTextObj(
            "A dog wearing sunglasses ",
        ),
        buildRichTextObj(
            "(Source)",
            {},
            "https://i.imgur.com/5vSShIw.jpeg"
        )
    ].flat()
})

// block.image.createBlock() feel too verbose? Import the shorthand function!
// Every block has one, and they have the same names as the methods in createNotion()
import { image } from 'notion-helper'

const anotherImageBlock = image(image)

// You can also just import NotionHelper to get all the methods, and to preserve a separate namespace

import NotionHelper from 'notion-helper'

const thirdImageBlock = NotionHelper.image(image)

Build property value or page meta objects by importing page_props and page_meta respectively.

page_props exposes setProp() methods for writeable properties.
page_meta exposes createMeta() methods for create parent, page_id, block_id, property_id, cover, and icon objects.

As with blocks, there are shorthand methods you can import.

import { page_props, page_meta } from 'notion-helper'

// Create a parent database object:

const database_id = "41e42f70a1ec4a6c917045f4ed6c930a"

const parent = page_meta.parent.createMeta({
    id: database_id,
    type: "database_id"
})

// Or do it faster wth a shorthand function

import { parentDb } from 'notion-helper'

const parent = parentDb(database_id)

// Set a date property's value:

const startDate = "09/13/2024" // MM/DD/YYYY dates get auto-converted!

const dateProp = page_props.date.setProp(startDate)

// Or do it faster with a shorthand function,
// and pass an end date while you're at it

import { date } from 'notion-helper'

const endDate = "09/17/2024"

const dateProp = date(startDate, endDate)

Don't understand the Notion API quite yet?

No worries, watch this free crash course and you'll be building your own automations in in no time.

notion-helper will make it easier to work with the Notion API, but it's still very helpful if you understand how it the API works.

Made with 🍚 and 🌮 and other stuff by Thomas Frank