●MAX — Rork Max generates native Swift for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with 2-click App Store publishing and no Xcode required●STACK — Standard Rork builds cross-platform mobile apps with React Native (Expo); choosing between the two by use case is the key decision●FOCUS — Unlike web-first tools such as Bolt or Lovable, Rork specializes in native iOS and Android app generation●BUGS — A hands-on review reports Rork resolved about 70% of bugs without manual help, with the remaining 30% needing edits in the exported codebase●FUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz)●PRICING — It is free to start, with paid plans from $25/month, so you can try before committing●MAX — Rork Max generates native Swift for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with 2-click App Store publishing and no Xcode required●STACK — Standard Rork builds cross-platform mobile apps with React Native (Expo); choosing between the two by use case is the key decision●FOCUS — Unlike web-first tools such as Bolt or Lovable, Rork specializes in native iOS and Android app generation●BUGS — A hands-on review reports Rork resolved about 70% of bugs without manual help, with the remaining 30% needing edits in the exported codebase●FUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz)●PRICING — It is free to start, with paid plans from $25/month, so you can try before committing
Putting Your Rork Max Native App's Content into iPhone Search — Becoming a 'Findable' App with Core Spotlight
Index the content of the native Swift app Rork Max generates into Core Spotlight, so users reach a specific in-app screen straight from iPhone search. Covers adding, updating, and removing index entries, plus the production trap of stale search results, from an indie developer's view.
A wallpaper-app user once told me: "I'd love to pull up that one favorite straight from the home screen search." Rather than opening the app, switching tabs, and hunting around, jumping directly to that content from iPhone-wide search (Spotlight) would indeed feel good.
Core Spotlight is what makes this possible. It puts in-app content into the iPhone's search index and lets a tapped search result return to the relevant screen. The fine details are hard to reach through a React Native bridge, but because Rork Max generates native Swift, importing CoreSpotlight lets you build everything from indexing to restoration cleanly. Here I'll work through becoming a "findable" app, centered on add/update/delete and the production traps.
Why it's worth appearing in Spotlight
An indie app, once installed, tends to be forgotten amid daily life. Running several free, AdMob-centric apps myself, I've felt keenly that how you create reasons to return shapes revenue. Indexing into Spotlight is a path where, the moment a user searches for something, your app's content quietly appears among the candidates. It's neither an ad nor a notification — it answers the user's active search calmly, so it doesn't break the experience.
But indexing isn't "set and forget." When content changes, the index must follow, and neglecting this leaves stale search results.
Step 1: Index content as a CSSearchableItem
First, convert in-app content into a CSSearchableItem and register it in the index. The uniqueIdentifier is the key for restoring the content later, so use a stable in-app ID.
import CoreSpotlightimport MobileCoreServicesfunc index(wallpaper id: String, title: String, thumbnail: Data) { let attr = CSSearchableItemAttributeSet(contentType: .image) attr.title = title attr.contentDescription = "Saved wallpaper" attr.thumbnailData = thumbnail // The thumbnail shown in results let item = CSSearchableItem( uniqueIdentifier: id, // Restore key. Use a stable ID domainIdentifier: "wallpaper", // The unit for bulk deletion attributeSet: attr ) CSSearchableIndex.default().indexSearchableItems([item]) { error in if let error = error { print("index failed: \(error)") } }}
Separating domainIdentifier per purpose makes category-wide bulk deletion easy later. I built without deciding this first and struggled to clear entries by group at delete time. I recommend partitioning it in the initial design.
✦
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
✦End-to-end code to index in-app content with CSSearchableItem and return to the right screen from a tapped search result
✦A design that keeps the index following content add/update/delete, plus how to diagnose the production symptom of a stale index
✦The criteria I used as an indie developer to narrow what gets indexed, and a practical approach to keeping reindex cost low
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.
Step 2: Return to the right screen from a tapped result
When indexed content appears in results and is tapped, the app launches via NSUserActivity. Pull out the uniqueIdentifier here and restore the corresponding screen.
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { guard userActivity.activityType == CSSearchableItemActionType, let id = userActivity.userInfo?[CSSearchableItemActivityIdentifier] as? String else { return false } Router.shared.openWallpaper(id: id) // Navigate directly to the screen return true}
Fail to pass id into navigation correctly here and opening from a result always drops users back to the top screen — a disappointing behavior. Returning from search is a path separate from a normal launch, so keep the routes distinct to be safe.
Step 3: Keep the index following add/update/delete
To keep the index fresh, update it along with the content lifecycle. Re-registering with the same uniqueIdentifier overwrites the content, and you delete what's no longer needed by ID.
// When content is gone, remove it from the index toofunc removeFromIndex(ids: [String]) { CSSearchableIndex.default() .deleteSearchableItems(withIdentifiers: ids) { error in if let error = error { print("delete failed: \(error)") } }}
The trap I hit in production was not removing the index entry when a user un-favorited something. The result: it appeared in search, but opening it showed "this is gone" — a mismatch. I fixed it by redesigning so content deletion and index deletion always happen in the same place.
Step 4: Index cost and a reindex strategy
Indexing is neither unlimited nor free. Registering a large batch at once burdens the device's indexing and shows up as perceptible jank on low-end devices. My approach is to update only changed items incrementally rather than reindexing everything on each launch. Register all items only the first time, then follow user actions partially afterward — that cuts cost substantially.
Also, passing thumbnailData as a large image makes the index heavy. Since what appears in results is a small thumbnail, handing over a pre-downscaled image is the practical choice.
Step 5: Narrow what you put into search
Technically you can index anything in the app, but what you should surface is limited to "things users recall by name and search for." The call I made as an indie developer was to index only favorites the user saved and named themselves, and not index system-generated lists or temporary screens. Noisy search results turn a useful path into one that erodes trust.
How to design a "findable" state
The value of Core Spotlight lies not in flashy features but in the app quietly answering the instant a user remembers it. Having long wrestled with creating reasons to return, I find this mechanism — sitting calmly beside the active act of searching — well suited to indie apps. Now that Rork Max puts native indexing APIs within reach, whether you can frame content as something to be "found" will, quietly, move your return rate. I hope this helps with your own implementation.
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.