Building on Notion’s Private API: A Reverse-Engineered Go Client That Powers Production Blogs
Hook
While Notion’s official API was still in beta with limited capabilities, developers were already publishing entire blogs and programming books by reverse-engineering the private web API that Notion’s own frontend uses.
Context
Notion has become ubiquitous as a writing and knowledge management tool, and developers naturally want to use it as a headless CMS—writing content in Notion’s polished interface while programmatically publishing to static sites, blogs, or documentation platforms. The problem? Notion’s official API launched in beta years after the product gained popularity, and even today lacks feature parity with what the web interface can access.
This gap created an opportunity for notionapi, a Go library that doesn’t wait for official API endpoints. Instead, it works with Notion’s internal API to retrieve page content in structured format. The library represents a pragmatic engineering decision: accept the fragility of an undocumented API in exchange for capabilities that simply don’t exist elsewhere. The fact that it powers the author’s production blog and programming book sites demonstrates this isn’t just an experiment—it’s a battle-tested approach to solving a real publishing workflow problem.
Technical Insight
The architecture of notionapi centers on reverse-engineering Notion’s internal API. The author documented the reverse-engineering process in a blog post linked from the README, showing how the library was built by analyzing the HTTP requests Notion’s frontend makes.
The core workflow involves retrieving page content using page IDs. Notion represents pages as collections of “blocks”—each paragraph, header, image, or embed is a block. The library retrieves this structured format, though the README doesn’t provide specific implementation details. According to the documentation at pkg.go.dev/github.com/kjk/notionapi, the library handles Notion’s block structure, but the exact API methods and types are not detailed in the README.
The library allows you to retrieve content of a Notion page in structured format, which you can then convert to HTML or other formats. The author uses this capability in production to transform Notion pages into static blog posts and programming books. The reference implementations at https://github.com/kjk/blog and https://github.com/essentialbooks/tools/ demonstrate real-world usage patterns, showing how to download pages and integrate with publishing pipelines that deploy to Netlify.
Authentication appears to use Notion’s internal mechanisms, though the README doesn’t specify the exact authentication approach. The library is designed primarily for reading content, with the README noting “limited write capabilities” without elaborating on what write operations are supported.
The structured format returned by the library enables practical publishing workflows. The author’s production usage demonstrates converting Notion content to HTML for blogs and books, handling typical content types, and integrating with static site generators. These reference implementations show patterns for downloading multiple pages, processing content, and publishing results, proving the approach works beyond simple examples.
Gotcha
The elephant in the room is stability. This library depends entirely on Notion’s private, undocumented API that could change at any moment. Notion has no obligation to maintain compatibility with unofficial clients, and changes to their internal API will break notionapi until someone updates the library. The author’s production usage suggests these breaks are manageable, but you’re signing up for potential maintenance burden.
Authentication details are not fully documented in the README. The library uses Notion’s internal authentication mechanisms, which may create operational friction compared to official API keys. The exact authentication approach and its implications for automation and security are not specified in the README.
Write operations are described as “limited,” and the README doesn’t elaborate on exactly what works and what doesn’t. If your use case requires creating pages, updating databases, or complex content manipulation, you’ll need to consult the API documentation or experiment with the library. The library is optimized for the read-heavy workflow of publishing content that you’ve already written in Notion’s interface, not for building Notion as a backend database with full CRUD operations.
The README notes that “official Notion API is still in beta and not as capable as this unofficial API,” but this statement may be outdated depending on when you’re reading this. You should verify the current state of Notion’s official API before committing to the unofficial approach.
Verdict
Use if: You need to extract Notion content programmatically for publishing workflows—blogs, documentation sites, or books—and Notion’s official API lacks features you require. The production-proven nature of this library (powering the author’s blog and programming books) makes it suitable for side projects and even production systems where you can tolerate occasional breakage and have the Go expertise to debug issues. It’s ideal when Notion genuinely works best as your writing environment and you need a pragmatic bridge to static site generation. Skip if: You’re building critical business systems that can’t tolerate API breakage, require extensive write operations, work in regulated industries where unofficial APIs violate compliance, or can achieve your goals with Notion’s official API (always check that first—the official API has evolved since this library was created). Also skip if you’re not comfortable with the maintenance risk of depending on reverse-engineered endpoints—the tradeoff between capability and stability is real, and only you can decide if it’s worth it for your use case.