NotionPublisherPlugin
The NotionPublisherPlugin enables publishing articles directly to Notion pages, automatically converting Markdown content to Notion's block format.
Installation
The plugin is included in the @artipub/core
package:
npm install @artipub/core
Configuration
interface NotionPublisherPluginOption {
/**
* Notion API key from your integration
* Required: Yes
*/
api_key: string;
/**
* Parent page ID where articles will be published as subpages
* Required: Yes
*/
page_id: string;
/**
* Specific page ID to update (overrides automatic tracking)
* Required: No
*/
update_page_id?: string;
}
Setup Guide
Step 1: Create Notion Integration
- Navigate to Notion Integrations
- Click "New integration"
- Configure your integration:
- Name: Give it a descriptive name (e.g., "ArtiPub Publisher")
- Associated workspace: Select your workspace
- Capabilities: Ensure "Read content", "Update content", and "Insert content" are enabled
- Click "Submit" to create the integration
- Copy the "Internal Integration Token" - this is your
api_key
Step 2: Connect Integration to Page
- Create or select a page in Notion where articles will be published (e.g., "Articles Inbox")
- Connect the integration to the page:
- Open the page in Notion
- Click the "..." menu in the top-right corner
- Select "Add connections"
- Search for and select your integration
Step 3: Get Page ID
There are two methods to obtain the page ID:
Method 1: From URL
- Open the page in Notion
- Click "Copy link" from the page menu
- The URL format:
https://www.notion.so/Page-Name-{page_id}
- Extract the ID after the last hyphen
Example:
URL: https://www.notion.so/My-Articles-abc123def456
Page ID: abc123def456
Method 2: From Developer Tools
- Open Notion in your browser
- Open Developer Tools (F12)
- Navigate to the Network tab
- Reload the page
- Look for requests containing the page ID
Usage
Basic Example
import { ArticleProcessor, PublisherManager, NotionPublisherPlugin } from "@artipub/core";
// Process your article first
const processor = new ArticleProcessor({
uploadImgOption: {
// Your image upload configuration
},
});
const { content } = await processor.processMarkdown("./article.md");
// Create publisher and add Notion plugin
const publisher = new PublisherManager(content);
publisher.addPlugin(
NotionPublisherPlugin({
api_key: process.env.NOTION_API_KEY!,
page_id: process.env.NOTION_PAGE_ID!,
})
);
// Publish to Notion
const results = await publisher.publish();
console.log(results);
// Output: [{ name: 'NotionPublisher', success: true, info: '...', pid: '...' }]
With Environment Variables
Create a .env
file:
NOTION_API_KEY=secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
NOTION_PAGE_ID=abc123def456789
Use in your code:
import dotenv from "dotenv";
dotenv.config();
publisher.addPlugin(
NotionPublisherPlugin({
api_key: process.env.NOTION_API_KEY!,
page_id: process.env.NOTION_PAGE_ID!,
})
);
Advanced: Publishing to Database
If your page_id points to a Notion database, articles will be created as database entries:
// Database-specific configuration
const notionPlugin = NotionPublisherPlugin({
api_key: process.env.NOTION_API_KEY!,
page_id: process.env.NOTION_DATABASE_ID!, // Database ID instead of page ID
});
// The plugin will automatically detect it's a database and create entries
publisher.addPlugin(notionPlugin);
Features
Supported Markdown Elements
The plugin automatically converts these Markdown elements to Notion blocks:
Markdown Element | Notion Block Type |
---|---|
Headings (h1-h3) | Heading blocks |
Paragraphs | Paragraph blocks |
Bold/Italic | Rich text formatting |
Links | Link annotations |
Images | Image blocks |
Code blocks | Code blocks with language |
Inline code | Code annotations |
Blockquotes | Quote blocks |
Lists (ordered/unordered) | Numbered/Bulleted list blocks |
Tables | Table blocks |
Horizontal rules | Divider blocks |
Image Handling
- Local images are automatically uploaded to Notion
- External image URLs are preserved
- Images maintain their alt text as captions
Code Block Support
Code blocks preserve syntax highlighting:
// This TypeScript code will have proper syntax highlighting in Notion
const example = "syntax highlighting works!";
Article Updates
When isTraceUpdate
is enabled (default), the plugin tracks published articles:
- First publish: Creates a new Notion page and saves the page ID
- Subsequent publishes: Updates the existing page instead of creating duplicates
// Article with unique ID will be tracked
const content = `# My Article
id: unique_article_123
Article content...`;
// First publish - creates new page
await publisher.publish();
// Later update - updates the same page
await publisher.publish();
Troubleshooting
Common Issues
1. "Unauthorized" Error
Cause: Invalid API key or integration not connected to page
Solution:
- Verify your API key is correct
- Ensure the integration is connected to the target page
- Check integration permissions
2. "Object not found" Error
Cause: Invalid page ID or page doesn't exist
Solution:
- Double-check the page ID extraction
- Ensure the page exists and hasn't been deleted
- Verify you're using the correct workspace
3. "Insufficient permissions" Error
Cause: Integration lacks necessary permissions
Solution:
- Check integration capabilities in Notion settings
- Ensure "Insert content" and "Update content" are enabled
- Re-connect the integration to the page
4. Images Not Appearing
Cause: Image upload failed or invalid URLs
Solution:
- Ensure images are properly processed by ArticleProcessor
- Check that image URLs are accessible
- Verify Notion has permission to access external images
Debug Mode
Enable debug logging to troubleshoot issues:
const plugin = NotionPublisherPlugin({
api_key: process.env.NOTION_API_KEY!,
page_id: process.env.NOTION_PAGE_ID!,
});
// Add custom logging
const originalProcess = plugin.process;
plugin.process = async (...args) => {
console.log("Publishing to Notion...");
try {
const result = await originalProcess.apply(plugin, args);
console.log("Notion publish result:", result);
return result;
} catch (error) {
console.error("Notion publish error:", error);
throw error;
}
};
Best Practices
1. Organize with Databases
Use Notion databases for better organization:
// Publish to a database with properties
const dbPlugin = NotionPublisherPlugin({
api_key: process.env.NOTION_API_KEY!,
page_id: process.env.NOTION_DATABASE_ID!,
});
// Articles become database entries with metadata
2. Error Handling
Always handle potential failures:
try {
const results = await publisher.publish();
const notionResult = results.find((r) => r.name === "NotionPublisher");
if (!notionResult?.success) {
console.error("Notion publish failed:", notionResult?.info);
// Implement fallback logic
}
} catch (error) {
console.error("Publishing error:", error);
// Handle critical errors
}
3. Rate Limiting
Notion API has rate limits. Implement delays for bulk publishing:
async function publishMultipleArticles(articles: string[]) {
for (const article of articles) {
const publisher = new PublisherManager(article);
publisher.addPlugin(notionPlugin);
await publisher.publish();
// Add delay to respect rate limits
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
4. Environment-Specific Configuration
Use different Notion pages for different environments:
const notionConfig = {
api_key: process.env.NOTION_API_KEY!,
page_id: process.env.NODE_ENV === "production" ? process.env.NOTION_PROD_PAGE_ID! : process.env.NOTION_DEV_PAGE_ID!,
};
publisher.addPlugin(NotionPublisherPlugin(notionConfig));