I read this thread https://developer.apple.com/forums/thread/788979 thoroughly, but I’m still confused regarding indexing files content.
I'm building a notes app where the notes are stored in files. A file can contain several notes (think paragraphs). Each note and the file document itself have a unique ID, all embedded in the file. So far so good, when the user opens a file in the app, I index all the notes in it using several CSSearchableItem, one for each note. Each CSSearchableItem gets a unique ID based on the note and file IDs.
The notes are then visible in Spotlight search and when the user taps one of them, the app is called with a Spotlight activity and I present the note.
I learned that I should create a CSImportExtension to allow the system to index files when app is not running. But the only method is update(_:forFileAt:), which allows to provide back to the system a single attributes set. How can I index the notes in a file as separate items?
What happens if an iCloud document file is edited remotely and the app is not running, or is editing another file? Does the system detect it and run CSImportExtension on the file?
All the notes and documents IDs are unique, and when the user duplicates the document file from within the app, new unique IDs are set in the duplicate file. But the user can also duplicate files outside the app, in which case the IDs remain the same in the duplicate file. How does Spotlight react to indexing two distinct items, with the same ID, but different 'contentURL'?
What if I index a note from a file, and set the current contentURL of the file, and then the user moves the file. Next time when I index a note from this file, Spotlight will get an item with the same uniqueIdentifier but with a different contentURL. Won't this confuse the system?
How to handle the case of deleted files: Unless a file is pending editing, the app doesn’t know it has been deleted, so it won’t remove the corresponding items from Spotlight.
I should mention that I use a Core Data database, which stores the mapping from file document IDs to file URLs, actually to bookmarks, so I can track the files even if the user renames or moves them.
                    
                  
                Core Spotlight
RSS for tagIndex your app so users can search the content from Spotlight and Safari using Core Spotlight.
Posts under Core Spotlight tag
            
              
                23 Posts
              
            
            
              
                
              
            
          
          
  
    
    Selecting any option will automatically load the page
  
  
  
  
    
  
  
              Post
Replies
Boosts
Views
Activity
                    
                      onContinueUserActivity(CSSearchableItemActionType, perform) works as expected on iOS when we search and select an item from Spotlight, but nothing happens when we do the same on a SwiftUI macOS app.
var body: some Scene {
    WindowGroup {
        MyView()
            .onContinueUserActivity(CSSearchableItemActionType, perform: handleSpotlight)
    }
}
func handleSpotlight(_ userActivity: NSUserActivity) {
    // Is not called...
}
How can we respond to a user clicking a Spotlight result from our apps on macOS?
                    
                  
                
                    
                      We are planning on renaming our app. The new name is not like the current name. It will be renamed in the App Store as well as the App display name. Yet, we still want new and existing users to be able to find the app by using the old name in search/spotlight under iOS. A great example of this is entering Twitter to find the X app and it shows up in the App section in the Spotlight search.
Are there any guidelines, settings, or tricks for doing this? Some have suggested adding a Spotlight search term but that will not have it show up in the App section I fear.
                    
                  
                
                    
                      On iOS 18, I'm trying to index documents in Spotlight using the new combination of AppIntents+IndexedEntity.
However, I don't seem to be able to index the textContent of the document. Only the displayName seems to be indexed.
As recommended, I start with the defaultAttributeSet:
/// I call this function to index in Spotlight
    static func indexInSpotlight(document: Document) async {
        do {
            if let entity = document.toEntity {
                try await CSSearchableIndex.default().indexAppEntities([entity])
            }
        } catch {
            DLog("Spotlight: could not index document: \(document.name ?? "")")
        }
    }
/// This is the corresponding IndexedEntity with the attributeSet
@available(iOS 18, *)
extension DocumentEntity {
    var attributeSet: CSSearchableItemAttributeSet {
        let attributeSet = defaultAttributeSet
        attributeSet.title = title
        attributeSet.displayName = title
        attributeSet.textContent = docContent
        attributeSet.thumbnailData = thumbnailData
        attributeSet.kind = "document"
        attributeSet.creator = Constants.APP_NAME
        return attributeSet
    }
}
How can I have more that the displayName to be indexed? Thanks :-)
                    
                  
                
                    
                      After more than a year since the announcement, I'm still unable to get this feature working properly and wondering if there are known issues or missing implementation details.
Current Setup:
Device: iPhone 16 Pro Max
iOS: 26 beta 3
Development: Tested on both Xcode 16 and Xcode 26
Implementation: Following the official documentation examples
The Problem:
Semantic search simply doesn't work. Lexical search functions normally, but enabling semantic search produces identical results to having it disabled. It's as if the feature isn't actually processing.
Error Output (Xcode 26):
[QPNLU][qid=5] Error Domain=com.apple.SpotlightEmbedding.EmbeddingModelError Code=-8007 "Text embedding generation timeout (timeout=100ms)"
[CSUserQuery][qid=5] got a nil / empty embedding data dictionary
[CSUserQuery][qid=5] semanticQuery failed to generate, using "(false)"
In Xcode 16, there are no error messages at all - the semantic search just silently fails.
Missing Resources:
The sample application mentioned during the WWDC24 presentation doesn't appear to have been released, which makes it difficult to verify if my implementation is correct.
Would really appreciate any guidance or clarification on the current status of this feature. Has anyone in the community successfully implemented this?
                    
                  
                
                    
                      I am wanting to not only surface my content in the system-level Spotlight search results but also to utilize the same index for my in-app search screen. The very few examples or tutorials I could find all craft a CSSearchQuery string using just the "title" attribute. I can't figure out where to look to understand how to search across other attributes.
My most pressing need is to be able to perform a CSSearchQuery looking for a search term in the .htmlContentData attribute. If I search for this term in the system search field it returns results, so I know it's being indexed. However when I use a search query (in my app) like htmlContentData == "someSearchTerm" I get zero results.
This frustration has led to some more general questions like:
How do you know what attribute names are available to use in the search query? Is it just a string literal that's exactly the same as the CSSearchableItemAttributeSet property in Swift? e.g. property .htmlContentData is referred to as "htmlContentData" in the query string?
Also, is there any way to just search across all attributes with CSSearchQuery? Obviously using the system Spotlight search (from Home Screen) you don't have to specify if you're searching the title or htmlContentData, it just finds it in either. Yet for CSSearchQuery I have to know up-front which fields I want to look in?
                    
                  
                
                    
                      I've been trying to add a CoreSpotlight indexer to my macOS application. The new template for the indexer uses the new appex CSImportExtension style importer.
I've been following this ->
https://developer.apple.com/documentation/corespotlight/csimportextension
I changed the CSSupportedContentTypes in the Info.plist file to the correct file type uti.
I added a dummy value into the attributes (see code below) - just setting contentDescription to 'noodle' (easy to search for)
class ImportExtension: CSImportExtension {
   override func update(_ attributes: CSSearchableItemAttributeSet, forFileAt: URL) throws {
      // Add a dummy value, and see whether spotlight finds it
      attributes.contentDescription = "noodle"
   }
}
I have a number of files on disk that match the uti (and can be found when I search by the file name)
Yet, when I build and run my app, the a spotlight search for 'noodle' finds no results.
Can anyone give me any advice? I cannot find any indication that the ImportExtension is called (although when I put a log message at the start of the  update() call there's no message in the console which seems to suggest it's not being called).
Is there any way of debugging this?
Cheers and thanks -- Darren.
                    
                  
                
                    
                      I've made working Spotlight Import Extension with in macOS 15.5 (24F74). mdimport confirm it's installed, and working. The problem is related to accessing data inside document bundles (package directory)
class ImportExtension: CSImportExtension {
  override func update(_ attributes: CSSearchableItemAttributeSet, forFileAt url: URL) throws {
    // ERROR: The file "QuickSort.notepad" couldn't be opened because you don't have permission to view it.
    let fileWrapper = try FileWrapper(url: url)
  }
}
forFileAt url points to a bundle. In order to read the metadata the extension needs to load the bundle from url and access its content, however in the sandbox environment,t the url allows only access to the bundle directory itself in particular NSFileWrapper(url: url) fails with error "The file "name.extension" couldn't be opened because you don't have permission to view it.", and effectively prevent from providing useful metadata.
Is there a way to access the Document Bundle content in order to read the metadata for Spotlight?
                    
                  
                
                    
                      I have a SwiftUI document-based app that for the sake of this discussion stores accounting information: chart of accounts, transactions, etc. Each document is backed by a SwiftData DB.
