Linktree clone using Notion API and Next js
Tags: nextjs, node, javascript, api
Published: 2021-10-06 10:07:30

Hello friends,
In this small series, we will be building something similar to linktree. Using Notion API to fetch the data out of a Notion page and displaying it on Next Js. 
By using notion page as the data source, user(you) can leverage the features that notion app provides, such as - Easily adding, removing and updating content, and even re-ordering the links(blocks). In the end, we will be deploying it on Vercel.



Pretty exciting, right?

![Using Notion page as datasource](https://ik.imagekit.io/tyfldsi6ql9s/linktree-notion-ss_UEKAQVW8Gyy.png?updatedAt=1633506376067)

This is a written tutorial for the [Notion API with NextJS. Linktree Clone](https://bit.ly/3adpXqh) youtube series

By the end, you will learn how to consume data out of a notion page and use it anyway, for this tutorial we will be using next js.
I prefer keeping things short and simple, so it is assumed that you know what Notion is and have a very basic level understanding of Next js.



## Step 1: Creating a Notion Page

The first thing we need is a notion page, which will be used as the data source.
In order for you to easily get started, you can duplicate [this template](https://utopian-suggestion-c65.notion.site/Desi-Codes-links-41b0bff4653b4b98ae7c7f1d3a740eaf)
Or use the button on the left to create a new page.

**!! While replacing or adding the image block(first block), make sure to use the 'embed' image option, instead of upload, as Notion provides access for only 60min for uploaded images, so it's better to use an external one, more on this later.**



## Step 2: Creating a new notion integration

In order for you to interact with this page using the Notion api, you need to have an Integration, which has access to this specific page.

1) Goto notion app
2) Click on 'Settings and Members' button on the left
3) Click on 'Integrations' (last button on the opened modal)
4) Click on 'Develop your own integrations'
5) Click on 'New Integration' and give it any name
6) After submitting keep the secret key at some place, as we will later set it as an environment variable in our next js project.
7) After creating the integration, now we just need to share the access of our page to this specific integration. So on the notion page, on right side top, click on 'share' button and 'invite' the new integration(it should be visible as an option). After which you are done!

If you duplicated the template, you're good to go, otherwise you'll need to add some links and image manually(again, make sure that the image is an embedded one and not uploaded)

## Step 3: Creating Next js project

Now we need to create a next project.

```javascript
npx create-next-app linktree-notion
```

In order to use the Notion API, we are going to use the Js SDK

```javascript
npm i @notionhq/client
```

The next thing that we need to do is to add 2 environment variables to our project
1) Notion Secret (Step 2, point 6)
2) Page ID

We need the id of the page which we want to use the data source, it's pretty simple, just open that page on browser, and the last segment of the url is the page id
![Notion page id](https://ik.imagekit.io/tyfldsi6ql9s/notion_page_id_AT-PFNTm5.png?updatedAt=1633509241368)

Create an .env file in the root of your project and add these two.
It should look something like this

![.env file](https://ik.imagekit.io/tyfldsi6ql9s/notion_env_0R0geYtpn.png?updatedAt=1633509851533)

After you've all this setup, now we just to make the request and fetch the data.
So, within the index.js (pages folder)

we will be making the requests within the `getStaticProps` function
**We first need to create a new instance of the Notion Client**

```javascript
const notion = new Client({
  auth: process.env.NOTION_SECRET,
});
```

After this, we just need to fetch the actual data, which includes the Page title and the blocks(image + links)
We cannot fetch both in a single request, so we'll have to make do different calls

```javascript
const page = await notion.pages.retrieve({
  page_id: process.env.LINKS_PAGE_ID,
});

    
const blocks = await notion.blocks.children.list({
  block_id: process.env.LINKS_PAGE_ID,
});
```

So the 'page' contains all the information about the page, within which we'll also be getting the page title
and the 'blocks' will contain all the different blocks on the page.

**Make sure that there are no blank blocks, which means there is no empty text block or anything like that.**
The one below, is a blank block. Make sure that there are none, in starting and the ending.

![Blank block](https://ik.imagekit.io/tyfldsi6ql9s/notion_blank_block__KkNCHGS7Rs.png?updatedAt=1633510429872)


So now just need to transform the data, as these two(page and blocks) will have a nested structure.

```javascript
const title = page.properties.title.title[0].plain_text;const  links = [];
let image = "";
    
blocks.results.forEach((block) => {
  if (block.type === "image") image =  block.image.external.url;
    
    if (block.type === "paragraph")
    	links.push({
    		name: block.paragraph.text[0].plain_text,
    		url: block.paragraph.text[0].href,
    	});
    });
```

For more info, you can watch [this part](https://youtu.be/BHm5Zp36nd8?t=824) of the series in order to better understand the above code.

now we just pass down these three things to our page.

```javascript
return {
  props: {
     title,
     links,
     image,
    },
  revalidate: 10,
}; 
```

We will be setting the revalidate to 10 seconds, so that our project can update itself after deployment.
In case, you're wondering why we're not using 'getServerSideProps' instead. Well, we can. However, there is a limitation on Notion API's end. which is

> The rate limit for incoming requests is an average of 3 requests per
> second.
[Notion Docs](https://developers.notion.com/reference/errors)

So, as we are already making 2 requests (one for the page and one for blocks), it is better to have some throttle in between.

Now, you just need to display the content on your page in any way that you like, or  you can  watch the [last part of the series](https://www.youtube.com/watch?v=JOLV996BO5Q&list=PLmA3URVkjqnnncC6nskypTHYoMH8u8mJO&index=5&ab_channel=DesiCodes), it's pretty small plus we will also deploy this project on Vercel.

In case, you want to compare your code with the final one [Here is the link](https://github.com/Desi-Codes/notion-linktree-clone/blob/main/pages/index.js)

I hope this was helpful, 
I would really appreciate if you subscribe to the [YT Channel](https://www.youtube.com/channel/UCY02y7r2SANwEFrddkp26wA)  and like and comment on the videos of [this series](https://www.youtube.com/watch?v=GDlNoxEpCt0&list=PLmA3URVkjqnnncC6nskypTHYoMH8u8mJO&ab_channel=DesiCodes)

Connect with me
IG: [https://www.instagram.com/desi.codes/](https://www.youtube.com/redirect?event=video_description&redir_token=QUFFLUhqbVJ2NFZSeFQ0b3JVcUtrZmJIVFNMZDZicGpmQXxBQ3Jtc0ttdGhKaEN5a21qV3VJYTFqUm9vb25FcXp5QjQ0TFVEYWlRTjlfMGpQbXNnYlNFU0R2Nms4bk92T3BaYmJaQUFGNzI2TlNDODlFMTREbkVOcVVfd0wtbWxTTm9NdXphcWQwLW93bmdfZGNubW1VQXdlYw&q=https%3A%2F%2Fwww.instagram.com%2Fdesi.codes%2F) 
Twitter: [https://twitter.com/Desi_codes](https://www.youtube.com/redirect?event=video_description&redir_token=QUFFLUhqblQzYlFzNENpalF0OWNuYmNSaVZzM0F4TTB6QXxBQ3Jtc0tra1U2dXh2R0xJd2x4MXF3Q2VrRmpsZGRSZC1Ed0ZuNHVWQlIxUDlFbFJsaXgtbDVNX0VCMnRXN01pLWg0QTVPRFBfVURDUUxwOEp4d3k2TC1NN0FsZEJ2Z2FhMXZGamxsLXpjUE9BZHpOQXRLUm5DOA&q=https%3A%2F%2Ftwitter.com%2FDesi_codes)