RORK LABJP
TOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the roundTOOLING — Rork's developer repos keep moving: rork-xcode was updated on July 16, rork-device on July 15, and rork-plist on July 13OPUS46 — Claude Opus 4.6 is live in Rork, and Rork Max is built to assemble apps on top of Claude CodeSIM — A cloud iOS simulator runs in the browser, with one click to install on a device and two clicks to publish to the App StoreMAX — Rork Max emits pure Swift rather than React Native, reaching iPhone, iPad, Apple Watch, Apple TV, Vision Pro, and even iMessageNATIVE — That opens up HealthKit, ARKit and LiDAR, NFC, Dynamic Island, Live Activities, 3D through Metal, and on-device inference with Core MLSEED — Rork raised a $15M seed led by Left Lane Capital, with Peak XV and a16z Speedrun joining the round
Articles/Dev Tools
Dev Tools/2026-05-01Advanced

Rork × Notification Service Extension Production Guide — Rich Push, Encrypted Payloads, and Dynamic Rewriting to Lift Open Rates

A practical guide to wiring a Notification Service Extension into a Rork-built iOS app — image attachments, end-to-end encrypted payloads, and dynamic APNs payload rewriting — with working Swift code and the production pitfalls that bit me along the way.

Rork515Notification Service ExtensionRich PushAPNs3Swift48iOS109Push Notifications9Encryption2

Premium Article

"The same notification, with and without an image, drives more than 2x the open rate" — when you watch the top App Store apps closely, the teams that have figured out Rich Push are the ones whose retention and revenue charts look very different from the teams that haven't. So it's frustrating when you ship an app with Rork, try to add image notifications, and run straight into "the image doesn't show up even with mutable-content: 1," "my Notification Service Extension keeps timing out at 30 seconds," or "this works in the simulator but not in production."

I've walked that road. The first time I built a Notification Service Extension (NSE), I had to stitch together fragments from ten different Apple docs, Stack Overflow threads, and forum posts before anything actually rendered. This article is the guide I wish I'd had: a Rork-friendly walkthrough that takes you from a bare app to a production-quality NSE that handles image attachments, end-to-end encrypted payloads, dynamic APNs payload rewriting, and the monitoring you'll actually want once it ships. The code assumes you've generated native iOS targets with Rork Max, but the same patterns apply if you're coming from an Expo bare workflow or a React Native project.

Why a Notification Service Extension Is Worth the Effort

iOS push notifications, by default, just show whatever APNs hands them. That works for plain text, but production apps run into three hard limits.

First, APNs payloads can't carry attachments. The hard cap is 4096 bytes over HTTP/2 — not even one Retina image fits. Instead, your payload includes an image URL, and the device has to download and attach it before showing the notification. The "modify the notification on-device" job is exactly what a Notification Service Extension is for.

Second, anything you put in an APNs payload passes through Apple's servers. For chat apps, finance apps, or any product where end-to-end encryption is non-negotiable, you can't ship the message body in plaintext. The server sends an encrypted payload, the device decrypts it inside the extension, and only then does the user see the actual content. This too is an NSE job.

Third, per-user, per-locale, per-timezone rewriting. If you want to send "3 hours until your deadline" to users across many languages, generating the localized strings on the server scales poorly. Rendering them on-device, where the locale and the user's nickname already live, is far cleaner — and again, NSE is where that code runs.

The thread tying all three together: APNs is not a trusted boundary. The device is. NSE is the only sanctioned way to do final-mile work on a notification, and Rork apps can use it freely once you open the native target and add the extension.

The Notification Pipeline, End to End

Before any code, it's worth being clear about when an NSE actually runs and what it can and can't do. Without this mental model, the 30-second deadline and the 50 MB memory ceiling will feel like random gotchas.

For a normal push, APNs hands the payload to the system, which renders it in Notification Center or the lock screen. When the payload contains mutable-content: 1, the system instead launches your app's NSE first and hands the notification to your UNNotificationServiceExtension subclass.

Inside the extension, didReceive(_:withContentHandler:) is called. You can rewrite the title, attach an image you just downloaded, decrypt a sealed payload, swap in a localized template — and when you're done, you call contentHandler with the modified content. The system then displays whatever you returned.

The hard constraints: 30 seconds of wall-clock time, ~50 MB of memory. If you're getting close to 30 seconds, the system calls serviceExtensionTimeWillExpire() so you can return your best-effort result before being killed. If you ignore it and overrun, the user sees the original payload — usually meaning no image and no decrypted body. The 50 MB limit bites harder than you'd expect; loading a 4K image with UIImage(data:) can blow it out by itself, so always downsample.

One more thing that catches people: the NSE runs in a different process from your main app, with its own bundle identifier. Sharing tokens or settings via Keychain or UserDefaults requires explicit App Group and Keychain Access Group configuration. If you skip this, you'll spend an evening debugging errSecItemNotFound.

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
If your push notifications never seem to show images and your open rates aren't moving, you'll walk away with a working Rich Push implementation today
You'll learn how to encrypt APNs payloads on the server and decrypt them on-device inside the extension, including the Swift code and the Keychain access group setup that usually trips people up
You'll get a battle-tested pattern for staying inside the 30-second runtime and 50 MB memory budget while still doing image downloads, localization, and personalization
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-05-01
Implementing CallKit + PushKit in Rork: Native Call UI and VoIP Push for Voice & Video Apps
A practical, production-grade walkthrough for wiring CallKit and PushKit into a Rork-built voice or video calling app — covering token lifecycle, audio sessions, App Store review risks, and the WebRTC handoff.
Dev Tools2026-07-17
Shipping Notifications Without Asking First — Provisional Authorization in Rork Apps, and the Expo Snippet That Quietly Undoes It
iOS lets you start delivering notifications with no permission dialog at all, via provisional authorization. The catch: expo-notifications reports granted as false for provisional devices, so the registration snippet in Expo's own docs re-requests permission and fires the very dialog you were avoiding. Here's why granted lies, a hook that models authorization as five states, how to write notifications for quiet delivery, when to ask for the upgrade, and how to keep provisional out of your CTR.
Dev Tools2026-07-17
Killing the Export Compliance Prompt in Rork Builds for Good
Every Rork and Rork Max build lands in App Store Connect with a Missing Compliance warning. Here is how to decide whether you qualify for the exemption, and how to set it once in app.json or Info.plist so the question never returns.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →