> ## Documentation Index
> Fetch the complete documentation index at: https://docs.replit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Build a Notion-powered website

> Learn how to build a website that uses Notion as a Content Management System (CMS) with Replit Agent.

export const WistiaEmbed = ({videoId, title = "Wistia video", playerColor = "FF0000", controlsVisibleOnLoad = false}) => {
  if (!videoId) {
    return null;
  }
  const url = "https://fast.wistia.net/embed/iframe/" + videoId + "?seo=false&playerColor=" + playerColor + "&controlsVisibleOnLoad=" + controlsVisibleOnLoad;
  return <Frame>
      <iframe src={url} title={title} allow="autoplay; fullscreen" allowFullScreen></iframe>
    </Frame>;
};

## Build a Notion-powered blog with Replit Agent

Notion is a powerful tool for organizing information, and it excels as a Content Management System (CMS). By integrating Notion with Replit, you can manage your website's content—like blog posts, portfolio items, or product listings—directly from your Notion workspace.

Replit, powered by [Replit Agent](/core-concepts/agent), handles the coding, hosting, and deployment, letting you go from idea to a published application quickly. Effective prompting is key to guiding Agent; for a comprehensive guide, see [Efficient prompting with Replit AI](/tutorials/effective-prompting) and [How to vibe code effectively](/tutorials/how-to-vibe-code).

<WistiaEmbed videoId="b2702imuy2" title="Vibe coding a custom website with Notion as a CMS" />

This tutorial guides you through building a minimalistic blog that pulls its posts from a Notion table. You will:

* Use Replit Agent to generate the initial application
* Connect your Replit app to a Notion database
* Learn to guide the AI and troubleshoot common issues using effective prompting techniques
* Publish your blog for the world to see

<Frame caption="Final result: A minimalistic blog powered by Notion">
  <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/final-app.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=8189975b31f2c1c47e9e8577df926bd6" alt="Screenshot of the final Notion-powered blog application with minimalist design" width="3840" height="2160" data-path="images/tutorials/notion-cms/final-app.png" />
</Frame>

The tutorial will follow largely from the video above, but with some additional context and steps to help you understand the process.

## Prerequisites

To follow this tutorial, you'll need:

* A Replit account
* A Notion account
* Familiarity with basic Replit Agent interactions. If you're new to Agent, check out the [Replit Agent documentation](/core-concepts/agent).

## Step 1: Prepare your Notion database

Before prompting Agent, set up your content source in Notion. This involves thinking procedurally about what your blog needs, similar to planning a product.

