Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Increase widget visibility on Apple Watch using RelevanceKit. Use when providing contextual relevance signals for watchOS widgets, declaring time-based or location-based relevance, combining multiple relevance providers, helping the system surface the right widget at the right time on watchOS 26, or routing mixed RelevanceKit/WidgetKit/HealthKit/MapKit Smart Stack scope.
.claude/skills/dpearson2699-relevancekit/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 154% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 88% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 122% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 68% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 143% | 0% |
Provide on-device contextual clues that increase a widget's visibility in the Apple Watch Smart Stack. RelevanceKit tells the system when a widget is relevant by time, location, fitness state, sleep schedule, or connected hardware. Targets Swift 6.3 / watchOS 26+.
> Beta-sensitive. Re-check Apple documentation before making strong RelevanceKit availability or behavior claims.
See references/relevancekit-patterns.md for complete relevant-widget, timeline provider, grouping, preview, and permission patterns.
watchOS uses two mechanisms to determine widget relevance in the Smart Stack:
relevance() on an existingAppIntentTimelineProvider to attach RelevantContext clues to timeline entries. Available across platforms; only watchOS acts on the data.
RelevanceConfiguration with aRelevanceEntriesProvider to build a widget driven entirely by relevance clues. The system creates individual Smart Stack cards per relevant entry. watchOS 26+ only.
Choose a timeline provider when the widget always has data to show and relevance is supplementary. Choose a relevant widget when the widget should only appear when conditions match, or when multiple cards should appear simultaneously (e.g., several upcoming calendar events).
| Type | Module | Role | |---|---|---| | RelevantContext | RelevanceKit | A contextual clue (date, location, fitness, sleep, hardware) | | WidgetRelevance | WidgetKit | Collection of relevance attributes for a widget kind | | WidgetRelevanceAttribute | WidgetKit | Pairs a widget configuration with a RelevantContext | | WidgetRelevanceGroup | WidgetKit | Controls grouping behavior in the Smart Stack | | RelevanceConfiguration | WidgetKit | Widget configuration driven by relevance clues (watchOS 26+) | | RelevanceEntriesProvider | WidgetKit | Provides entries for a relevance-configured widget (watchOS 26+) | | RelevanceEntry | WidgetKit | Data needed to render one relevant widget card (watchOS 26+) |
RelevanceConfiguration, RelevanceEntriesProvider, and RelevanceEntry are WidgetKit APIs. Keep them in this skill's scope only when they are part of the watchOS relevant-widget workflow that exposes RelevanceKit clues.
swiftimport RelevanceKit import WidgetKit
RelevantContext is declared across platforms (iOS 17+, watchOS 10+), but RelevanceKit functionality only takes effect on watchOS. Calling the API on other platforms has no effect. Timeline-provider relevance() is available on iOS 18+, macOS 15+, visionOS 26+, and watchOS 11+ for shared provider code. RelevanceConfiguration, RelevanceEntriesProvider, and RelevanceEntry are watchOS 26+ only.
Certain relevance clues require authorization or target setup:
| Clue | Required Permission | |---|---| | .location(inferred:) | Containing app requests location access; widget extension declares NSWidgetWantsLocation | | .location(_:) (CLRegion) | Containing app requests location access; widget extension declares NSWidgetWantsLocation | | .location(category:) | Containing app requests location access; widget extension declares NSWidgetWantsLocation | | .fitness(.workoutActive) | HealthKit access to HKWorkoutType | | .fitness(.activityRingsIncomplete) | HealthKit access to appleExerciseTime, appleMoveTime, and appleStandTime | | .sleep(_:) | HealthKit sleepAnalysis permission | | .hardware(headphones:) | None | | .date(...) | None |
Add location purpose strings to the containing app's Info.plist, not only the widget extension. In widget code, check CLLocationManager.isAuthorizedForWidgetUpdates before relying on location clues. For fitness and sleep clues, enable HealthKit and request the exact read types in the app and widget extension target that provides relevance.
Add a relevance() method to an existing AppIntentTimelineProvider. This approach shares code across iOS and watchOS while adding watchOS Smart Stack intelligence.
swiftstruct MyProvider: AppIntentTimelineProvider { // ... snapshot, timeline, placeholder ... func relevance() async -> WidgetRelevance<MyWidgetIntent> { let attributes = events.map { event in let context = RelevantContext.date( from: event.startDate, to: event.endDate ) return WidgetRelevanceAttribute( configuration: MyWidgetIntent(event: event), context: context ) } return WidgetRelevance(attributes) } }
Build a widget that only appears when conditions match. The system calls relevance() to learn when the widget matters, then calls entry() with the matching configuration to get render data.
swift@available(watchOS 26.0, *) struct MyRelevanceProvider: RelevanceEntriesProvider { func relevance() async -> WidgetRelevance<MyWidgetIntent> { let attributes = events.map { event in WidgetRelevanceAttribute( configuration: MyWidgetIntent(event: event), context: RelevantContext.date(event.date, kind: .scheduled) ) } return WidgetRelevance(attributes) } func entry( configuration: MyWidgetIntent, context: Context ) async throws -> MyRelevanceEntry { if context.isPreview { return .preview } return MyRelevanceEntry(event: configuration.event) } func placeholder(context: Context) -> MyRelevanceEntry { .placeholder } }
When a feature mixes widgets, location, workouts, and Smart Stack relevance, keep RelevanceKit focused on RelevantContext, WidgetRelevanceAttribute, provider relevance(), RelevantIntentManager, relevant-widget handoffs, and permissions for relevance clues. Route timelines, reload budgets, families, rendering, APNs widget pushes, Live Activities, and widget Controls to WidgetKit; HKWorkoutSession, HKLiveWorkoutBuilder, HKWorkoutRoute, queries, activity-ring/sleep data, and authorization UX to HealthKit; and MKLocalSearch, MKLocalSearchCompleter, MKDirections, geocoding, authorization, regions, geofencing, and place data to MapKit/CoreLocation.
Time clues tell the system a widget matters at or around a specific moment.
swiftRelevantContext.date(eventDate)
DateKind provides an additional hint about the nature of the time relevance:
| Kind | Use | |---|---| | .default | General time relevance | | .scheduled | A scheduled event (meeting, flight) | | .informational | Information relevant around a time (weather forecast) |
swiftRelevantContext.date(meetingStart, kind: .scheduled)
swift// Using from/to RelevantContext.date(from: startDate, to: endDate) // Using DateInterval RelevantContext.date(interval: dateInterval, kind: .scheduled) // Using ClosedRange RelevantContext.date(range: startDate...endDate, kind: .default)
The system infers certain locations from a person's routine. No coordinates needed.
swiftRelevantContext.location(inferred: .home) RelevantContext.location(inferred: .work) RelevantContext.location(inferred: .school) RelevantContext.location(inferred: .commute)
Apply the location row in the Permissions table and check CLLocationManager.isAuthorizedForWidgetUpdates before returning clues.
swiftimport CoreLocation let region = CLCircularRegion( center: CLLocationCoordinate2D(latitude: 37.3349, longitude: -122.0090), radius: 500, identifier: "apple-park" ) RelevantContext.location(region)
Indicate relevance near any location of a given category. Returns nil if the category is unsupported. The factory is SDK-available on Apple platforms 26.0+, but RelevanceKit clues still only affect Smart Stack behavior on watchOS.
swiftimport MapKit if let context = RelevantContext.location(category: .beach) { // Widget is relevant whenever the person is near a beach }
swift// Relevant when activity rings are incomplete RelevantContext.fitness(.activityRingsIncomplete) // Relevant during an active workout RelevantContext.fitness(.workoutActive)
Apply the exact fitness mapping in Permissions.
swift// Relevant around bedtime RelevantContext.sleep(.bedtime) // Relevant around wakeup RelevantContext.sleep(.wakeup)
Apply the sleep mapping in Permissions.
swift// Relevant when headphones are connected RelevantContext.hardware(headphones: .connected)
No special permission required.
Return multiple WidgetRelevanceAttribute values in the WidgetRelevance array to make a widget relevant under several different conditions.
swiftfunc relevance() async -> WidgetRelevance<MyIntent> { var attributes: [WidgetRelevanceAttribute<MyIntent>] = [] // Relevant during morning commute attributes.append( WidgetRelevanceAttribute( configuration: MyIntent(mode: .commute), context: .location(inferred: .commute) ) ) // Relevant at work attributes.append( WidgetRelevanceAttribute( configuration: MyIntent(mode: .work), context: .location(inferred: .work) ) ) // Relevant around a scheduled event for event in upcomingEvents { attributes.append( WidgetRelevanceAttribute( configuration: MyIntent(eventID: event.id), context: .date(event.date, kind: .scheduled) ) ) } return WidgetRelevance(attributes) }
Order matters. Return relevance attributes ordered by priority. The system may use only a subset of the provided relevances.
swift@available(watchOS 26, *) struct MyRelevantWidget: Widget { var body: some WidgetConfiguration { RelevanceConfiguration( kind: "com.example.relevant-events", provider: MyRelevanceProvider() ) { entry in EventWidgetView(entry: entry) } .configurationDisplayName("Events") .description("Shows upcoming events when relevant") } }
When both a timeline widget and a relevant widget show the same data, use associatedKind to prevent duplicate cards. The system replaces the timeline widget card with relevant widget cards when they are suggested.
swiftRelevanceConfiguration( kind: "com.example.relevant-events", provider: MyRelevanceProvider() ) { entry in EventWidgetView(entry: entry) } .associatedKind("com.example.timeline-events")
WidgetRelevanceGroup controls how the system groups widgets in the Smart Stack.
swift// Opt out of default per-app grouping so each card appears independently WidgetRelevanceAttribute( configuration: intent, group: .ungrouped ) // Named group -- only one widget from the group appears at a time WidgetRelevanceAttribute( configuration: intent, group: .named("weather-alerts") ) // Default system grouping WidgetRelevanceAttribute( configuration: intent, group: .automatic )
When using a timeline provider, also update RelevantIntentManager so the system has relevance data between timeline refreshes.
swiftimport AppIntents func updateRelevantIntents() async { let intents = events.map { event in RelevantIntent( MyWidgetIntent(event: event), widgetKind: "com.example.events", relevance: RelevantContext.date(from: event.start, to: event.end) ) } try? await RelevantIntentManager.shared.updateRelevantIntents(intents) }
Call this whenever relevance data changes -- not only during timeline refreshes.
Use the entry, relevance-configuration, and full-provider recipes in Preview Recipes. Enable WidgetKit Developer Mode on the watch, test permissions granted and denied, and finish on a physical Apple Watch; see Testing Tips.
platforms but only has effect on watchOS.
relevant widget for the same data, use .associatedKind(_:) to prevent duplication.
updateRelevantIntents. When using timeline providers,calling this only inside timeline() means the system has stale relevance data between refreshes. Update whenever data changes.
location(category:). This factory returns an optional.Not all MKPointOfInterestCategory values are supported.
HealthKit, MapKit, and CoreLocation implementation remains in sibling scope.
and every clue uses the exact Permissions-table setup.
location category optionals and widget-update authorization are handled.
.associatedKind(_:) prevents duplicate cards, andupdateRelevantIntents runs whenever timeline-provider data changes.
granted and denied permission states.
implementations, permission handling, and grouping strategies
Other measured skills in the registry, with their headline benchmark lift.