RORK LABJP
GROWTH — Rork keeps growing with 743K monthly visits and an 85% growth rateMAX — Rork Max generates native Swift apps for iPhone, iPad, Watch, TV, Vision Pro, and iMessageMAX — It reaches AR/LiDAR scanning, Metal 3D games, Live Activities, HealthKit, and Core ML, beyond React Native's reachSTACK — Standard Rork builds iOS and Android together in React Native (Expo), so non-engineers can ship real appsPRICE — Plans start free, paid tiers from $25/month, and Rork Max at $200/monthMARKET — Gartner projects 75% of new apps will be low-code or no-code by the end of 2026GROWTH — Rork keeps growing with 743K monthly visits and an 85% growth rateMAX — Rork Max generates native Swift apps for iPhone, iPad, Watch, TV, Vision Pro, and iMessageMAX — It reaches AR/LiDAR scanning, Metal 3D games, Live Activities, HealthKit, and Core ML, beyond React Native's reachSTACK — Standard Rork builds iOS and Android together in React Native (Expo), so non-engineers can ship real appsPRICE — Plans start free, paid tiers from $25/month, and Rork Max at $200/monthMARKET — Gartner projects 75% of new apps will be low-code or no-code by the end of 2026
Articles/Dev Tools
Dev Tools/2026-07-04Advanced

Start a Live Activity Without Launching Your Rork Max App — Designing Around a push-to-start Token That Never Arrives

In a native Swift app generated by Rork Max, you want to start a Live Activity from your server without the user ever opening the app. But the push-to-start token is never observed and it fails silently. Here's the cause and an observation layer that reliably captures the token.

Rork Max213Live Activities6ActivityKit4push-to-startSwift40iOS102

Premium Article

The moment a ride is confirmed, I wanted the ETA to appear on the lock screen even if the user never opened the app — a server-initiated Live Activity. That's what I set out to add to a Rork Max app with push-to-start. Since iOS 17.2, you can start a Live Activity from a remote notification alone, without ever bringing the app to the foreground. But even with the implementation in place, the start token that was supposed to reach my server stayed empty forever. No error, no warning — the token was simply never observed.

The cause was that the task running Activity.pushToStartTokenUpdates never actually captured a token. As an indie developer working on the lock screen, this "the code is in but the token silently never comes" state is the first thing that stops you. This walks through adding a launch-from-cold path to a Rork Max native app with the smallest diff: how to isolate the silent failure, and an observation layer you can use as-is.

push-to-start and update run on different tokens

The first thing to sort out: remote control of a Live Activity involves two tokens with different natures. Confuse them and you'll capture one while the other jams, landing you in "why won't it work."

The roles of the start token and the update token

The first is the push-to-start token. It's the key to "starting a Live Activity that doesn't yet exist, from a cold app," and you can observe exactly one per app when ActivityAuthorizationInfo is enabled. The second is each Activity's update token, used to update or end an individual Activity that has already started.

push-to-start is per-app; update is per-Activity. That granularity difference carries straight into the delivery side. The apns-topic you send to APNs differs from a normal push (bundleId): for both start and update it's {bundleId}.push-type.liveactivity, with apns-push-type: liveactivity. Leave that topic the same as a normal push and, even with a valid token, delivery is rejected silently.

First, confirm the token is even being observed — from logs

Before chasing the cause by guesswork, I confirm on-device from logs whether the token-observation task is actually emitting values. push-to-start arrives via an async sequence, so if the task never started or got released midway, it just stops silently.

import ActivityKit
import os
 
let laLog = Logger(subsystem: "net.rorklab.sample", category: "liveactivity")
 
@MainActor
final class LiveActivityBootstrap {
    private var startTokenTask: Task<Void, Never>?
 
    func begin() {
        // Without permission, the token never comes
        guard ActivityAuthorizationInfo().areActivitiesEnabled else {
            laLog.error("live activities disabled by user")
            return
        }
        observeStartTokens()
    }
 
    private func observeStartTokens() {
        startTokenTask = Task {
            for await tokenData in Activity<DeliveryAttributes>.pushToStartTokenUpdates {
                let token = tokenData.map { String(format: "%02x", $0) }.joined()
                laLog.info("push-to-start token: \(token.prefix(12))…")
                await self.registerStartToken(token)   // send to server
            }
        }
    }
}

Note that pushToStartTokenUpdates is static on the Activity type. DeliveryAttributes is your own ActivityAttributes-conforming type, and you observe the app-wide start token bound to it. If the token fragment never appears in the logs, the cause is almost always either the observation task's start timing or permission.

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 can isolate from logs where push-to-start — starting a Live Activity from the server without opening the app — falls silent: permission, Info.plist, or the token-observation task
You get a thin observation layer that runs pushToStartTokenUpdates from launch and reliably delivers the token to your server, ready to drop into Rork Max's generated code
You'll sort out the two distinct token types used for start vs. update, down to the APNs topic on the delivery side that makes it work on a real device
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-06-26
Show Your Rork App's Progress on the Lock Screen and Dynamic Island
Add Live Activities and ActivityKit to a Swift app generated by Rork Max so a meditation timer or delivery status appears on the lock screen and Dynamic Island, with working code and the submission gotchas to watch for.
Dev Tools2026-06-14
Updating Live Activities Remotely: Putting Live Lock Screen Info on a Rork App
A practical design for updating Live Activities remotely through APNs so the Lock Screen and Dynamic Island stay current even when your app is closed. Covers push-to-start vs update tokens, the content-state payload, stale-date and the update budget, and bridging from Expo, with working code and the issues I hit in production.
Dev Tools2026-04-05
Rork Max × WidgetKit & Live Activities in Practice — From Home Screen to Dynamic Island
A complete guide to implementing iOS Widgets, Lock Screen widgets, and Dynamic Island Live Activities with Rork Max. Covers WidgetKit fundamentals, Timeline update strategies, App Intents integration, and monetization.
📚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 →