<Steps>
  <Step title="Create a Notion integration">
    1. In Notion, go to **Settings & members** (usually in the top-left sidebar).
    2. Navigate to **Connections** (previously "Integrations").
    3. Select **Develop or manage integrations**.
    4. Select **+ New integration**.

    <Frame caption="Creating a new integration in Notion">
      <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/new-integration-1.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=36613d11085fa2589511be942ce03218" alt="Notion developer portal showing the New integration button" width="3794" height="2168" data-path="images/tutorials/notion-cms/new-integration-1.png" />
    </Frame>

    5. Name your integration (e.g., "My Replit Blog Integration").
    6. Associate it with your desired Notion workspace.

    <Frame caption="Configuring your Notion integration">
      <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/new-integration-2.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=649a346838203ef40f1293f69125916f" alt="Notion integration configuration screen with name and workspace selection" width="3796" height="2168" data-path="images/tutorials/notion-cms/new-integration-2.png" />
    </Frame>

    7. For "Integration type," choose **Internal Integration**.
    8. Select **Submit**.
    9. Copy your **Internal Integration Secret** (token) and save it securely. This is your Notion API key.

    <Frame caption="Obtaining your Integration Secret">
      <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/new-integration-3.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=22cb64a8c057b70293b955b0edcdb55d" alt="Notion integration secrets page showing the integration token" width="3796" height="2168" data-path="images/tutorials/notion-cms/new-integration-3.png" />
    </Frame>

    10. Under **Capabilities**, ensure "Read content" is enabled. For this tutorial, reading is sufficient. If you later want to write data to Notion, enable "Insert content" and "Update content."

    <Info>
      Create a new integration for each project to manage permissions granularly. This is a security best practice.
    </Info>

    For more detailed instructions, refer to [Notion's official documentation on creating an integration](https://developers.notion.com/docs/create-a-notion-integration).

    You can directly access Notion's integrations dashboard at [notion.so/my-integrations](https://notion.so/my-integrations).
  </Step>

  <Step title="Create a Notion page with a database">
    1. Create a new page in Notion for your blog content.
    2. On this page, add a new **Table** database.
    3. Name your table (e.g., "Blog Posts").
    4. Define columns for your posts. **Specify** these clearly in your mind, as you'll soon tell Agent about them:
       * `Title` (Text, default title property)
       * `Body` (Text, for main post content)
       * `Slug` (Text, for URL-friendly identifiers)
       * `PublishedDate` (Date, or use "Created time" / "Last edited time")
       * `ReadingTime` (Text or Number, e.g., "5 min read")
       * `Description` (Text, short summary for previews)

    <Frame caption="Example Notion database setup for blog posts">
      <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/blog-posts.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=18b381c19ccdddc74a2c67a523400d60" alt="Notion database configured with columns for blog posts" width="3840" height="2160" data-path="images/tutorials/notion-cms/blog-posts.png" />
    </Frame>

    5. Add a few sample posts. You can use Notion's AI features to help generate content!
  </Step>

  <Step title="Connect your integration to the page">
    1. Open the Notion page containing your database.
    2. Click the **•••** (three dots) menu in the top-right corner.

    <Frame caption="Access the integration menu in Notion">
      <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/add-integration.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=20d1052e1ec46366a2727cce6bcf0c50" alt="Notion connections menu showing how to add your integration to the page" width="3840" height="2160" data-path="images/tutorials/notion-cms/add-integration.png" />
    </Frame>

    3. Select **+ Add connections**.
    4. Search for and select the integration you created (e.g., "My Replit Blog Integration").

    <Frame caption="Adding your integration to the Notion page">
      <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/add-integration-menu.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=f3c0325b2e9e8de79b8b7b126974b636" alt="Notion page showing the three dots menu to add integrations" width="3840" height="2160" data-path="images/tutorials/notion-cms/add-integration-menu.png" />
    </Frame>

    5. Confirm the connection. This allows Replit (via the integration token) to access this page and its database.
  </Step>
</Steps>

## Step 2: Prompt Replit Agent

With Notion set up, let's get Replit Agent to build our blog's foundation. **Plan before you prompt**: a clear outline of features leads to more focused prompts.

<Steps>
  <Step title="Open Replit Agent">
    Navigate to the Replit homepage and open **Agent**.
  </Step>

  <Step title="Write your prompt">
    Provide Agent with a detailed prompt. **Simplify** your language, but be **specific** about requirements, constraints, and desired outputs. Here's an example:

    ```text theme={null}
    Help me create a hyper-minimalistic blog using Notion as a CMS.
    The blog should pull posts from a Notion page.
    The table on the Notion page has the following columns: Title, Body, Slug, PublishedDate, ReadingTime, Description.
    You should generate a slug for each post based on its title if the Slug column is empty.
    Make the blog theme black with white text. Keep it extremely minimal.
    The posts should be listed on the homepage, and clicking a post should navigate to a page displaying the full post content.
    ```

    <Tip>
      For more tips on writing effective prompts, see our guide on [Efficient prompting with Replit AI](/tutorials/effective-prompting).
      You can also **show** Agent what you mean by providing a URL to scrape for initial styling or content ideas (e.g., your personal portfolio) by adding: `Scrape the content of [URL] for initial design inspiration and placeholder text.`
    </Tip>

    Agent will generate a plan. Review it to ensure it aligns with your expectations, then approve it. This is your first **checkpoint** in the AI-assisted building process.
  </Step>

  <Step title="Review the initial preview">
    Agent will then generate a visual preview. Check if the basic layout and styling are heading in the right direction. Refinements will come later.
  </Step>
</Steps>

## Step 3: Connect Replit to Notion with Secrets

Agent will likely need your Notion integration details to fetch data.

<Steps>
  <Step title="Add Secrets in Replit">
    Typically, you'll need:

    1. `NOTION_API_KEY`: Your Internal Integration Secret from Step 1.
    2. `NOTION_DATABASE_ID`: The ID of your Notion database.

    **How to find your Notion Database ID:**

    * Open your Notion page with the database in a browser.
    * The URL might be `https://www.notion.so/your-workspace/PAGE_TITLE-PAGE_ID?v=DATABASE_VIEW_ID`. The `PAGE_ID` is often the database ID if the database is the page's main element.
    * **More reliably**: Click the **•••** menu on your database view, select **Copy link to view**, and paste it. The link `https://www.notion.so/your-workspace/DATABASE_ID?v=VIEW_ID` contains the `DATABASE_ID` before `?v=`.

    Go to the **Secrets** tool (🔒 icon) in the Project Editor. Add these:

    * Key: `NOTION_API_KEY`, Value: `[Your_Notion_Integration_Secret]`
    * Key: `NOTION_DATABASE_ID`, Value: `[Your_Notion_Database_ID]`

    <Frame caption="Adding your Notion secrets to Replit">
      <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/add-secrets.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=d96b903522fbf7e189c77d3c1901352e" alt="Replit Secrets tool with Notion API key and Database ID added" width="3840" height="2160" data-path="images/tutorials/notion-cms/add-secrets.png" />
    </Frame>

    Agent should automatically use these secrets and attempt to connect. The app will likely restart.
  </Step>
</Steps>

## Step 4: Debugging and refining with Agent

Building with AI is iterative. Expect errors or imperfections. This is where guiding the AI effectively—often called "vibe coding"—is key. For a deeper dive into this skill, check out our tutorial on [How to vibe code effectively](/tutorials/how-to-vibe-code). **Master context** by providing only relevant information for each debugging step.

<Tip>
  Keep the **Console** in the Project Editor open. It provides valuable error messages and logs.
</Tip>

<Frame caption="Debugging your Notion app using the Replit Console">
  <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/console-debug.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=7cc562bec25b26e5302b74793f002c00" alt="Replit Console showing error messages while debugging the Notion integration" width="3840" height="2160" data-path="images/tutorials/notion-cms/console-debug.png" />
</Frame>

Here are common scenarios and how to address them by **debugging methodically**:

### Scenario 1: "Failed to load posts" or property errors

#### Symptom

The app runs but doesn't display posts. Console errors might mention "Could not find sort property with name ID created\_time" or other column mismatches.

#### Cause

Agent might assume column names or properties (e.g., `created_time` for sorting) that don't exist or are named differently in your Notion database.

#### Troubleshooting

1. **Verify Notion Database**: Ensure column names in your database exactly match Agent's expectations or your prompt. If Agent seeks `created_time` and you have `PublishedDate`, it's a mismatch.
2. **Prompt Agent with error (Debug principle)**: Copy the *exact* console error and **select** relevant code snippets if you've identified them. Provide this focused context to Agent:
   ```text theme={null}
   There's an error fetching posts. Console: "Could not find sort property with name ID created_time".
   My Notion database uses 'PublishedDate'. Please use this for sorting/fetching. Here's the suspected code from `services/notion.js`: [code snippet]
   ```
3. **Iterate (Experiment principle)**: If Agent's fix fails, provide more specifics. "Posts still not loading. Error persists. Show me the code for fetching/sorting Notion posts." If you added a column like `created_time` in Notion as a quick fix, you can later ask Agent: "Remove reliance on 'created\_time', use 'PublishedDate' instead." Remember to use Agent's **Checkpoints** to save working states.

### Scenario 2: Incorrect data display or formatting

#### Symptom

Data appears, but incorrectly (e.g., reading time wrong on homepage but right on post page; Markdown rendering issues).

#### Troubleshooting

1. **Be specific (Specify principle)**: Describe the issue and location clearly:
   ```text theme={null}
   On the homepage, post reading time is incorrect, but it's correct on individual post pages.
   Also, display 'PublishedDate' on the homepage for each post summary.
   ```
2. **Markdown issues (Show principle)**: If Notion "Body" Markdown renders incorrectly (e.g., extra spaces, formatting errors):
   * Inspect raw content in Notion; its formatting can introduce subtle characters.
   * Prompt Agent clearly. You can even **show** an example:
     ```text theme={null}
     Markdown rendering issue: In post X, bold text like '**this**' appears as ' ** this **' and fails to render. Ensure Markdown parsing handles such cases or trims whitespace. Example of correct rendering for bold: **This is bold**.
     ```
   * Testing with known good Markdown (e.g., from ChatGPT pasted into Notion) can isolate if the issue is source data or rendering logic.

### General debugging flow

1. **Observe**: Note the error or incorrect behavior.
2. **High-level prompt (Simplify)**: Describe the problem to Agent clearly.
3. **Check Console/DevTools (Debug)**: Look for detailed errors.
4. **Iterate & provide context (Select, Show)**: If Agent's fix fails, provide more context (error message, relevant code, your goal, attempts made).
5. **Incremental changes (Checkpoint)**: Ask Agent to fix one thing at a time. Use **Checkpoints** in Agent to save progress.
6. **Rollback**: If prompts worsen things, roll back to a working **Checkpoint** and try a new approach.

<Note>
  Don't hesitate to examine Agent-generated code. Even without expertise in the language, you can often spot logical issues or understand data flow, helping you write better prompts. Files like `notionService.js` usually handle Notion API calls.
</Note>

## Step 5: Further enhancements

Once core functionality works, ask Agent to add features. Use positive, direct language (**Instruct** principle). Here are ideas:

<AccordionGroup>
  <Accordion title="Implement caching and prefetching">
    Ask Agent: "Implement post caching and prefetching from Notion for a super-fast site."
    This reduces Notion API calls and speeds up page loads.
  </Accordion>

  <Accordion title="Enhance styling">
    Ask Agent: "Add a hover effect to homepage blog post links." or "Improve post typography for readability."
    Small visual tweaks significantly improve user experience. You can **show** Agent examples of styles you like.
  </Accordion>

  <Accordion title="Configure data refresh strategy">
    Consider how often to fetch new Notion data. For simple blogs, on page load or server restart might be enough.
    For dynamic content, ask Agent: "Explore options to auto-refresh Notion posts hourly." This might involve background polling (adds complexity but keeps content current).
  </Accordion>
</AccordionGroup>

## Step 6: Publish your website

Happy with your site? Time to share it!

1. Select **Publish** in the Project Editor (top right).
2. Review publishing settings (project name, tier). For more details, see [Deployments](/category/replit-deployments).
3. Select **Publish**.

<Frame caption="Publishing your Notion-powered website">
  <img src="https://mintcdn.com/replit/0ixNWaRF232g0Gwn/images/tutorials/notion-cms/deploy.png?fit=max&auto=format&n=0ixNWaRF232g0Gwn&q=85&s=3f5a9b1b5946fc3461fc8e93f29dcac9" alt="Replit publishing interface showing how to publish your Notion-powered website" width="3840" height="2160" data-path="images/tutorials/notion-cms/deploy.png" />
</Frame>

Replit builds, bundles, and publishes your app to a public URL.

## What you've learned

By following this tutorial, you've learned to:

* Set up Notion as a CMS with an integration and structured database
* Prompt Replit Agent to build a web app connected to Notion, applying principles like **planning, specifying, and simplifying**
* Securely manage API keys using Replit Secrets
* Iteratively debug and refine an AI-generated app using techniques like **providing context, showing examples, and using checkpoints**
* Publish your Notion-powered website on Replit

For detailed information about checkpoints and rollbacks, see [Checkpoints and Rollbacks](/core-concepts/agent/checkpoints-and-rollbacks).

Building with AI like Replit Agent is collaborative. Procedural thinking, clear instructions, and methodical debugging are crucial for turning ideas into reality, fast.

## Next steps

Continue developing your Notion-powered website:

<AccordionGroup>
  <Accordion title="Experiment with content types">
    Try adding diverse content from Notion: image galleries, embedded videos, or categorized items.
  </Accordion>

  <Accordion title="Leverage advanced Notion features">
    Explore Notion's formulas, rollups, and relations for complex data structures. Work with Agent to display this rich data on your Replit site.
  </Accordion>

  <Accordion title="Combine with other Replit integrations">
    Enhance your app by merging Notion data with other [Replit AI](/core-concepts/how-replit-works) tools or [Agent integrations](/replitai/integrations). For example, use Replit Auth for private content or OpenAI for AI-generated summaries from Notion data within your app.
  </Accordion>
</AccordionGroup>

Happy building! We can't wait to see what you create.