I'd like to incorporate search into the app so that users can find transactions matching certain criteria, so I went to Core Spotlight. Indexing & search within the app seem to work well.
The issue is that Spotlight APIs appear to be App based & not Document based. I can't find a way to separate Spotlight data by document.
I've tried having each document maintain a UUID as a document-specific identifier and include the identifier in every CSSearchableItem. When performing a query I filter the results with CSUserQueryContext.filterQueries that filter by the document identifier. That works to limit results to the specific file for search operations.
Index updates via CSSearchableIndexDelegate.reindex* methods seem to be App-centric. A user may have file #1 open, but the delegate is being asked to update CSSearchableItems for IDs in other files.
Is there a proper way to use Spotlight for in-app search with a document-based app?
Is there a way to keep Spotlight-indexed data local within the app & not make it available across the system? I.e. I'd like to search within the app only. System-level searches should not surface this data.
                    
                  
                
                    
                      I just adding a way to donate my app's data to Core Spotlight using CSSearchableIndex, but I'm finding that spotlight is only searching for the title of the CSSearchableItem I create. I know the index is working, because it always finds the item through the title property, but nothing else.
This is how I'm creating the CSSearchableItem:
- (CSSearchableItem *) createSearchableItem {
    
    CSSearchableItemAttributeSet* attributeSet = [[CSSearchableItemAttributeSet alloc] initWithContentType: UTTypeText];
    attributeSet.title = [self titleForIndex];
    attributeSet.displayName = [self titleForIndex];
    attributeSet.contentDescription = [self contentDescriptionForIndex];
    attributeSet.thumbnailData = [self thumbnailDataForIndex];
    attributeSet.textContent = [self contentDescriptionForIndex];
    
    CSSearchableItem *item = [[CSSearchableItem alloc] initWithUniqueIdentifier: [self referenceURLString] domainIdentifier:@"com.cjournal.cjournal-Logs" attributeSet:attributeSet];
    item.expirationDate = [NSDate distantFuture];
    return item;
}
There's a lot of confusing tips around which say specifying the 'textContent' should work, and/or setting the displayName is essential, but none of these are working.
Is there something I'm missing with my setup?
Thanks.
                    
                  
                
                    
                      In IOS17 and IOS18, core spotlight can only match app contents by searching for the displayName, but cannot hit the contents by using keywords. Moreover, when matching the app content by searching for the "displayName", it requires inputting four consecutive characters to achieve a match.These issues did not occur in iOS 16. What is the reason for this?
Here is my code.
func addItemToIndex(_ item: QSpotlightItem) {
    let attributeSet = CSSearchableItemAttributeSet(contentType: .item)
    attributeSet.title = item.title
    attributeSet.displayName = item.title
    attributeSet.contentDescription = item.contentDescription
    attributeSet.keywords = item.keywords
    attributeSet.thumbnailData = item.thumbnailImage
    attributeSet.contactKeywords = item.keywords
    attributeSet.supportsNavigation = true
    let searchableItem = CSSearchableItem(uniqueIdentifier: item.id, domainIdentifier: "xxx", attributeSet: attributeSet)
    searchableItem.expirationDate = .distantFuture
    CSSearchableIndex.default().indexSearchableItems([searchableItem]) { error in
        if let error = error {
        } else {
        }
    }
}
                    
                  
                
                    
                      In Core Spotlight, one can only index content by using title or displayName, and it requires four consecutive characters for indexing. These situations occurred in iOS 17 and 18. In iOS 16, I could not only index content by title or displayName, but also by keyword. Moreover, there was no restriction of requiring four consecutive characters. I could index my app content by simply inputting one character.
Here is my code.https://github.com/kritto1/corespotlight-bug-test/tree/main
@available(iOS 14, *)
func addItemToIndex(_ item: QSpotlightItem) {
    let attributeSet = CSSearchableItemAttributeSet(contentType: .item)
    attributeSet.title = item.title
    attributeSet.displayName = item.title
    attributeSet.contentDescription = item.contentDescription
    attributeSet.keywords = item.keywords
    attributeSet.thumbnailData = item.thumbnailImage
    attributeSet.contactKeywords = item.keywords
    attributeSet.supportsNavigation = true
    let searchableItem = CSSearchableItem(uniqueIdentifier: item.id, domainIdentifier: "com.qunar.iphone.spotlight", attributeSet: attributeSet)
    searchableItem.expirationDate = .distantFuture
    CSSearchableIndex.default().indexSearchableItems([searchableItem]) { error in
        if let error = error {
        } else {
        }
    }
}
@available(iOS 14, *)
func addToSpotlightIndex() {
    let spotlightHotel = QSpotlightItem(
                        id: "corespotlight_1",
                        title: "查询酒店住宿",
                        contentDescription: "",
                        thumbnailImage: UIImage(named: "img2")?.pngData(),
                        keywords: ["酒店", "住宿"]
                    )
    addItemToIndex(spotlightHotel)
    
    let spotlightFlight = QSpotlightItem(
                        id: "corespotlight_2",
                        title: "查询和预订机票",
                        contentDescription: "",
                        thumbnailImage: UIImage(named: "img2")?.pngData(),
                        keywords: ["查询", "预订", "机票"]
                    )
    addItemToIndex(spotlightFlight)
    
    let spotlightSight = QSpotlightItem(
                        id: "corespotlight_3",
                        title: "查询预订门票",
                        contentDescription: "",
                        thumbnailImage: UIImage(named: "img2")?.pngData(),
                        keywords: ["查询", "预订", "门票"]
                    )
    addItemToIndex(spotlightSight)
}
                    
                  
                
                    
                      Hi all,
