Copy script
Copied
Copy script
Copied
Enhanced Notion Blog Creator with Auto Database Setup
Create professional blog posts in Notion with zero setup required! This enhanced script automatically finds or creates a complete blog database with all necessary properties, then creates rich, formatted blog posts with cover images, SEO optimization, and markdown support. Perfect for content creators, marketers, and bloggers who want to streamline their Notion workflow without manual database configuration.

Created by
andrew van beek - Keyboard Team
Requirements
KEYBOARD_NOTION_BLOG_INTERNAL_SECRET
Script
Copy script
Copied
Copy script
Copied
const axios = require('axios'); // Configuration const NOTION_API_URL = 'https://api.notion.com/v1'; const NOTION_TOKEN = process.env.KEYBOARD_NOTION_BLOG_INTERNAL_SECRET; console.log('š Enhanced Notion Blog Creator - Auto Database Setup + Blog Post Creation'); console.log('='.repeat(70)); // High-quality cover images const randomCovers = [ 'https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d?w=1500&q=80', // Laptop on desk 'https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=1500&q=80', // Code on screen 'https://images.unsplash.com/photo-1461749280684-dccba630e2f6?w=1500&q=80', // Programming setup 'https://images.unsplash.com/photo-1498050108023-c5249f4df085?w=1500&q=80', // Computer and coffee 'https://images.unsplash.com/photo-1504639725590-34d0984388bd?w=1500&q=80', // Minimal workspace 'https://images.unsplash.com/photo-1611224923853-80b023f02d71?w=1500&q=80', // Notion-style workspace 'https://images.unsplash.com/photo-1519389950473-47ba0277781c?w=1500&q=80', // Technology abstract 'https://images.unsplash.com/photo-1517077304055-6e89abbf09b0?w=1500&q=80', // Modern office 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=1500&q=80', // Creative workspace 'https://images.unsplash.com/photo-1434030216411-0b793f4b4173?w=1500&q=80', // Writing and planning 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=1500&q=80', // Data visualization 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=1500&q=80', // Analytics dashboard 'https://images.unsplash.com/photo-1555421689-491a97ff2040?w=1500&q=80', // Mobile and laptop 'https://images.unsplash.com/photo-1581291518857-4e27b48ff24e?w=1500&q=80', // Clean desk setup 'https://images.unsplash.com/photo-1531297484001-80022131f5a1?w=1500&q=80' // Tech workspace ]; // Function to get root page ID for database creation async function getRootPageId() { try { console.log('š Finding accessible workspace page for database creation...'); const searchResponse = await axios({ method: 'POST', url: `${NOTION_API_URL}/search`, headers: { 'Authorization': `Bearer ${NOTION_TOKEN}`, 'Notion-Version': '2022-06-28', 'Content-Type': 'application/json' }, data: { filter: { value: 'page', property: 'object' }, page_size: 1 } }); if (searchResponse.data.results.length > 0) { const rootPage = searchResponse.data.results[0]; console.log(`ā Found root page for database creation`); return rootPage.id; } throw new Error('No accessible pages found. Please ensure your Notion integration has access to at least one page in your workspace.'); } catch (error) { console.error('ā Error getting root page:', error.response?.data || error.message); throw error; } } // Function to create a complete blog database with all properties async function createBlogDatabase(parentPageId) { try { console.log('š Creating new Blog Posts database with complete schema...'); const databaseData = { parent: { type: 'page_id', page_id: parentPageId }, title: [ { type: 'text', text: { content: 'Blog Posts' } } ], properties: { 'Title': { title: {} }, 'Status': { status: { options: [ { name: 'Draft', color: 'gray' }, { name: 'In Review', color: 'yellow' }, { name: 'Published', color: 'green' } ] } }, 'Category': { select: { options: [ { name: 'Technology', color: 'blue' }, { name: 'Health & Wellness', color: 'green' }, { name: 'Business', color: 'orange' }, { name: 'Lifestyle', color: 'purple' }, { name: 'Travel', color: 'red' }, { name: 'Personal Development', color: 'yellow' }, { name: 'Food & Recipes', color: 'brown' }, { name: 'Education', color: 'pink' } ] } }, 'Tags': { multi_select: { options: [ { name: 'Technology', color: 'blue' }, { name: 'Personal', color: 'green' }, { name: 'Tutorial', color: 'orange' }, { name: 'News', color: 'red' }, { name: 'Opinion', color: 'purple' }, { name: 'Review', color: 'yellow' }, { name: 'Travel', color: 'pink' }, { name: 'Health', color: 'gray' } ] } }, 'Publish Date': { date: {} }, 'Author': { people: {} }, 'Framer Slug': { rich_text: {} }, 'SEO Description': { rich_text: {} }, 'Content': { rich_text: {} }, 'Featured Image': { url: {} } } }; const response = await axios({ method: 'POST', url: `${NOTION_API_URL}/databases`, headers: { 'Authorization': `Bearer ${NOTION_TOKEN}`, 'Notion-Version': '2022-06-28', 'Content-Type': 'application/json' }, data: databaseData }); console.log(`ā Created new blog database: ${response.data.title[0].plain_text} (ID: ${response.data.id})`); return response.data; } catch (error) { console.error('ā Error creating blog database:', error.response?.data || error.message); throw error; } } // Function to find existing blog database or create new one async function findOrCreateBlogDatabase() { try { console.log('š Looking for existing blog database...'); const response = await axios({ method: 'POST', url: `${NOTION_API_URL}/search`, headers: { 'Authorization': `Bearer ${NOTION_TOKEN}`, 'Notion-Version': '2022-06-28', 'Content-Type': 'application/json' }, data: { filter: { value: 'database', property: 'object' } } }); // Find the first database with "Blog" in the title const blogDb = response.data.results.find(db => db.title?.[0]?.plain_text?.toLowerCase().includes('blog') ); if (blogDb) { console.log(`ā Found existing blog database: ${blogDb.title[0].plain_text} (ID: ${blogDb.id})`); return blogDb; } else { console.log('š No blog database found, creating new one...'); const rootPageId = await getRootPageId(); return await createBlogDatabase(rootPageId); } } catch (error) { console.error('ā Error finding/creating blog database:', error.response?.data || error.message); throw error; } } // Enhanced function to parse markdown content into Notion blocks function parseMarkdownToNotionBlocks(content) { const blocks = []; const lines = content.split('\n'); for (let i = 0; i < lines.length; i++) { const line = lines[i]; // Handle headers (H1-H3) const headerMatch = line.match(/^(#{1,3})\s+(.+)$/); if (headerMatch) { const level = headerMatch[1].length; const headerText = headerMatch[2]; const headerType = level === 1 ? 'heading_1' : level === 2 ? 'heading_2' : 'heading_3'; blocks.push({ object: 'block', type: headerType, [headerType]: { rich_text: [{ text: { content: headerText } }] } }); continue; } // Handle horizontal rules if (line.match(/^(-{3,}|\*{3,}|_{3,})$/)) { blocks.push({ object: 'block', type: 'divider', divider: {} }); continue; } // Handle blockquotes if (line.startsWith('> ')) { const quoteText = line.substring(2); blocks.push({ object: 'block', type: 'quote', quote: { rich_text: [{ text: { content: quoteText } }] } }); continue; } // Handle bulleted lists if (line.match(/^[\*\-\+]\s+/)) { const listItemText = line.replace(/^[\*\-\+]\s+/, ''); blocks.push({ object: 'block', type: 'bulleted_list_item', bulleted_list_item: { rich_text: [{ text: { content: listItemText } }] } }); continue; } // Handle numbered lists if (line.match(/^\d+\.\s+/)) { const listItemText = line.replace(/^\d+\.\s+/, ''); blocks.push({ object: 'block', type: 'numbered_list_item', numbered_list_item: { rich_text: [{ text: { content: listItemText } }] } }); continue; } // Handle regular paragraphs if (line.trim()) { blocks.push({ object: 'block', type: 'paragraph', paragraph: { rich_text: [{ text: { content: line } }] } }); } } return blocks; } // Function to create blog post with enhanced content async function createBlogPost(databaseId, blogData) { try { console.log('⨠Creating blog post with enhanced content...'); // Select random cover image if requested const coverImage = blogData.useRandomCover ? randomCovers[Math.floor(Math.random() * randomCovers.length)] : null; if (coverImage) { console.log('š¼ļø Selected random cover image'); } // Generate SEO description if not provided const seoDescription = blogData.seoDescription || `Discover insights about ${blogData.title.toLowerCase()}. ${blogData.content.substring(0, 100)}...`; // Generate slug from title const slug = blogData.title.toLowerCase() .replace(/[^a-z0-9\s-]/g, '') .replace(/\s+/g, '-') .replace(/-+/g, '-') .trim('-'); // Parse content into rich Notion blocks const contentBlocks = parseMarkdownToNotionBlocks(blogData.content); console.log(`š Parsed content into ${contentBlocks.length} Notion blocks`); // Build page children with rich content const pageChildren = [ { object: 'block', type: 'callout', callout: { rich_text: [{ text: { content: `š ${blogData.content.substring(0, 150)}...` }, annotations: { bold: true } }], icon: { emoji: 'āØ' } } }, { object: 'block', type: 'divider', divider: {} } ]; // Add parsed content blocks (limit to 90 to stay under 100 block limit) const maxContentBlocks = Math.min(90, contentBlocks.length); pageChildren.push(...contentBlocks.slice(0, maxContentBlocks)); if (contentBlocks.length > maxContentBlocks) { console.log(`ā ļø Content limited to ${maxContentBlocks} blocks due to Notion's limits`); } // Add footer pageChildren.push( { object: 'block', type: 'divider', divider: {} }, { object: 'block', type: 'callout', callout: { rich_text: [{ text: { content: 'š Created with Enhanced Notion Blog Creator - Auto Database Setup!' } }], icon: { emoji: 'š¤' } } } ); // Create the page data const pageData = { parent: { database_id: databaseId }, properties: { 'Title': { title: [{ text: { content: blogData.title } }] }, 'Status': { status: { name: blogData.status } }, 'Category': { select: { name: blogData.category } }, 'Tags': { multi_select: Array.isArray(blogData.tags) ? blogData.tags.map(tag => ({ name: tag.trim() })) : blogData.tags.split(',').map(tag => ({ name: tag.trim() })) }, 'Publish Date': { date: { start: new Date().toISOString().split('T')[0] } }, 'Framer Slug': { rich_text: [{ text: { content: slug } }] }, 'SEO Description': { rich_text: [{ text: { content: seoDescription } }] }, 'Content': { rich_text: [{ text: { content: blogData.content } }] } }, children: pageChildren }; // Add cover image if requested if (coverImage) { pageData.cover = { type: 'external', external: { url: coverImage } }; } const response = await axios({ method: 'POST', url: `${NOTION_API_URL}/pages`, headers: { 'Authorization': `Bearer ${NOTION_TOKEN}`, 'Notion-Version': '2022-06-28', 'Content-Type': 'application/json' }, data: pageData }); return response.data; } catch (error) { console.error('ā Error creating blog post:', error.response?.data || error.message); throw error; } } // Main execution async function main() { try { // Parse input data const blogData = { title: '{{title}}', status: '{{status}}', category: '{{category}}', tags: {{tags}}, author: '{{author}}', content: '{{content}}', seoDescription: '{{seoDescription}}' || null, useRandomCover: {{useRandomCover}} }; console.log(`š Creating blog post: "${blogData.title}"`); console.log(`š Content: ${blogData.content.length} characters`); console.log(`š·ļø Category: ${blogData.category} | Status: ${blogData.status}`); // Find existing blog database or create new one automatically const blogDb = await findOrCreateBlogDatabase(); // Create the blog post with enhanced features const newPost = await createBlogPost(blogDb.id, blogData); // Verify creation by fetching the post const verifyResponse = await axios({ method: 'GET', url: `${NOTION_API_URL}/pages/${newPost.id}`, headers: { 'Authorization': `Bearer ${NOTION_TOKEN}`, 'Notion-Version': '2022-06-28' } }); console.log('\nā SUCCESS! Enhanced blog post created!'); console.log('š Results:'); console.log(` š Title: ${verifyResponse.data.properties.Title?.title?.[0]?.text?.content}`); console.log(` š Status: ${verifyResponse.data.properties.Status?.status?.name}`); console.log(` š·ļø Category: ${verifyResponse.data.properties.Category?.select?.name}`); console.log(` š·ļø Tags: ${verifyResponse.data.properties.Tags?.multi_select?.map(tag => tag.name).join(', ')}`); console.log(` š¼ļø Cover: ${verifyResponse.data.cover ? 'Professional cover image applied' : 'No cover'}`); console.log(` š Page URL: ${verifyResponse.data.url}`); console.log(` š Page ID: ${newPost.id}`); console.log(` šļø Database ID: ${blogDb.id}`); console.log('\nš Enhanced Features Applied:'); console.log(' ā Automatic database detection/creation'); console.log(' ā Complete database schema with all properties'); console.log(' ā Markdown content parsing to rich blocks'); console.log(' ā Professional cover image selection'); console.log(' ā SEO optimization (slug, description)'); console.log(' ā Rich content formatting and structure'); console.log(' ā Full verification workflow'); } catch (error) { console.error('ā Enhanced script failed:', error.message); } } // Execute the enhanced script main();