Creating Notion pages from a template with the API

Notion quietly shipped an amazing upgrade to the public API in October. For me, this is a FOTY (Feature of the Year) candidate! Released alongside versions 5.2.0 and 5.3.0 of the SDK, you can now apply a template when creating and updating pages via the API.

The amazing thing about this addition is that it completely works with Linked views of data sources. The inability to create Linked views via the API was my #1 blocker for creating my own templating system, so this opens up so many opportunities for coders!

Note: if you just want the example code, check the “templates” example folder in my Notion API examples repository.

Listing templates

Templates are associated with a Data Source. You can fetch a data source with the API and then use listTemplates to fetch a list of its associated templates. 

If you’re not sure what a Data Source is, well, it used to be called a Database. Now Databases can have more than one Data Source in their container. If you used to fetch a Database via the API, now you’ll find the Data Sources with the Database payload. If you have a “source” Database, with a single Data Source in it, here’s how you’d accomplish fetching it and getting a list of its templates using the latest version of the API.

				
					  const { data_sources: dataSources } = await notion.databases.retrieve({
    database_id: '1e7abab87ee8457799c1155cf69d502a',
  });

  const dataSource = await notion.dataSources.retrieve({
    data_source_id: dataSources.at(0).id,
  });

  const { templates } = await notion.dataSources.listTemplates({
    data_source_id: dataSource.id,
  });
				
			

Here’s an example value for  templates in the above code. You can see that one of my templates has is_default true which means its the default template for this data source.

				
					[
  {
    "id": "e8007a4a-9a02-45c5-bb87-544ff7a6e8b3",
    "name": "Untitled",
    "is_default": true
  },
  {
    "id": "1861c1cc-e3f3-80bf-8823-f701d4e7a2c1",
    "name": "Album",
    "is_default": false
  },
  {
    "id": "28b1c1cc-e3f3-80a3-9327-c9d8a176a4e8",
    "name": "with linked view",
    "is_default": false
  }
]
				
			

Creating pages with templates

The create pages endpoint is what we use to create from a template. But now you’re going to pass a value for template alongside your page properties.

				
					 const params = {
    parent: {
      type: 'data_source_id',
      data_source_id: dataSource.id,
    },
    properties: {
      Name: {
        title: [
          {
            text: {
              content: 'Example page',
            },
          },
        ],
      },
    },
    template: {
        type: 'template_id',
        template_id: templates.at(0).id,
    },
  };

  const page = await notion.pages.create(params);
				
			

The template parameter is an object that an minimum must have a type. In the case above we’re using a specific template by ID.

We can use three different options for template[type] which is a string:

  1. template_id – if using this type, you must also supply the template_id as shown above
  2. default – use the default template as defined on the data source
  3. none [default] – do not apply a template

Property precedence

Similar to the application, any properties you pass with the original request will be preserved, overriding the properties present in the template. For example, if you have a default set of “Tags” in a multi-select, you can pass those tags in with the properties to override them (even creating new options in the process).

Checking for template application

Just like in the application when we duplicate a template, template application is asynchronous. Meaning when you get a result back from notion.pages.create none of the properties, page cover, icon, etc. will be applied yet. 

In order to know when your template has fully applied, you will need to leverage webhooks. For most folks this won’t be necessary, but if you are building an integration or app that relies on knowing a template is “ready to go”, this extra step will help.

The best practice is to listen for two webhook events.

  1. page.created – Sent when the page is initially created. You can store the ID of the page on your end at this point.
  2. page.content_updated – Sent when the page’s content is updated. At this point you can assume the template has been applied since it would update the page’s body. 

Once you’ve “heard” these webhook events, you’re pretty much guaranteed that the template has fully been applied. You may want to check for the presence of key page blocks if they are required for operation, but, for the most part, this is sufficient for the vast majority of use-cases.

There’s lots more information in Notion’s official guide for this if you think it’ll be a concern for your application.

Updating pages with templates

In the 5.3.0 version of the SDK, the pages.update endpoint was also updated to include the template parameter. If works mostly the same as the pages.create endpoint, but you cannot use the "none" type for the template value (not passing a value for template is the same). 

As well as the new template parameter, you can also send through a boolean value for erase_content. This will wipe all the content from the body of the page. 

Be careful using this one as it will delete all contents of the page as expected. If you leave this one off or pass false, the template applied will append to the page body. This can be good for keeping any content you wrote manually or previously an apply the template content below it.

				
					  const params = {
    page_id: '28e1c1cce3f3801fb861f1cf847a861a',
    template: { type: 'default' },
    erase_content: true
  };

  const page = await notion.pages.update(params);
				
			

Sourcing templates (advanced)

One cool (possibly removed at some point) side-effect of this change…

template_id does not currently have to be the ID of a template in a data source. You can use the ID of another page in the database to create a duplicate of it.

In fact, It doesn’t even have to be the ID of a page in a data source. Any page in your Notion workspace that the bot (or integration token) has access to can be used as the source. You can even use templates from other data sources!

Note: I would recommend being very careful with this as copying pages from database to database can have odd effects with property merging.

Can I use this with my automation platform??

So how can you use this with Make or Zapier?

This is dependent on the platforms adding support for the template parameter. For example Zapier’s current Create Data Source Item action does not support this yet. So you’ll have to use something different.

  • Zapier – use the Webhooks by Zapier action to send a POST request to the Notion API.
  • Make – use the HTTP – Make a Request module or the Notion – Make an API Call module to send a POSTrequest to the Notion API

Share This Post

Email
LinkedIn

Get 🔥 Notion tips in your inbox

When you sign up, you’ll get tips, perspectives, and opinions on how you can better use Notion. Plus you’ll get a steady drip of Notion updates, videos, interviews, and resources from the Notion Mastery team.

Master your life and business workflows with Notion.