has anybody found the trick how to get SwiftData working with SpotLight Search?
Setting the attribute "spotlight" in the Model definition seems to do nothing at all,  as pointed out by Paul Hudson in his new book as well
(https://www.hackingwithswift.com/quick-start/swiftdata/how-to-index-swiftdata-objects-in-spotlight)
Thanks a lot!
                    
                  
                
                    
                      I'd like to set the recordingYear in my Spotlight File Importer extension but the property is missing from CSSearchableItemAttributeSet
e.g. in the resulting in mdls I'd like to see:
kMDItemRecordingYear = 2008;
This would allow me to search in Finder by the recording year criteria.
There is a recordingDate property and I tried setting it to Date that only has a year but it didn't work. It just resulted in this:
kMDItemRecordingDate = "2008-01-01 00:00:00 +0000";
                    
                  
                
                    
                      The new Core Spotlight APIs in 18.4 and aligned releases for using Apple Intelligence models to summarize messages sort of work? But I'd say in my testing that only about 80% of the requests I send to Spotlight come back to the delegate with summaries and the rest are never returned. No errors logged in the delegate methods.
I can't figure out if there's a pattern. Before I dig apart my code, I'm wondering if anyone else here is using these brand-new APIs and has seen anything similar.
It's odd because my code to submit to Spotlight to be summarized is the same for all of my entities but some just never seem to be returned.
                    
                  
                
                    
                      Watched videos, blog post and downloaded their projects and there the core spot lights works accordingly.
I copied code to an empty project and did the same as what they did but still is not working
os: macOS and iOS
on coredataobject I settled up a attribute to index for spotlight and in object it self I putted the attribute name in display name for spotlight.
    static let shared = PersistenceController()
    
    var spotlightDelegate: NSCoreDataCoreSpotlightDelegate?
    @MainActor
    static let preview: PersistenceController = {
        let result = PersistenceController(inMemory: true)
        let viewContext = result.container.viewContext
        for _ in 0..<10 {
            let newItem = Item(context: viewContext)
            newItem.timestamp = Date()
        }
        do {
            try viewContext.save()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
        return result
    }()
    let container: NSPersistentContainer
    init(inMemory: Bool = false) {
        container = NSPersistentContainer(name: "SpotLightSearchTest")
        if inMemory {
            container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores(completionHandler: { [weak self] (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
            if let description = self?.container.persistentStoreDescriptions.first {
                description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
                description.type = NSSQLiteStoreType
                if let coordinator = self?.container.persistentStoreCoordinator {
                    self?.spotlightDelegate = NSCoreDataCoreSpotlightDelegate(
                        forStoreWith: description,
                        coordinator: coordinator
                    )
                    self?.spotlightDelegate?.startSpotlightIndexing()
                }
            }
        })
        container.viewContext.automaticallyMergesChangesFromParent = true
    }
}
in my @main view
struct SpotLightSearchTestApp: App {
    let persistenceController = PersistenceController.shared
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
                .onContinueUserActivity(CSSearchableItemActionType) {_ in 
                    print("")
                }
        }
    }
}
onContinueUserActivity(CSSearchableItemActionType) {_ in
print("")
}
never gets triggered. Sow What am I missing that they dont explain in the blog post or videos ?
                    
                  
                
                    
                      I wish to have all spotlight services stopped on my MacBook, however with turning all options off in the settings and also the "Help Apple Improve Search" option, however the option turns back on whenever there is a restart on the laptop as well as background services running. How can I disable this permanently?
I have tried to following as well:
sudo mdutil -a -i off
sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.metadata.mds.plist
sudo launchctl unload -w /System/Library/LaunchAgents/com.apple.metadata.mds.user.plist
sudo rm /Library/Preferences/com.apple.spotlight.plist
sudo launchctl disable system/com.apple.metadata.mds
However with  ps aux | grep -E "mds|Spotlight|corespotlightd" it still shows spotlight related services running:
User1          73830   0.0  0.0 410741568   1680 s018  S+   11:58am   0:00.00 grep -E mds|Spotlight|corespotlightd
root              3170   0.0  0.0 410682288   4816   ??  Ss   20Jan25   4:28.08 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Versions/A/Support/mds_stores
root              3168   0.0  0.0 427023376  14864   ??  Ss   20Jan25  33:53.97 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds
User1            593   0.0  0.1 434378432  45456   ??  S    20Jan25  14:00.32 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Versions/A/Support/corespotlightd
What else can I try in order to stop these and to stay shut off after turning my laptop on and off again?
                    
                  
                
                    
                      There's a 128mb limit for donating items to core spotlight. As far as I understand, there's a warning that shows in the Xcode console when either approaching or hitting that limit. It would be great if there was an API to check the current status of available storage for QA purposes to see if we're either donating too much or can donate more. Thanks!
                    
                  
                
                    
                      I've been exploring the Trails Sample App from this session at WWDC24.
The app has a TrailEntity of type AppEntity which is leveraged in multiple places throughout the app, including:
The GetTrailInfo App Intent with a trail parameter of type TrailEntity.
A parameterized App Shortcut which calls the GetTrailInfo intent.
The TrailDataManager's init calls updateSpotlightIndex(), which creates a CSSearchableItem for each Trail in the app, along with an associateAppEntity call linking the corresponding TrailEntity to each item that gets added to the CSSearchableIndex.
If you build the app and search "trails" in Spotlight, the Trails Sample App section includes instances of TrailEntity as search results. But if you comment out the App Shortcut that takes a TrailEntity as a parameter and rebuild, there are no instances of TrailEntity in the search results. In both cases, the console prints [Spotlight] Trails indexed by Spotlight.
Is this expected behavior? Why are the TrailEntity instances only appearing in Spotlight via the App Shortcut? Shouldn't the CSSearchableItem instances show up in Spotlight on their own regardless? If not, then what is the purpose of adopting Core Spotlight with App Entities? Does this add the app entities to the semantic index for "new Siri", even though they're not user facing in the Spotlight UI?
                    
                  
                
              
                
              
              
                
                Topic:
                  
	
		App & System Services
  	
                
                
                SubTopic:
                  
                    
	
		General
		
  	
                  
                
              
              
                Tags:
              
              
  
  
    
      
      
      
        
          
            Shortcuts
          
        
        
      
      
    
      
      
      
        
          
            Core Spotlight
          
        
        
      
      
    
      
      
      
        
          
            App Intents
          
        
        
      
      
    
      
      
      
        
          
            Apple Intelligence
          
        
        
      
      
    
  
  
              
                
                
              
            
          
                    
                      I am working to add Spotlight indexing for my app entities as discussed in WWDC24's video "What's New in App Intents".
That video goes over the IndexedEntity protocol and the integration with Spotlight via CSSearchableItemAttributeSet.
What I'm seeing though does not match the video. In the video, the presenter goes through the sort of progressive approach you can take to getting this data into Spotlight starting with the basics and then expanding to include more support depending on how much the developer wants to do.
What I'm seeing is that if you conform to IndexedEntity, your entities will appear in Spotlight using the name derived from
public var displayRepresentation: DisplayRepresentation
So, that works. Name appears... BUT the next part of the video goes into how to expand your implementation with more metadata for Spotlight via CSSearchableItemAttributeSet. The issue I'm seeing is that once that's implemented, the items disappear from Spotlight, almost like that implementation is overriding the base implementation in a way that no longer functions.
My expectation is that an item with custom attributes would use them in Spotlight as appropriate, not disappear from search, i.e. what's shown in the video should work.
I've got a sample project here:
https://hanchor.s3.amazonaws.com/misc/IndexingTest.zip
To reproduce with the sample:
Build and run. Indexing is setup in the init() method so it will just run.
Go to Spotlight and search for 'Huntersblau', a string included in the content set. At this point you should see a result - good!
Stop the app and go back and uncomment the var attributeSet: CSSearchableItemAttributeSet implementation in IndexingTestApp.swift. This will provide custom attributes to Spotlight.
Repeat steps 1 and 2 - you'll see now, it no longer appears in the search results - when CSSearchableItemAttributeSet is implemented, the item drops out of Spotlight.