Claude
Skills
Sign in
Back

relevancekit

Included with Lifetime
$97 forever

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.

General

What this skill does


# RelevanceKit

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](references/relevancekit-patterns.md) for complete relevant-widget, timeline provider, grouping, preview, and permission patterns.

## Contents

- [Overview](#overview)
- [Setup](#setup)
- [Relevance Providers](#relevance-providers)
- [Boundary Routing](#boundary-routing)
- [Time-Based Relevance](#time-based-relevance)
- [Location-Based Relevance](#location-based-relevance)
- [Fitness and Sleep Relevance](#fitness-and-sleep-relevance)
- [Hardware Relevance](#hardware-relevance)
- [Combining Signals](#combining-signals)
- [Widget Integration](#widget-integration)
- [Common Mistakes](#common-mistakes)
- [Review Checklist](#review-checklist)
- [References](#references)

## Overview

watchOS uses two mechanisms to determine widget relevance in the Smart Stack:

1. **Timeline provider relevance** -- implement `relevance()` on an existing
   `AppIntentTimelineProvider` to attach `RelevantContext` clues to timeline
   entries. Available across platforms; only watchOS acts on the data.
2. **Relevant widget** -- use `RelevanceConfiguration` with a
   `RelevanceEntriesProvider` 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).

### Key Types

| 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.

## Setup

### Import

```swift
import RelevanceKit
import WidgetKit
```

### Platform Availability

`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.

### Permissions

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.

## Relevance Providers

### Option 1: Timeline Provider with Relevance

Add a `relevance()` method to an existing `AppIntentTimelineProvider`. This
approach shares code across iOS and watchOS while adding watchOS Smart Stack
intelligence.

```swift
struct 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)
    }
}
```

### Option 2: RelevanceEntriesProvider (watchOS 26+)

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
    }
}
```

## Boundary Routing

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-Based Relevance

Time clues tell the system a widget matters at or around a specific moment.

### Single Date

```swift
RelevantContext.date(eventDate)
```

### Date with Kind

`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) |

```swift
RelevantContext.date(meetingStart, kind: .scheduled)
```

### Date Range

```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)
```

## Location-Based Relevance

### Inferred Locations

The system infers c
Files: 3
Size: 43.7 KB
Complexity: 46/100
Category: General

Related in General