◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Dev Tools
⬡ Dev Tools/2026-04-23Advanced

Using Notion as a CMS Backend for Rork Apps — Auth, Block Rendering, Rate Limits, and the 1-Hour Image URL Problem

Put Notion behind your Rork app. Pick the right auth model, render Notion blocks safely, survive the 1-hour image URL expiry, and stay under the API rate limit — a production-grade walkthrough.

Notion APIRork584CMSOAuthReact Native239CachingRate Limiting

✦ Premium Article

When a Rork-built app starts to feel like it needs actual articles, recipes, or lessons behind it, the backend question shows up uninvited. Firestore feels heavy to wire up from scratch. Supabase adds infrastructure you now have to think about. Sanity or Contentful are wonderful, but they might outclass a small project in ways you can feel in your wallet. I have spent the last few years quietly using Notion as the backend for exactly these "right-sized" apps — and it holds up better than you might expect.

Notion's appeal is almost embarrassingly practical. Writers can edit in a tool they already know. Titles, bodies, tags, and publish flags fall out of a database without you designing anything. Write in Notion, read in Rork — that split cuts friction out of the "write, fix, ship" loop that indie developers live and die by.

That said, Notion's API has three quirks you absolutely want to know before shipping. Image URLs expire after one hour, the API has a rate limit you will notice eventually, and page content comes back as a peculiar array of blocks. Miss any of those and the version of your app that launched just fine on Monday will greet you on Friday with "the images are gone" reports from confused readers.

This guide walks through using Notion as the CMS for a Rork-generated React Native app, including the operational lessons I earned the hard way across five indie projects. We're aiming for something that keeps working — not a cute sample that falls apart in week two.

Three questions to settle before you put Notion behind your app

Before wiring anything, clarify three things about your app. It saves design regret later.

1. Read-only, or read-write? Blogs, news, recipes — anywhere "I write, readers read" — are a clean fit. If you need user-submitted content, Notion is the wrong tool. The API supports writes, but funneling strangers' content into your own workspace is an operational mess. Supabase or Firestore are much saner there.

2. One language, or many? For multilingual apps you have two shapes: one row per language (with a locale property), or one row with title_ja, title_en columns side by side. I prefer the former. Translation progress is easier to track, and "publish Japanese today, hold the English until next week" just works.

3. Image-heavy, or text-heavy? Image-heavy apps (recipes, travel guides, portfolios) must plan for the 1-hour expiry before writing a single line of frontend code. Text-heavy apps can ship a much simpler version.

Once those three are settled, the rest of the work flows straight.

Start with an Internal Integration Token; reach for OAuth only when you must

Notion gives you two auth paths.

  • Internal Integration Token — read and write your own workspace. Mint a token, send it as Authorization: Bearer, and you're online.
  • Public OAuth — let other users connect their workspaces. Needed for multi-workspace SaaS-style products.

If you're a solo developer shipping your own writing to your own app, start with an Internal Integration Token. Building OAuth first — callback handling, encrypted token storage, refresh flows — quietly eats a week before you render a single paragraph.

There is one rule, though, that you cannot bend: never put the token in the client bundle. Dropping NOTION_TOKEN=secret_xxx into a Rork-generated .env that ships with the app is a leak waiting to happen. The token belongs on a server (Cloudflare Workers, a tiny Hono BFF, whatever you have) and the app always talks to Notion through that server.

A minimal backend needs exactly three endpoints: list articles, get one article, and proxy images. The Hono setup from Rork × Hono Cloudflare Workers REST API Implementation Guide pairs cleanly with Notion and is what I'm using in the examples below.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦You'll settle the infamous '1-hour image URL expiry' with a proxy pattern that pairs short-TTL edge caching and signed URL refresh — no more broken images the day after launch
✦You'll learn where Internal Integration Tokens end and public OAuth begins, so you can start personal and scale to multi-workspace without rewriting your auth layer
✦You'll build a type-safe block renderer that survives Notion adding new block types tomorrow, turning your CMS into a reliable content pipeline rather than a weekly fire drill
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ Dev Tools2026-09-04
EAS secret visibility does not keep a value out of your app — deciding prefix and visibility separately
The EXPO_PUBLIC_ prefix decides what ships inside your app; EAS visibility decides who can read it. Why stacking them blanks a value on OTA updates, and how to check your build.
⬡ Dev Tools2026-08-22
Every bulk replace exited zero. The damage was in the lines I did not delete
Run a bulk replace over generated code and the breakage lands on the neighbouring lines, not the matched ones. Here is what broke in a live project, and a dependency-free guard that checks the invariants a replace must preserve.
⬡ Dev Tools2026-08-14
Find the native edits expo prebuild will erase before you upgrade to SDK 57
Expo SDK 57 makes expo prebuild clear and regenerate ios and android by default. Here is how to audit your hand edits first, move them into config plugins, and why 57.0.9 matters for Reanimated apps.