What Are App Intents in iOS 26? The Developer Guide to Apple Intelligence Integration
Your app has a problem it doesn't know about yet.
When a user holds up their iPhone camera to a bottle of wine, a pair of sneakers, or a dish at a restaurant, iOS 26's Visual Intelligence kicks in. It scans the scene, figures out what's there, and surfaces results from apps that participate. If your app sells wine, shoes, or recipes — and you haven't adopted the new App Intents APIs — your app doesn't show up. At all.
That's the shift. Apps in 2026 aren't just launched. They're queried. Siri, Spotlight, and now Visual Intelligence reach directly into your app's data and act on it. The question isn't whether this matters. It's whether your app is ready.
This guide covers everything from scratch. What App Intents are, how they work, what iOS 26 adds, and how to implement each piece. Whether you've never written an AppIntent in your life or you're upgrading an existing implementation, you're in the right place.
What you'll need: Xcode 26+, the iOS 26 SDK, and a basic grasp of Swift and SwiftUI. That's it.
Jump to what you need:
- Part 1 — The Foundation: What App Intents are and how they evolved
- Part 2 — Core Primitives: The building blocks, explained
- Part 3 — iOS 26 Additions:
IntentValueQuery,@DeferredProperty, Snippets, Entity View Annotations - Part 4 — Apple Intelligence Deep Dive: Routing, phrases, MCP vs. App Intents
- Part 5 — Testing and Shipping: How to test, debug, and submit
- Part 6 — Common Mistakes: Six mistakes and how to avoid them
- Part 7 — Patterns by App Category: Where to start for your app type
- FAQs
Part 1 — The Foundation
What Are App Intents? (And Why They Matter More Than Ever in iOS 26)
The Core Idea in Plain English
Here's the simplest way to think about it.
Your app is a restaurant. It has a menu of things it can do — log a workout, find a recipe, track a package, add something to a cart. Before App Intents, the only way to access that menu was to walk in the front door (open the app), find a table (navigate to the right screen), and order yourself (tap the button yourself).
App Intents puts the menu in the window. The system — Siri, Spotlight, Shortcuts, Apple Intelligence — reads the menu and places orders on the user's behalf. The user doesn't have to open the app at all.
The important detail: the menu is declared, not discovered. You describe what your app can do in code at compile time, and the system learns it before the user ever asks. That's what makes zero-UI actions and proactive suggestions possible.
The Problem App Intents Replaced
Before iOS 16, Siri integration meant SiriKit. And SiriKit was... a lot. It locked you into predefined domains: messaging, payments, workouts, restaurant bookings. If your app didn't fit a domain, you were out of luck. If it did fit, the API was still painful.
App Intents threw that out. Any app can expose any action. The system doesn't care what category your app is in — if you implement the protocol, your actions are available in the system.
Here's the quick comparison:
| SiriKit | App Intents | |
|---|---|---|
| Flexibility | Fixed domains only | Any action, any data |
| Apple Intelligence support | No | Yes |
| Visual Intelligence | No | Yes (iOS 26+) |
| Code complexity | High (Intent definitions, response objects, extension) | Lower (Swift protocol conformance) |
| Availability | iOS 10+ | iOS 16+ |
App Intents is the present and the future. SiriKit is on maintenance mode.
Est. LoC (SiriKit)
2,500Est. LoC (App Intents)
250Every Surface Where App Intents Appear in iOS 26
One implementation, many surfaces. Here's where your App Intents show up once you've built them:
- Siri — spoken requests ("Hey Siri, log my water") and follow-up conversation
- Spotlight — search results with inline action buttons
- Shortcuts app — user-composable automations that chain your intents together
- Widgets — parameterized widget configurations (which project? which city?)
- Action Button (iPhone 15 Pro+) — one-tap trigger for a named intent
- Lock Screen Controls — quick-access system buttons
- Apple Intelligence — the AI layer that routes natural language to the right intent automatically
- Visual Intelligence (iOS 26 — NEW) — image-context queries that pull your entities into the camera overlay UI
💡 Not everything needs Apple Intelligence hardware. Shortcuts, Spotlight, and Siri work on all iOS 26 devices. Visual Intelligence requires iPhone 15 Pro or newer with Apple Intelligence enabled.
The Evolution of App Intents: iOS 16 Through iOS 26
If you're new to App Intents, this gives you context. If you've been using it since iOS 16, this is a quick "here's how we got here."
[iOS 16] ── The Foundation
│ (AppIntent, AppEntity, AppShortcutsProvider)
│
[iOS 17] ── Widget Integration
│ (AppIntentConfiguration, Smart Parameterization)
│
[iOS 18] ── Apple Intelligence Enters
│ (ProvidesDialog, ShowsSnippetView, AI Routing)
│
[iOS 26] ── App Intents 2.0
(IntentValueQuery, @DeferredProperty, SnippetIntent)
iOS 16 — The Foundation
This is where it started. Apple introduced the AppIntent protocol, AppEntity, AppShortcutsProvider, and Spotlight integration. The framework replaced SiriKit as the primary system integration API for new apps.
The limitation at this point: every property on an entity had to be fully computed before it was returned. No lazy loading. Everything upfront, every time.
iOS 17 — Widget Integration
iOS 17 brought AppIntentConfiguration, which made widgets smarter. Instead of a static widget, you could build a parameterized one — the user picks which project, which city, which habit to track. App Intents became the data bridge between your app and the home screen.
iOS 18 — Apple Intelligence Enters the Picture
This is when things got serious. Apple Intelligence launched with App Intents as its action surface — the layer through which AI-driven responses trigger real app behavior. Two new result types arrived: ProvidesDialog (a Siri response sentence) and ShowsSnippetView (attach a SwiftUI card to the response).
App Intents went from "nice to have for Shortcuts power users" to "your app's contract with Apple's AI."
iOS 26 — App Intents 2.0
Four additions. Same core model, extended into new surfaces:
IntentValueQuery— Visual Intelligence integration@DeferredProperty— async-computed entity propertiesSnippetIntent— interactive pop-up UI with system refresh support- Entity view annotations — context-specific rendering for your entities
The rest of this guide is mostly about these four. But first — the building blocks.
📌 Already shipping App Intents for iOS 18? Jump straight to Part 3. The iOS 26 additions are fully additive — your existing code doesn't break.
Part 2 — Core Primitives: The Building Blocks
The App Intents Framework: Core Concepts Every Developer Must Know
Before iOS 26 additions make sense, the core types need to click. This section is the "before we run, let's walk" part.
The AppIntent Protocol — Defining an Action
An AppIntent is a struct that represents one thing your app can do. It has a title (what the system calls it) and a perform() method (what happens when it runs).
import AppIntents
struct LogWaterIntakeIntent: AppIntent {
static var title: LocalizedStringResource = "Log Water Intake"
@Parameter(title: "Amount (ml)")
var amount: Int
func perform() async throws -> some IntentResult & ProvidesDialog {
WaterTracker.shared.log(ml: amount)
return .result(dialog: "Logged \(amount)ml of water.")
}
}
That's the whole shape. A title, optional parameters, and a perform() that runs the action and returns a result.
The perform() return type uses composition. ProvidesDialog tells Siri to speak the result. Add & ShowsSnippetView and you get a SwiftUI card alongside the dialog. Add & ReturnsValue<Int> and the Shortcuts app can chain the output into another step.
AppEntity — Your App's Data as a System Citizen
If AppIntent is the verb, AppEntity is the noun. It's a piece of your app's data the system can reference and display.
struct Recipe: AppEntity {
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Recipe")
static var defaultQuery = RecipeQuery()
var id: RecipeID
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(
title: "\(title)",
subtitle: "\(cuisine) · \(cookTime) min",
image: .init(named: imageName)
)
}
@Property(title: "Title") var title: String
@Property(title: "Cuisine") var cuisine: String
@Property(title: "Cook Time") var cookTime: Int
}
Three things are required: a unique identifier, a typeDisplayRepresentation (what the type is called), and a displayRepresentation (how an individual instance looks in the system UI).
AppShortcutsProvider — Registering Your Actions with the System
This is the registry. It tells Siri and Apple Intelligence what your app can do, in plain English phrases.
struct RecipeAppShortcuts: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: FindRecipeIntent(),
phrases: [
"Find a recipe in \(.applicationName)",
"What can I cook in \(.applicationName)?",
"Show me recipes in \(.applicationName)"
],
shortTitle: "Find a Recipe",
systemImageName: "fork.knife"
)
}
}
Phrases are how Siri finds your intent. Write them the way a real person would say them. The \(.applicationName) token disambiguates between apps — essential if your phrases are generic.
Common mistake: registering one phrase per intent. Siri needs variety to match natural speech. Aim for at least three phrases per intent.
@Parameter — Accepting Input
Parameters connect your intent to data. They can be entity types, simple values (String, Int, Bool), or system types (Date, Duration).
When a required parameter is missing, the system generates a follow-up question automatically using the parameter's title. You declare what you need; the system handles the conversation.
For dynamic options (a dropdown of your user's projects, for example), use DynamicOptionsProvider to return the list at query time.
IntentResult Composition
The return type of perform() describes what the system does with the result. Mix and match:
| Result type | What it does |
|---|---|
ReturnsValue<T> |
Returns a typed value to Shortcuts or Intelligence pipelines |
ProvidesDialog |
Returns a sentence for Siri to speak/display |
ShowsSnippetView |
Attaches a SwiftUI view to the response |
Compose them with &: some IntentResult & ProvidesDialog & ShowsSnippetView. All three together is perfectly valid.
EntityQuery and EntityStringQuery
Every AppEntity needs at least one query type so the system can fetch it.
EntityQuery— fetches entities by their identifiers. The system uses this internally to resolve a saved parameter reference.EntityStringQuery— adds string-search, enabling Spotlight and Siri to find entities by name.
If users ever refer to an entity by name (which they almost always do), implement both. EntityQuery alone makes your entities invisible to name-based searches.
Setting Up App Intents in Your Xcode Project
Good news: this isn't complicated.
Project Configuration
- No special entitlement needed for most App Intents features. Visual Intelligence (
IntentValueQuery) is the same — no extra entitlement as of iOS 26. - No Info.plist keys required for basic App Intents. Xcode handles the metadata generation at build time.
- Xcode 26+ is required. The build system generates App Intents metadata at compile time, which is why everything must be a compile-time declaration, not runtime registration.
Structuring Your App Intents Code
Keep it organized and you'll thank yourself later:
- One file per intent (
LogWaterIntakeIntent.swift) - One file per entity (
Recipe.swift,RecipeQuery.swift) - One
AppShortcutsProviderin the main app target
If an intent needs to run in the background without launching your app's UI, put it in an App Extension. But for most intents, the main app target is fine.
If you're using Swift Packages: entity and intent types can live in a package, but AppShortcutsProvider must be in the app target itself.
Your First AppIntent: The Minimal Working Version
Here's the fastest path from zero to a working intent:
- Create a struct conforming to
AppIntentwith atitleand aperform()method - Have
perform()do one thing and return aProvidesDialogresult - Register it in an
AppShortcutsProviderwith three natural-language phrases - Build and run the app once (this indexes the intents)
- Open the Shortcuts app, find your intent, run it
That's your baseline. From here, you're adding entities, parameters, and iOS 26 features on top of a working foundation.
Part 3 — iOS 26 Additions: App Intents 2.0
Visual Intelligence Integration with IntentValueQuery
This is the headline feature. If your app has any kind of visual content — products, food, places, objects — this is the most valuable iOS 26 addition you can adopt.
How Visual Intelligence Works: The System Flow
Here's what happens when a user points their camera at something:
- User opens Visual Intelligence (photo, screenshot, or live camera)
- The system's Vision and ML layer extracts semantic context from the image
- The system queries every app that has registered an
IntentValueQuerywith that context - Each app returns matching
AppEntityinstances - The system aggregates results and surfaces them in the Visual Intelligence UI
- The user taps a result to deep-link directly into the originating app
Your app's job is step 4. Everything else the system handles.
Critically: your query runs in the background. It doesn't launch your app. It's silent, fast, and automatic.
The IntentValueQuery Protocol
The protocol has one method:
import AppIntents
struct ProductLookupQuery: IntentValueQuery {
func values(for descriptor: SemanticContentDescriptor) async throws -> [Product] {
let candidates = try await catalog.search(labels: descriptor.labels)
return candidates.map(Product.init)
}
}
Register it on your entity:
struct Product: AppEntity {
static var defaultIntentValueQuery = ProductLookupQuery()
// ... rest of entity
}
That's the registration. One property. The system calls the query automatically when Visual Intelligence is active and your app is installed.
Understanding SemanticContentDescriptor
The descriptor the system passes to your query has two fields.
The labels Field — Semantic Tags from the System
An array of detected category and content tags. Think: ["wine bottle", "pinot noir", "label text", "red wine"]. The system's ML layer has already done the image recognition work. Your job is to map those tags to your own data.
Don't assume exact string equality. Fuzzy-match against your taxonomy, use synonyms, and handle partial matches. The labels are the system's best guess at what's in the image — work with them, not against them.
The pixelBuffer Field — Raw Visual Data
A CVReadOnlyPixelBuffer containing the actual image. Only use this if your app runs its own on-device vision model — a Core ML image classifier, a Vision framework request, something like that.
For most apps, labels is entirely sufficient and far cheaper to process. Save pixelBuffer for cases where the system's semantic tags aren't specific enough for your domain.
Implementing IntentValueQuery: Step-by-Step
- Confirm your entity is already registered as an
AppEntitywith adefaultQuery - Create a struct conforming to
IntentValueQuery - Implement
values(for:)— mapdescriptor.labelsto your data source - Declare the query on your entity:
static var defaultIntentValueQuery = YourQuery() - Unit test it — construct a
SemanticContentDescriptordirectly and callvalues(for:)to verify results before testing on hardware
Which Apps Should Implement IntentValueQuery?
If a user might ever point a camera at something and want your app to respond, implement it. That includes:
- Shopping and e-commerce — product catalog lookup from a photo
- Recipes and food — ingredient or dish identification
- Wine and beverage — label recognition
- Travel and navigation — landmark or place identification
- Fitness and wellness — exercise equipment or movement identification
- Any app where the answer to "what is this?" lives in your data
Scoping and Relevance: Returning Quality Results
This is where most first implementations go wrong.
The Visual Intelligence UI shows results from multiple apps side by side. If your app returns 20 loosely-matched results and another app returns 3 highly-relevant ones, users will trust the other app. Worse — the system may learn to deprioritize your results over time.
Return top 3–5 results, ranked by relevance. Good ranking signals:
- Text similarity between labels and your product/content names
- Recency of the user's interaction with that entity
- Personalization data if you have it (browsing history, purchase history, favorites)
Three excellent results beat twenty mediocre ones. Every time.
@DeferredProperty — Async Entity Values
This one's less flashy but genuinely solves an annoying problem.
The Problem: All-or-Nothing Property Computation
Before iOS 26, every @Property on an AppEntity had to be computed before the entity was returned from a query. If even one property needed a network fetch, the entire entity was slow to return.
The workaround was ugly: expose a "thin" entity for query results, build a separate "detail" intent to load the full data, and wire them together. It worked, but it was a lot of plumbing for what should be a simple idea.
How @DeferredProperty Solves This
@DeferredProperty declares a property as async-computed. The getter runs only when the system actually needs that value.
In practice: your entity returns fast with its cheap properties (title, subtitle, thumbnail). If the user selects it and the system needs the full details, then the deferred getter runs.
struct Recipe: AppEntity {
@Property(title: "Title") var title: String
@Property(title: "Cuisine") var cuisine: String
@DeferredProperty(title: "Full Instructions")
var instructions: String {
get async throws {
try await RecipeAPI.loadInstructions(id: id)
}
}
}
The instructions property is never computed during a query. It loads on demand, when the system actually needs it for a detail view.
When to Use It (and When NOT To)
Use @DeferredProperty for:
- Server-fetched fields (full descriptions, metadata, reviews)
- Large text bodies that require a disk read
- ML-computed scores or summaries
- Media metadata that's expensive to load
Don't use @DeferredProperty for:
- Fast in-memory lookups
- Computed properties that take under a millisecond
- Simple string formatting
The async overhead — task scheduling, awaiting, actor hops — is real. If your property is cheaper to compute than the overhead costs, you've made things slower, not faster.
Error Handling with @DeferredProperty
The getter is get async throws, so errors propagate naturally. If the getter throws, the system omits that property from the detail view. The entity still shows up — just without that field.
Best practice: throw typed errors so you can distinguish network failures from data-not-found. Log failures so you can diagnose them. Don't let errors silently vanish.
Interactive Snippets — Richer Responses in System Surfaces
One-line Siri responses are fine for simple actions. But for weather forecasts, package tracking, sports scores, or transit times — you need more than a sentence. That's what snippets are for.
What Is an App Intents Snippet?
A snippet is a small SwiftUI view the system displays alongside (or instead of) a dialog response. It appears in Spotlight, Visual Intelligence, and the Siri response surface.
Think of it as a card — compact, focused, interactive. The user can tap buttons, scroll content, and trigger follow-up actions without ever opening your app.
The golden rule: a snippet is a card, not an app. One primary result, one or two action buttons. That's the shape.
ShowsSnippetView vs. SnippetIntent — Choosing the Right Approach
AppIntent + ShowsSnippetView |
SnippetIntent |
|
|---|---|---|
| iOS availability | iOS 18+ | iOS 26+ |
| Use case | Attach a view to any intent's result | Design an intent specifically as a snippet |
| System reload | Not supported | static func reload() — system refreshes content |
| Best for | Adding snippets to existing intents | New live-updating features (scores, forecasts, ETAs) |
The decision is simple: upgrading an existing intent? Add ShowsSnippetView to its return type. Building a new intent designed to live as a refreshable card? Use SnippetIntent.
Building Your First Interactive Snippet
For a standard intent:
struct PackageTrackingIntent: AppIntent {
static var title: LocalizedStringResource = "Track Package"
@Parameter(title: "Tracking Number")
var trackingNumber: String
func perform() async throws -> some IntentResult & ProvidesDialog & ShowsSnippetView {
let status = try await ShippingAPI.status(for: trackingNumber)
return .result(
dialog: "Your package is \(status.summary).",
view: PackageStatusCard(status: status)
)
}
}
For a SnippetIntent with system refresh support:
struct LiveScoreSnippet: SnippetIntent {
static var title: LocalizedStringResource = "Live Score"
@Parameter(title: "Game")
var game: Game
func perform() async throws -> some IntentResult & ShowsSnippetView {
let score = try await SportsAPI.currentScore(for: game)
return .result(view: ScoreCard(score: score))
}
static func reload() async throws {
// System calls this when it wants fresh data
// Trigger a data refresh here
}
}
Your ScoreCard view is a normal SwiftUI view. Keep it self-contained, pass in a model object, and use system typography modifiers.
What Makes a Good Snippet (and What Doesn't)
Do this:
- ✅ One primary result per snippet
- ✅ One or two action buttons ("Open in App", "Mark Delivered", "Add to Calendar")
- ✅ System typography:
.headline,.body,.caption - ✅
AsyncImagefor images (non-blocking) - ✅ A clear "Open in App" escape hatch for complex flows
Avoid this:
- ❌ Navigation stacks, tab bars, or any multi-screen UI inside a snippet
- ❌ Login or onboarding flows inside a snippet
- ❌ More than 4 interactive elements
- ❌ Heavy images or video on initial render
- ❌ Blocking the view's body on a network fetch
Snippets in Spotlight, Visual Intelligence, and Siri
Good news: one snippet view works everywhere.
- Spotlight — snippet appears inline in the search result. The user never leaves the search UI.
- Visual Intelligence — snippet appears below the entity card. Context before the user decides to open the app.
- Siri — snippet is the visual component alongside the spoken dialog.
Build it compact and responsive and the system adapts it to each context automatically.
Entity View Annotations — How Your Entities Render
This is a quieter addition, but it fixes something that has always been a bit awkward.
The Old Single-Representation Model
Before iOS 26, DisplayRepresentation was one struct — one title, one subtitle, one image. The system used that same representation everywhere: a tight Spotlight list row, a Siri result card, a Visual Intelligence hero panel.
The problem: a compact list display looks anemic as a hero card. A hero card layout looks overcrowded in a list row. You had one shot and had to pick the least-bad option.
Context-Specific Rendering with iOS 26
iOS 26 lets entities declare multiple representation variants. The system picks the right one for the rendering context automatically. You don't detect the context in code — you just describe the variants and let the system decide.
Variant contexts:
- Compact list — Spotlight rows, tightly packed
- Standard card — Siri response surface
- Hero card — Visual Intelligence panel, full-width
Implementing Multiple Variants
The mechanism extends displayRepresentation with context-specific variants:
struct Recipe: AppEntity {
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(
title: "\(title)",
subtitle: "\(cuisine) · \(cookTime) min",
image: .init(named: thumbnailName)
)
}
// iOS 26: add a richer hero variant for Visual Intelligence
var heroDisplayRepresentation: DisplayRepresentation {
DisplayRepresentation(
title: "\(title)",
subtitle: "\(cuisine) · \(cookTime) min · ⭐️ \(rating)",
image: .init(named: heroImageName)
)
}
}
All variants share the same underlying entity data. Only the presentation layer changes.
When This Actually Matters
Entity view annotations make a real difference for apps with rich media content — recipes, products, locations, events. If your Visual Intelligence card previously felt sparse (just a title and a tiny thumbnail), annotations let you deliver a proper hero image and richer metadata there without affecting how the entity looks in Spotlight list rows.
Part 4 — Apple Intelligence Integration Deep Dive
How Siri and Apple Intelligence Route Requests to Your App
Understanding the routing pipeline is what separates intents that Siri finds reliably from ones that Siri never surfaces.
The Routing Pipeline
When a user says something to Siri, here's what happens:
- Apple Intelligence's natural language model parses the request
- It matches against registered
AppShortcutphrases across all installed apps - It resolves any parameters from context or by asking follow-up questions
- It calls
perform()on the matching intent
What the model uses to match: the phrases you wrote in AppShortcutsProvider, the titles on your parameters, and the typeDisplayRepresentation of your entities.
What you can't control: the routing logic itself. You influence it through clarity — clear phrases, well-named parameters, descriptive entity representations.
Writing Effective AppShortcut Phrases
This is where most developers leave performance on the table. Phrases are your lever. Use it.
Write the way users actually speak. Not "Initiate Water Log Entry" — "Log my water." Not "Execute Recipe Search" — "Find me something to cook."
Write at least three variants per intent:
- Imperative: "Log my water"
- Question: "Can you log my water intake?"
- Natural speech: "I want to add some water"
Use \(.applicationName) for disambiguation. If your phrase is generic ("set a reminder"), Siri might route it to the system instead. Specificity wins.
Avoid overlapping system phrases. Anything that sounds like "call," "message," "set a timer," or "navigate to" will lose to the OS. Go domain-specific.
Parameter Resolution and Follow-Up Disambiguation
When a required parameter is missing, the system generates a follow-up question from the parameter's title. You declared @Parameter(title: "Amount (ml)") — Siri asks "How many millilitres?"
For parameters that depend on each other (city → neighborhood, project → task list), use IntentParameterDependency. The system handles the branching conversation; your intent just declares the dependency.
Proactive Suggestions via Spotlight Donation
You don't need to manually donate interactions anymore. When you implement EntityStringQuery, the system automatically indexes your entities and surfaces them as proactive Spotlight suggestions.
The system learns from usage patterns. If a user logs water every morning, Siri will start suggesting it at that time. You get that for free — no extra code needed.
App Intents vs. MCP Tools — Which Should You Build?
With all the talk of AI agents lately, this question comes up constantly. Short answer: they're not competitors.
What App Intents Are Optimized For
- Apple's first-party surfaces — Siri, Spotlight, Shortcuts, Visual Intelligence, Action Button
- Privacy-first — all routing happens on-device; no data leaves Apple's stack without user consent
- Zero user configuration — if your app is installed, your intents are available, automatically
- Apple Intelligence orchestration — the system can chain your intents with other apps' actions
What MCP Tools Cover
- Third-party AI agents — Claude, ChatGPT, any LLM running locally or remotely
- Cross-app orchestration — "read my emails and create Jira tickets from the action items" (not something Apple Intelligence does today)
- Developer-to-developer integrations — exposing your data to the broader agent ecosystem beyond Apple
Decision Framework
| Goal | Use |
|---|---|
| Show up in Siri, Spotlight, Visual Intelligence | App Intents |
| Show up in Claude, ChatGPT, or other agents | MCP Tools |
| Show up in both | App Intents + local MCP server |
The good news if you want both: they share the same underlying data model. You write your business logic once and expose it through two thin protocol layers — AppIntent for Apple's surfaces, MCP tool handlers for agent surfaces.
Part 5 — Testing, Debugging, and Shipping
Testing Your App Intents Implementation
Shipping App Intents without testing them thoroughly is how you end up with Siri telling users she "can't help with that" — which is equally frustrating for users and for you.
Testing in the Shortcuts App
The Shortcuts app is your primary manual test surface. It's free, always available, and exposes exactly how the system sees your intents.
- Add your intent to a shortcut and run it
- Inspect parameters, dialogs, and snippet output
- Test parameter flows: remove a required parameter and verify the system prompts for it correctly
- Test edge cases: empty values, invalid inputs, network failures
Make this part of your routine before any release.
Unit Testing Intents
AppIntent.perform() is a plain async throwing function. Test it directly with XCTest or Swift Testing — no special setup required.
For IntentValueQuery: construct a SemanticContentDescriptor in your test and call values(for:) directly. Inject a mock data provider so results are predictable and fast.
func testProductLookupReturnsResults() async throws {
let query = ProductLookupQuery()
let descriptor = SemanticContentDescriptor(labels: ["sneakers", "running shoe"])
let results = try await query.values(for: descriptor)
XCTAssertFalse(results.isEmpty)
}
Mock your data layer. Tests that depend on a live server are tests waiting to fail.
Testing Visual Intelligence
Here's the hard truth: the full Visual Intelligence flow requires real hardware. You need an iPhone 15 Pro or newer, iOS 26+, and Apple Intelligence enabled in Settings → Apple Intelligence & Siri.
For CI pipelines: unit test the query logic. Use physical devices for integration testing of the full Visual Intelligence flow.
A useful shortcut (literally): build a Shortcut that manually calls your IntentValueQuery with a test descriptor. Much faster dev loop than holding the camera up at a test image every iteration.
Debugging Common Failures
| Problem | Likely cause | Fix |
|---|---|---|
| Intent not appearing in Siri or Spotlight | AppShortcutsProvider in wrong target |
Move it to the app target; call updateAppShortcutParameters() |
| Entity not resolving in a parameter | EntityQuery.entities(for:) isn't returning the entity |
Verify the query returns the entity for the identifier the system passes |
| Snippet not rendering | Missing ShowsSnippetView in return type |
Add & ShowsSnippetView and verify the view doesn't throw during init |
IntentValueQuery never called |
defaultIntentValueQuery missing on entity, or app not indexed |
Add the property; launch the app once on the device after a fresh install |
Performance Best Practices
App Intents run in the system's context with real time budgets. Slow queries and heavy snippets don't just feel bad — they get skipped.
Keep Entity Queries Fast
The system expects results quickly. If your query is slow, it loses the race to other apps' results or times out entirely.
- Cache frequently queried entities in memory
- Persist that cache between launches so the first query after a cold start is still fast
- For
IntentValueQuery: pre-index visual labels against your catalog at app launch so the query is an in-memory lookup, not a live search request
Scope Results for Quality Over Quantity
Return 3–5 results, ranked by relevance. Not 20. Not "everything that matches."
Good ranking signals: text relevance, recency of user interaction, personalization data. If the user just viewed a product, surface it first.
Snippet Render Budget
Snippets render in the system's process with a strict memory and time budget.
- Avoid heavy SwiftUI animations on initial render; save them for in-response interactions
- Load images asynchronously with
AsyncImage— never block the view's body - Target snippet init + first render under 100ms
App Store Submission Considerations
Privacy Manifest and App Intents
App Intents themselves don't require new privacy manifest entries. But:
- If your
IntentValueQueryprocesses thepixelBuffer(the raw camera image), document the relevant data category in your privacy manifest - If your intents access contacts, health data, or location, those existing permission flows apply — the system triggers the permission prompt before calling
perform()
Nothing exotic here. If you're already handling permissions correctly, you're fine.
Communicating Apple Intelligence Requirements to Users
Visual Intelligence results (IntentValueQuery) only appear on Apple Intelligence-capable devices. On everything else, your other App Intents work fine — Siri, Shortcuts, Spotlight.
In your App Store description and onboarding: don't gate the whole app on Apple Intelligence. Present Visual Intelligence features as enhancements for supported devices, not core requirements.
Part 6 — The Six Most Common App Intents Mistakes
Consider this the "we learned these the hard way so you don't have to" section.
Mistake 1: IntentValueQuery Returning Unscoped Results
What happens: the query returns every catalog item that vaguely matches any descriptor label.
Why it hurts: Visual Intelligence shows multiple apps' results simultaneously. A wall of unranked results from your app pushes your best matches off-screen. Users stop trusting your results.
Fix: build a relevance scorer. Return top-N sorted by score. Your best 3 results are worth more than your worst 20.
Mistake 2: Using @DeferredProperty for Fast Values
What happens: a simple computed property gets marked as @DeferredProperty because it's technically computed.
Why it hurts: async overhead — task scheduling, awaiting, actor hops — costs more than the computation you were trying to avoid.
Fix: reserve @DeferredProperty for genuinely expensive work: network calls, large disk reads, ML inference. If the property takes under a millisecond, keep it synchronous.
Mistake 3: Building Mini-Apps Instead of Snippets
What happens: the snippet gets a navigation stack, tab bar, settings screen, and onboarding flow crammed in.
Why it hurts: snippets render in a constrained surface. Complex layouts look broken. Users abandon them.
Fix: one primary result. One or two action buttons. An "Open in App" button for anything complex.
Mistake 4: Too Few Shortcut Phrases
What happens: one phrase per intent, written in internal app language ("Log Entry", "Recipe Search").
Why it hurts: Siri can't match natural speech to phrases that don't sound like natural speech.
Fix: three to five variants per intent. Include imperative, question, and casual phrasings. Use words your users actually say.
Mistake 5: Missing EntityStringQuery
What happens: EntityQuery is implemented (identifier-based), but EntityStringQuery is skipped.
Why it hurts: Spotlight can't index your entities by name. Siri can't resolve "my [entity name]" in a spoken request.
Fix: implement both. EntityStringQuery is required for any entity users refer to by name — which is almost all of them.
Mistake 6: Not Testing on Real Hardware
What happens: IntentValueQuery is tested via unit tests only, and the developer assumes Visual Intelligence is covered.
Why it hurts: the full system flow — image capture, semantic extraction, query aggregation, UI display — only happens on real hardware with a real Apple Intelligence session.
Fix: keep at least one iPhone 15 Pro (or newer) in your test device pool. No substitute for the real thing.
Part 7 — Real-World Patterns by App Category
Not sure where to start? Here's the playbook for six common app types.
Shopping and E-Commerce Apps
| Primary surface | IntentValueQuery (product from camera), EntityStringQuery (product search in Spotlight) |
| Best snippet | Product card: name, price, availability + "Add to Cart" / "Open in App" |
| Key intents | "Search for [product]", "Check price of [product]", "Add [product] to cart" |
@DeferredProperty targets |
Full product description, review summary, real-time inventory count |
Shopping apps are arguably the biggest winners from Visual Intelligence. Point camera at a product → your app surfaces it. That's a direct path to purchase with zero friction.
Recipe and Food Apps
| Primary surface | IntentValueQuery (ingredient/dish ID), EntityStringQuery (recipe by name) |
| Best snippet | Recipe card: title, cook time, difficulty + "Save Recipe" / "Start Cooking" |
| Key intents | "Find a recipe with [ingredient]", "Start cooking [recipe]", "Add [ingredient] to shopping list" |
@DeferredProperty targets |
Full ingredient list, step-by-step instructions |
The full recipe is the perfect @DeferredProperty candidate. The query only needs title, cook time, and a thumbnail. The instructions only matter when the user starts cooking.
Productivity and Task Management Apps
| Primary surface | Siri and Shortcuts (task creation, status checks), Spotlight (task search) |
| Best snippet | Task card: title, due date, priority + "Mark Complete" / "Reschedule" |
| Key intents | "Add a task to [project]", "What's due today?", "Mark [task] as done" |
| Visual Intelligence fit | Lower — task apps benefit less from image-based queries |
Focus your energy here on Siri phrase quality and Spotlight indexing. That's where task app users actually look.
Travel and Navigation Apps
| Primary surface | IntentValueQuery (landmark/place ID), Siri (navigation commands) |
| Best snippet | Location card: name, distance, rating, hours + "Navigate" / "Save Place" |
| Key intents | "Navigate to [place]", "How far is [destination]?", "Save [location] to favorites" |
@DeferredProperty targets |
Full business details, user reviews, operating hours fetched from API |
Visual Intelligence is high-value for travel. Point camera at a landmark → surface it in your app with reviews, opening hours, and a "Navigate" button.
Health and Fitness Apps
| Primary surface | Siri (log workouts, check stats), Spotlight (exercise search), Action Button (start workout) |
| Best snippet | Workout summary: stats + "Log Again" / "View Details" |
| Key intents | "Log a [workout type]", "How many steps today?", "Start a run" |
| Note | HealthKit permission triggers automatically before perform() runs |
The Action Button is a natural fit for fitness apps. One tap → start a workout. Set it up.
Media and Entertainment Apps
| Primary surface | Siri (play content, search), Spotlight (content discovery) |
| Best snippet | Content card: title, runtime + "Play" / "Add to Watchlist" |
| Key intents | "Play [show name]", "Add [movie] to my watchlist", "What's new in [genre]?" |
@DeferredProperty targets |
Full synopsis, cast details, streaming availability |
Siri phrase quality is critical for media apps. Users speak naturally ("find something funny to watch") — your phrases need to match that range.
Frequently Asked Questions
Do I need Apple Intelligence enabled to test App Intents features?
Not for most things. Siri, Shortcuts, and Spotlight work on all iOS 26 devices with Apple Intelligence disabled.
Visual Intelligence — and therefore IntentValueQuery — is the exception. It requires an Apple Intelligence-capable device (iPhone 15 Pro or newer) with Apple Intelligence enabled in Settings.
For development, you can bypass the hardware requirement for your query logic: call values(for:) directly in a unit test with a manually constructed SemanticContentDescriptor.
I already implemented App Intents for iOS 18 — how much work is the iOS 26 upgrade?
Not much. The iOS 26 additions are purely additive. Your existing AppEntity, AppShortcutsProvider, and AppIntent types don't need to change.
You're adding new conformances on top of what already exists:
IntentValueQueryfor Visual Intelligence@DeferredPropertyfor expensive properties- A snippet view for richer responses (optional)
- Entity view variants (optional)
Most teams adopt these incrementally, starting with whichever addition has the highest impact for their app category.
What's the difference between SnippetIntent and an AppIntent with ShowsSnippetView?
Both produce a snippet UI. The difference is refresh support.
SnippetIntent (iOS 26+) adds a static reload() method. The system can call it to update the snippet's content without re-invoking perform(). That makes it the right choice for live-updating content: sports scores, flight status, package tracking, weather.
AppIntent + ShowsSnippetView (iOS 18+) produces a snapshot of the result at the time perform() ran. Great for responses that don't need to update. If you're adding snippets to existing intents, start here.
Can IntentValueQuery and EntityQuery coexist on the same entity type?
Yes, and they should. They serve different contexts:
EntityQuery— resolves entities by identifier (Shortcuts, Siri parameter references)EntityStringQuery— name-based search (Spotlight, spoken Siri)IntentValueQuery— image-context queries (Visual Intelligence)
All three can be declared on the same AppEntity. The system picks the right one for the context automatically.
How do entity view annotations interact with widgets?
They don't — they're separate systems. Entity view annotations apply within App Intents contexts (Spotlight, Visual Intelligence, Siri). Widgets use WidgetKit's own view system.
If your app exposes the same data as both an AppEntity and a widget, you'll have two separate presentation layers: entity view annotations for system AI surfaces, and a WidgetKit TimelineEntry view for the home screen. They share the underlying data model; only the views differ.
My IntentValueQuery returns correct results in unit tests but doesn't appear in Visual Intelligence. What's wrong?
Check these in order:
defaultIntentValueQuerynot declared on the entity — addstatic var defaultIntentValueQuery = YourQuery()to your entity type- App not indexed — launch the app on the test device at least once after installing the new build
- Apple Intelligence disabled — check Settings → Apple Intelligence & Siri
- Device not capable — requires iPhone 15 Pro or newer; simulators don't support Visual Intelligence
Is there a performance cost to registering lots of App Intents?
Registration itself is negligible. App Intents are loaded lazily — the system only invokes the intents and queries relevant to the current context.
The performance cost lives in execution: your perform() and values(for:) implementations. If those are slow (synchronous network calls, blocking disk reads), that cost is felt at query time. Profile them with Instruments and keep them async.
Conclusion
What We Covered
We went from zero to the full iOS 26 App Intents surface:
- Part 1 — what App Intents are, every surface they appear on, and how the framework evolved from iOS 16 to today
- Part 2 — the core primitives:
AppIntent,AppEntity,AppShortcutsProvider, parameters, result types, and queries - Part 3 — the four iOS 26 additions in detail:
IntentValueQueryfor Visual Intelligence,@DeferredPropertyfor lazy entity loading,SnippetIntent/ShowsSnippetViewfor interactive response cards, and entity view annotations for context-aware rendering - Part 4 — how Apple Intelligence routes requests to your app, how to write phrases that actually work, and where MCP Tools fit versus App Intents
- Part 5 — how to test, debug, and ship: the Shortcuts app, unit testing, hardware requirements, and the common failure modes
- Part 6 — six mistakes and exactly how to avoid them
- Part 7 — concrete starting points for six app categories
Key Takeaways
- App Intents are your app's contract with Apple Intelligence. Every surface — Siri, Spotlight, Visual Intelligence — depends on how well you implement them.
- iOS 26's additions are additive. Your existing implementation doesn't break. You extend it.
IntentValueQueryis the highest-leverage new addition for apps with visual content. Visual Intelligence is new real estate. Claim it early.- Quality beats quantity. Fewer, better phrases. Fewer, more relevant query results. Smaller, more focused snippets.
- Test on real hardware. Visual Intelligence, Siri routing, and snippet rendering all behave differently in the actual system context than in unit tests.
Your Next Three Steps
Pick the one that fits your situation and start there.
If you're new to App Intents: write one intent, register it with three phrases, and test it in the Shortcuts app. Get that baseline working before adding anything else.
If you're upgrading an iOS 18 implementation: audit your AppEntity types for @DeferredProperty candidates first — it's the fastest win with the least risk. Then evaluate whether your app category benefits from IntentValueQuery.
If you're going all-in on iOS 26: start with IntentValueQuery (it's the most visible addition), layer in @DeferredProperty for expensive properties, then add snippets to your highest-value intents.
For further reference, see the App Intents framework documentation on Apple's developer portal, and WWDC25 Session 275: Explore new advances in App Intents.