View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Videos

Open Menu Close Menu
  • Collections
  • All Videos
  • About

Back to WWDC26

  • About
  • Summary
  • Transcript
  • Code-along: Make your app available to Siri

    Dive deep into an Xcode project showing how you can make your app available to Siri. Learn how to adopt App Schemas to let people ask questions about calendar events and take natural language actions like scheduling. Discover best practices for making content available in the Spotlight semantic index and providing context for on-screen awareness.

    Chapters

    • 0:00 - Introduction
    • 1:43 - App Schemas and the plan
    • 3:44 - Build the CalendarEntity
    • 8:00 - Build the AttendeeEntity
    • 10:30 - Build the EventEntity
    • 14:34 - Open events with OpenIntent
    • 15:30 - Onscreen awareness
    • 17:18 - Create events with Siri
    • 19:24 - Update events
    • 21:30 - Custom snippet views
    • 22:30 - Delete events
    • 23:35 - Next steps

    Resources

    • Integrating your calendar app with Apple Intelligence
    • Donating your app’s data and actions to the system
    • Donations and discovery
    • Making app entities available in Spotlight
    • Making actions and content discoverable by Apple Intelligence
    • Providing contextual cues to Apple Intelligence and Siri
    • Apple Intelligence and Siri AI
    • Calendar
    • App schema domains
      • HD Video
      • SD Video

    Related Videos

    WWDC26

    • Build intelligent Siri experiences with App Schemas
    • Explore advanced App Intents features for Siri and Apple Intelligence
  • Search this video…

    Hi, I'm Justin, an engineer on the Swift Intelligence Frameworks team. Welcome to this code-along. In this video, I'll take an app and make it available to Siri, step by step. Imagine I start a conversation with Siri on my iPhone and ask: "Who's coming to my picnic?" Siri searches for the event, its attendees, and shows me the guest list.

    I realize it includes that one friend that's always late, so I say: "Move it to noon… actually 11:30 am".

    Siri asks to confirm the details, and I say: "sounds good, thanks".

    Siri makes the changes and renders a custom view.

    Now I need to update my friends: "Text everyone going to the picnic and let them know about the change using emojis".

    After double-checking the message, I say: "Send it".

    And just like that, Siri sends the message. Then I remember the event's note had a reminder to bring something important to the picnic. So I ask: "What did I need to bring to the picnic again?" Siri searches the event and finds a note to myself to bring a chocolate cake.

    I'm curious how much time I have to get ready, so I say: "How long will it take to drive there?" Siri finds the event's location, and gives me an estimate.

    This is how Siri can make everyday things effortless… simply with a conversation. That's the mission for today.

    I'll take an existing app and make it available to Siri. Siri is powered by Apple Intelligence, Apple's personal intelligence system. Developers integrate their apps with Apple Intelligence through the App Intents framework, so their app's content and actions become available within Siri and other system experiences. The companion video "Build intelligent Siri experiences with App Schemas" covers the concepts behind the framework and how Apple Intelligence and Siri work with your app's content and actions. If App Intents is new to you, the video "Get to know App Intents" covers the core fundamentals like intents, entities, and queries, and how they connect to system features like Siri and Shortcuts.

    I've been working on a sample project called CometCal. It's a SwiftUI calendar app with a fun cosmic twist, and the source code is available for download on the Apple Developer website for you to follow along.

    It does all the basics of a calendar app: showing today's events, viewing and editing them, creating more, and even managing different calendars.

    Right now, the only way to interact with it though is through the screen… but that's about to change! In this video, I'm going to update CometCal so that Siri can: understand the app's content and answer my questions. And take actions like updating an event… making Siri more helpful than ever. The first step is giving Siri an understanding of my app's content. Right now, Siri has no idea what a calendar or an event means inside CometCal. That's where App Schemas come in. App Schemas describe my app's content and actions in terms Siri can already understand. They define the structure of my entities, the parameters of my actions, and the outputs. No training phrases, no natural language processing on my end. App Schemas are organized into App Schema Domains.

    The calendar domain covers everything related to scheduling: events, calendars, attendees, and the actions that operate on them. Now that the groundwork is set… time to suit up, jump into Xcode, and start the countdown! CometCal already has a CalendarModel in its data layer, that's the SwiftData model for calendars, like the difference between a Personal calendar and a Work calendar. The goal is to create an app entity that represents it using App Schemas, so Siri can understand what a calendar is in this app.

    I'll create a new Swift file called CalendarEntity, and import AppIntents.

    Next, I'll type calendar_ in the editor. Xcode offers every schema in the Calendar domain, right in autocomplete. Since the goal is a calendar entity, I'll select calendar_calendar.

    The snippet fills in the structure: the @AppEntity macro, properties, DisplayRepresentation and query stubs. This is now a schematized entity, a type Siri can reason over. A few things to fill in. First, I'll set the id type to UUID to match the data model.

    To enable matching by meaning and not just text, I'll conform to the IndexedEntity protocol. Conforming to IndexedEntity allows my app to donate entities using the Spotlight index to get the benefits of semantic understanding. When an entity is donated, Siri can resolve it by name, by property, or by context, without requiring a custom property query.

    To keep things moving, I added ways to convert between the data model and the entity.

    The CalendarEntity's initializer maps from CalendarModel to pull out what the entity needs. And the convenience .entity property on CalendarModel produces a CalendarEntity using the initializer. I'll use this soon in places like the query to convert between the two.

    Next, I'll add a @Dependency property for the CalendarManager in the query. That's CometCal's data layer that handles all the SwiftData operations. The @Dependency property wrapper is how App Intents injects shared resources into intents and queries, so instead of creating new instances, it provides the same object I register once as I've done on the right.

    The CalendarManager is main-actor isolated, so I'll also annotate the query struct as @MainActor.

    I'll implement the method required by the EntityQuery protocol. This fetches calendars by ID using the CalendarManager dependency. Now, EntityQuery covers cases where the system already knows an entity's ID. But later, when creating events, the system will need to know which calendars are available so Siri can offer them as options. For that, I'll conform to EnumerableEntityQuery and add an allEntities method that returns all calendars.

    For the DisplayRepresentation, I'll set the title to the calendar title and the image to a system image of a calendar. Siri and Spotlight use this when displaying the entities. That's one entity ready for orbit… almost. There's one more piece that's easy to miss. IndexedEntity defines the shape of my indexed content, but entities still need to be donated. To do that, I'll open the CalendarManager file.

    Anytime calendars, or any indexed entity for that matter, are changed, the index needs to be updated. For that, I have a CSSearchableIndex instance initialized in the CalendarManager's initializer that uses a unique name for CometCal. In the createCalendar method, just before returning the new calendar, I'll donate the entity by calling indexAppEntities using the searchable index instance from before.

    Similarly, in the updateCalendar method, I'll index the updated calendar entity.

    And in the deleteCalendar method, I'll remove the entity from the index by calling deleteAppEntities, passing in the entity's id and type.

    I'll fire up the engines and give it a go… I'll open CometCal and create a new calendar called "Lunar Orbit Log" Then, I'll swipe down to search for "Lunar Orbit Log"… and there it is with the calendar icon and the title. With CalendarEntity working, the next two entities follow the same pattern, but each introduces something new and shiny. Here's a new file called AttendeeEntity with AppIntents already imported. Same pattern as before… type calendar_attendee and select the snippet.

    The familiar parts are the same… All of that is wired up off-camera so I can keep moving at light speed. Feel free to pause here and check the completed source code. Unlike CalendarEntity, AttendeeEntity conforms to the TransientAppEntity protocol instead of IndexedEntity. That's intentional.

    A transient app entity is one that represents a temporary entity that doesn't require a unique identifier and isn't meant to be queried. That's the right fit here. In CometCal, an attendee represents a person's participation in a specific event, not the person themselves. The same person can attend multiple events, and indexing each attendance separately would create duplicative results in Spotlight. Since attendees are always accessed through the event that holds them, there's no need for an independent look up path. TransientAppEntity makes that explicit… no query to write, no index to maintain. Attendees have properties that are required by the schema like the boolean property to tell whether this attendance is optional.

    One new item is the IntentPerson type… the system's standard way to represent a person with a name and contact information. This is useful when sharing this data between apps, like sending an attendee's email address to draft a message in the Mail app. The schema also includes two @AppEnum types. The schema defines the set of possible cases, and my app adopts the ones that apply. These are also schematized, so I'll create them quickly using code snippets. I'll use the calendar_attendeeStatus snippet for status.

    The snippet comes with all the cases the schema supports. CometCal's model already maps directly, so no changes are needed, but if an app uses different terminology, simply map the existing model to the schema's cases so Siri can recognize the shape. Similarly, I'll use calendar_attendeeType for the attendee type.

    The schema requires at least one case to describe what kind of attendee this is and since CometCal's attendees are all people, I'll add a person case.

    I'll fill in the types for status and type respectively.

    And that takes care of the AttendeeEntity.

    That's two entities in orbit. One more to launch. The calendar and attendee entities find their orbit with the next one… the gravitational center that pulls them all together... the EventEntity. The system's search index really shines for the event entity. When someone asks "When is my crew lunch?", Siri can search the title. When they ask "What events mention oxygen?", it can search the note content. People can ask questions about their data, and Siri answers directly.

    Here's EventEntity with the calendar_event snippet already applied. Just like CalendarEntity, the EventEntity conforms to the IndexedEntity protocol and includes the indexing in CalendarManager to take advantage of the semantic index. There's a lot here. The schema covers a wide range of properties. But don't panic, the same patterns from the previous entities apply. The main difference is the number and variety of parameters.

    To keep this mission on schedule, the familiar pieces are wired up off-camera. Feel free to pause and check the source code. The schema defines which properties are required and which are optional. The essentials like title or startDate are straightforward to wire up. Optional properties that my app doesn't use, like travelTime or virtualLocation, can simply stay unset. Properties that aren't part of the schema but exist on the data model, like isFavorite, can also be added to the entity. What makes this entity interesting is how it composes with the other entities built earlier. The calendar this event belongs to is a CalendarEntity… and the attendees is an array of AttendeeEntity.

    Siri understands these relationships with App Schemas.

    The recurrence property is also one worth quickly pointing out.

    It can be used to represent events that repeat, like a weekly workout or an important yearly anniversary. It uses Foundation's Calendar.RecurrenceRule type and converts to and from CometCal's simple frequency enum for cases like daily, weekly, monthly or yearly.

    As part of the schema, there are also union values for an event's location and alarms.

    A union value is a property that can hold one of several different types. For example, the location can be either a PlaceDescriptor from the GeoToolbox framework, or a String. Again, we can simply implement these via code snippets.

    Like so. For alarms, it can be either a Duration or a Date.

    Assign the properties to these types accordingly.

    Like the attendee, there are also schematized enums here like the EventEntityStatus. Both enums related to events come complete from the snippets, so I'll add those and wire them up.

    Lastly, assign the status property to the new status type. And with that, the content layer is fully fueled and ready for launch.

    Time to find out if this thing has liftoff! On the left is the detail view of the Meteor Shower Watch Party. The time, location, and note are all there on screen… But imagine I'm mid-conversation with Siri talking about meteors, and I suddenly remember about the party. Instead of leaving the conversation to open CometCal and find the details, I can just ask… "Is the Meteor Shower Party happening anytime soon?" "What's the weather like out there?" I can also switch to typing: "When is the peak viewing time?" I can also tap on the result to take me to CometCal.

    Siri answers every question using the app's content. No need for custom natural language... just entities and schemas. Now, you may have noticed that tapping the event from my conversation with Siri opens CometCal, but it just lands on the main screen.

    It doesn't navigate to the event like I would expect. Siri doesn't know how to open a specific event in the app yet. I'm going to take a short detour to make this experience even better. To get this working, here's an OpenEventIntent. It's a small intent that conforms to the system.open schema. It takes an EventEntity as its target and tells the NavigationManager to navigate to that event. The system calls this whenever someone taps an event result in Spotlight or Siri, or asks Siri to open one.

    And that's it! Now if I tap on an event… this time, CometCal opens straight to the detail view of my Meteor Shower Watch Party. That's the OpenIntent bridging the gap. Siri can now understand the app's content better than ever, so people can ask Siri about any of it. Not bad for three structs and filling out a few code snippets, right? There's one more thing I can do to make my conversation with Siri feel even more natural. When someone has a specific event on screen, they might want to say something like "email the people in this event" without having to say the event's title. That's onscreen awareness... and it takes just two view modifiers. In CometCal's CalendarListView, where it lists all of my events, I'll add an .appEntityIdentifier modifier to the list, passing in an EntityIdentifier for each of the event entities. This connects the list to its entities, so when someone is browsing the list, the system knows which events are on screen. In the event detail view, when a single event's details are on screen, I'll append a .userActivity modifier with an EntityIdentifier. This tells the system that one specific event is front and center so Siri can resolve this event to exactly the one being viewed.

    And that's it! Here's what it enables.

    Now that Siri can understand what's currently onscreen and open event entities, I'll ask Siri to open the event in a natural way: "Hey Siri, open that third event." Now that I am currently on the Meteor Shower Watch Party detail view, I'll try referring to this event rather than saying the entire title… "Hey Siri, email the people in this event and ask someone to bring chocolate and marshmallows." Siri can use it's understanding of the onscreen event to find the attendees and hand them off to Mail.

    Seriously… two modifiers… that's all it takes to connect what's on screen to the app's content.

    Siri can now talk about the content. But to truly take off, I'll give Siri the ability to act. Once again, App Schemas lead the way, and this is where things get really interesting. I'll start with creating events. Just like entities, intents use code snippets too. I'll find the calendar_createEvent snippet and select it. It scaffolds the intent with the @AppIntent macro, the schema, all the parameters the schema requires, and a perform stub. The parameters, from title to note, come from the schema and I can use them in the intent's perform logic.

    I'll start by filling in the types. Then I'll add a @Dependency for the CalendarManager to use in the perform method. In the perform method, I'll mark it @MainActor and set EventEntity as the return value type.

    The general pattern is straightforward: resolve the intent's parameters into something the data layer understands, perform the action, and return the result as an entity. For creating a calendar event, that means resolving the parameters like extracting the location from the union value, and converting recurrence if provided. I'll pass everything to calendarManager's createEvent method and return the result as an EventEntity.

    Here's what's remarkable. Because this conforms to an App Schema, Siri can handle all the heavy lifting. Interpreting language, asking for clarification, and confirming details… so people can just have a natural conversation with Siri. Time to take it for a launch… Imagine I want to create a new event, but I'm mid-spacewalk and my iPhone is floating just out of reach. Instead of grabbing it, I'll just ask Siri... "Hey Siri, create a new event in the Lunar Orbit Log." "Call it Zero Gravity Yoga for June 15th, 8am." Siri can resolve the title, the date, and the time of the new event. When it's done, the event is added to the calendar.

    Just like that, a few lines of code and the app works with Siri. That's the power of App Schemas. Now that events can be created with Siri, I'll keep the momentum going with updating events.

    Here's UpdateEventIntent, already filled out using the calendar_updateEvent snippet. The structure is similar to the create intent, but the key difference is that most parameters are optional since someone might only change one or two things. The event parameter is what Siri resolves; everything else is optional. The perform logic follows the same pattern: resolve each parameter if provided, then pass everything to the CalendarManager's updateEvent method and return the updated event. It might be more code than the create intent, but there's nothing completely new happening here.

    However, there's one important subtlety with optional parameters in update intents worth calling out. For example, when recurrence is nil, does that mean "don't change it" or "remove it"? A simple nil check doesn't tell me which case I'm dealing with. Zooming into the recurrence logic in the perform method, the @AppIntent macro wraps each property in an IntentParameter which exposes a valueState. This is how I tell the difference. .set with an actual value means a new value is provided. .set with a nil value means it's explicitly cleared. .unset means the parameter isn't part of the request.

    This pattern applies to any optional parameter where clearing the value is a meaningful action. Now that the update intent is wired up, I'll send a few commands into orbit: "Hey Siri, move this to 10 in the evening." "Yep, that's fine" "Also, change this to repeat weekly and move it to my Deep Space calendar" "Sounds good" "Actually, do not repeat this event" The detail view reflects every change. All from a few lines of code and an App Schema.

    That update works, but Siri displays a default result card. This is CometCal, it deserves something with more... atmosphere. By default, Siri builds the result card from the display representation. Snippet views let me replace that with a custom SwiftUI view. I've prepared a SwiftUI view that takes an EventEntity and lays out the details in a stellar way. You can get really creative here… but also remember to keep it simple and lightweight.

    To wire this all up, I'll open UpdateEventIntent.

    I'll add ShowsSnippetView to the perform method's return type. Then in the return statement, I'll pass the EventSnippetView. The same approach works for any other intent that returns a result, like the create intent.

    "Hey Siri, push the crew lunch out by an hour" I now get the new snippet! The cosmic gradient accent, dark blue background, the updated event details and a star icon… That's the app's personality shining through within Siri. That covers the update intent. The last action to wire up is delete, and it's the simplest of the three. Here's the DeleteEventIntent. This is pretty simple… just the event and an optional span for recurring events. The perform logic finds the event and deletes it.

    Siri automatically handles the confirmation dialog before anything is removed.

    Time to test the ejection sequence: "Siri, delete that party." "Yes, delete it." "Also, delete the event happening June 9th." "Oh… actually, never mind." Siri asks for confirmation before deleting any event, and also makes sure to disambiguate when more than one event matches. Three intents. Full event management with Siri. Mission accomplished! CometCal has gone from screen-bound to fully voice-piloted. A lot got built during this video. Here are some next steps for making your own apps work with Siri. Download the CometCal sample project and explore the full implementation. Browse the App Intents documentation to explore all the available App Schemas and domains For automated testing, check out this video to learn how to write tests for CometCal using the new AppIntentsTesting framework.

    And watch "Explore advanced App Intents features for Siri and Apple Intelligence" to go deeper into ways to refine how your app works with Siri that weren't covered in this video. You're now mission-ready to take your app to the final frontier. Thank you so much for following along!

    • 0:00 - Introduction
    • Justin Kang previews the goal: take an existing app and make it available to Siri. A picnic scenario shows Siri searching events, updating times with confirmation, texting attendees, and answering questions, all through conversation.

    • 1:43 - App Schemas and the plan
    • Apps integrate with Apple Intelligence through App Intents, and App Schemas describe content and actions in terms Siri already understands, no training phrases or NLP. Schemas are organized into domains (here, the calendar domain). Introduces the CometCal sample app and the two goals: understand content, and perform actions.

    • 3:44 - Build the CalendarEntity
    • Create a schematized @AppEntity from the calendar_calendar snippet, set the id to UUID, conform to IndexedEntity, wire a @Dependency and @MainActor query (EnumerableEntityQuery with allEntities()), set a display representation, and donate to Spotlight via indexAppEntities and deleteAppEntities.

    • 8:00 - Build the AttendeeEntity
    • Built from calendar_attendee, but conforming to TransientAppEntity instead of IndexedEntity, attendees are accessed only through their event, so they need no identifier, query, or index. Introduces the IntentPerson type and two schematized @AppEnums (calendar_attendeeStatus, calendar_attendeeType).

    • 10:30 - Build the EventEntity
    • The central IndexedEntity (from calendar_event), where the semantic index shines for title and note-content questions. Composes the CalendarEntity and [AttendeeEntity], handles recurrence (Calendar.RecurrenceRule), union values for location and alarms, and event status/span enums.

    • 14:34 - Open events with OpenIntent
    • A small OpenEventIntent conforming to the system.open schema takes an EventEntity and tells the NavigationManager to navigate to it, so tapping an event in Spotlight or Siri opens straight to its detail view.

    • 15:30 - Onscreen awareness
    • Two view modifiers connect the screen to entities: .appEntityIdentifier on the event list and .userActivity (with an EntityIdentifier) on the detail view, letting Siri resolve "this event" or "that third event" without naming the title.

    • 17:18 - Create events with Siri
    • Build CreateEventIntent from calendar_createEvent: fill in parameter types, add a @MainActor @Dependency, and in perform() resolve the schema parameters (location union value, recurrence) into the data layer and return an EventEntity. Siri handles language, clarification, and confirmation.

    • 19:24 - Update events
    • UpdateEventIntent (calendar_updateEvent) mostly mirrors create, but parameters are optional. The key subtlety: an IntentParameter's valueState distinguishes .set with a value (change it), .set with nil (explicitly clear it), and .unset (not part of the request).

    • 21:30 - Custom snippet views
    • Replace Siri's default result card by adding ShowsSnippetView to the intent's return type and returning a custom SwiftUI EventSnippetView, bringing the app's visual personality (cosmic gradient, star icon) into Siri.

    • 22:30 - Delete events
    • DeleteEventIntent is the simplest, just the event plus an optional span for recurring events, and Siri automatically handles confirmation and disambiguation before deleting.

    • 23:35 - Next steps
    • Download the CometCal sample, browse the App Intents documentation for all schemas and domains, write tests with AppIntentsTesting, and watch "Explore advanced App Intents features for Siri and Apple Intelligence."

Developer Footer

  • Videos
  • WWDC26
  • Code-along: Make your app available to Siri
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines