An automated bi-directional synchronization daemon and knowledge graph visualizer built with TypeScript, Next.js, and Notion API. Periodically indexes personal bookmark databases, extracts semantic relationships into interactive visual nodes, and persists cached metadata using Redis for instant retrieval.
Bookmarked bridges the gap between how you consume content and how you organize it. Instead of losing that brilliant tweet buried in your timeline, forward it to our Telegram bot. Seconds later, it's in your Notion database—beautifully formatted, tagged, and searchable.
I was spending hours every week manually copying tweets and articles into Notion. The workflow was broken: switch apps, copy, switch again, paste, format. I realized I could automate this entirely. Thus Bookmarked was born.
This project emerged from a personal pain point that resonated with thousands of users across Twitter, Reddit, and Product Hunt.
The architecture follows a microservices-inspired approach:
1Telegram Bot → Express Server → Job Queue → Notion API2 ↓ ↓ ↓3 User Input Parsing Background4 & Routing Processing
Notion API has strict rate limits (3 requests/second). When bulk importing, we'd hit them constantly.
Solution: Implemented a sophisticated queue system that intelligently batches requests and respects Notion's rate limits using exponential backoff.
1// Exponential backoff retry strategy2async function retryWithBackoff(fn, maxRetries = 3) {3 for (let attempt = 0; attempt < maxRetries; attempt++) {4 try {5 return await fn();6 } catch (error) {7 if (error.status === 429) {8 const delay = Math.pow(2, attempt) * 1000;9 await new Promise((resolve) => setTimeout(resolve, delay));10 } else {11 throw error;12 }13 }14 }15}
Twitter contains embedded images and videos. How do we preserve them in Notion? We download media, optimize it, upload to a CDN, and embed the links in Notion. Network operations are concurrent with proper error handling.
Different link formats (tweets, threads, links) need different parsing strategies. We built a plugin architecture where each source type has its own parser, making it easy to add new sources.
Users might send the same link twice. We needed deduplication without false negatives.
Solution: Content hashing with fuzzy matching to detect duplicates while allowing intentional multiple saves.
The project uses many amazing libraries. We've given back by contributing improvements to:
Built with ❤️ for people who love collecting ideas and organizing thoughts.