{"id":"fa1af623-ded5-481a-834a-6cd5f5aea81f","shortId":"P2dzSz","kind":"skill","title":"sensorkit","tagline":"Access research-grade sensor data using SensorKit. Use when reading ambient light levels, accelerometer data, rotation rates, device usage patterns, keyboard metrics, or media events for approved research studies. Requires SensorKit entitlement and research study authorization.","description":"# SensorKit\n\nCollect research-grade sensor data from iOS and watchOS devices for approved\nresearch studies. SensorKit provides access to ambient light, motion, device\nusage, keyboard metrics, visits, phone/messaging usage, speech metrics, face\nmetrics, wrist temperature, heart rate, ECG, and PPG data. Targets\nSwift 6.3 / iOS 26+.\n\n**SensorKit is restricted to Apple-approved research studies.** Apps must submit\na research proposal to Apple and receive the `com.apple.developer.sensorkit.reader.allow`\nentitlement before any sensor data is accessible. This is not a general-purpose\nsensor API -- use CoreMotion for standard accelerometer/gyroscope needs.\n\n## Contents\n\n- [Overview and Requirements](#overview-and-requirements)\n- [Entitlements](#entitlements)\n- [Info.plist Configuration](#infoplist-configuration)\n- [Authorization](#authorization)\n- [Available Sensors](#available-sensors)\n- [SRSensorReader](#srsensorreader)\n- [Recording and Fetching Data](#recording-and-fetching-data)\n- [SRDevice](#srdevice)\n- [Common Mistakes](#common-mistakes)\n- [Review Checklist](#review-checklist)\n- [References](#references)\n\n## Overview and Requirements\n\nSensorKit enables research apps to record and fetch sensor data across iPhone\nand Apple Watch. The framework requires:\n\n1. **Apple-approved research study** -- submit a proposal at\n   [researchandcare.org](https://www.researchandcare.org/resources/accessing-sensorkit-data/).\n2. **SensorKit entitlement** -- Apple grants `com.apple.developer.sensorkit.reader.allow`\n   only for approved studies.\n3. **Manual provisioning profile** -- Xcode requires an explicit App ID with the\n   SensorKit capability enabled.\n4. **User authorization** -- the system presents a Research Sensor & Usage Data\n   sheet that users approve per-sensor.\n5. **24-hour data hold** -- newly recorded data is inaccessible for 24 hours,\n   giving users time to delete data they do not want to share.\n\nAn app can access up to 7 days of prior recorded data for an active sensor.\n\n## Entitlements\n\nAdd the SensorKit reader entitlement to a `.entitlements` file. List only the\nsensors your study uses:\n\n```xml\n<key>com.apple.developer.sensorkit.reader.allow</key>\n<array>\n    <string>ambient-light-sensor</string>\n    <string>motion-accelerometer</string>\n    <string>motion-rotation-rate</string>\n    <string>device-usage</string>\n    <string>keyboard-metrics</string>\n    <string>messages-usage</string>\n    <string>phone-usage</string>\n    <string>visits</string>\n    <string>pedometer</string>\n    <string>on-wrist</string>\n</array>\n```\n\nXcode build settings for manual signing:\n\n| Setting | Value |\n|---|---|\n| Code Signing Entitlements | `YourApp.entitlements` |\n| Code Signing Identity | `Apple Developer` |\n| Code Signing Style | `Manual` |\n| Provisioning Profile | Explicit profile with SensorKit capability |\n\n## Info.plist Configuration\n\nThree keys are required:\n\n```xml\n<!-- Study purpose shown in the authorization sheet -->\n<key>NSSensorKitUsageDescription</key>\n<string>This study monitors activity patterns for sleep research.</string>\n\n<!-- Link to your study's privacy policy -->\n<key>NSSensorKitPrivacyPolicyURL</key>\n<string>https://example.com/privacy-policy</string>\n\n<!-- Per-sensor usage explanations -->\n<key>NSSensorKitUsageDetail</key>\n<dict>\n    <key>SRSensorUsageMotion</key>\n    <dict>\n        <key>Description</key>\n        <string>Measures physical activity levels during the study.</string>\n        <key>Required</key>\n        <true/>\n    </dict>\n    <key>SRSensorUsageAmbientLightSensor</key>\n    <dict>\n        <key>Description</key>\n        <string>Records ambient light to assess sleep environment.</string>\n    </dict>\n</dict>\n```\n\nIf `Required` is `true` and the user denies that sensor, the system warns them\nthat the study needs it and offers a chance to reconsider.\n\n## Authorization\n\nRequest authorization for the sensors your study needs. The system shows the\nResearch Sensor & Usage Data sheet on first request.\n\n```swift\nimport SensorKit\n\nlet reader = SRSensorReader(sensor: .ambientLightSensor)\n\n// Request authorization for multiple sensors at once\nSRSensorReader.requestAuthorization(\n    sensors: [.ambientLightSensor, .accelerometer, .keyboardMetrics]\n) { error in\n    if let error {\n        print(\"Authorization request failed: \\(error)\")\n    }\n}\n```\n\nCheck a reader's current status before recording:\n\n```swift\nswitch reader.authorizationStatus {\ncase .authorized:\n    reader.startRecording()\ncase .denied:\n    // User declined -- direct to Settings > Privacy > Research Sensor & Usage Data\n    break\ncase .notDetermined:\n    // Request authorization first\n    break\n@unknown default:\n    break\n}\n```\n\nMonitor status changes through the delegate:\n\n```swift\nfunc sensorReader(_ reader: SRSensorReader, didChange authorizationStatus: SRAuthorizationStatus) {\n    switch authorizationStatus {\n    case .authorized:\n        reader.startRecording()\n    case .denied:\n        reader.stopRecording()\n    default:\n        break\n    }\n}\n```\n\n## Available Sensors\n\n### Device Sensors\n\n| Sensor | Type | Sample Type |\n|---|---|---|\n| `.deviceUsageReport` | Device usage | `SRDeviceUsageReport` |\n| `.keyboardMetrics` | Keyboard activity | `SRKeyboardMetrics` |\n| `.onWristState` | Watch wrist state | `SRWristDetection` |\n\n### App Activity Sensors\n\n| Sensor | Type | Sample Type |\n|---|---|---|\n| `.messagesUsageReport` | Messages app usage | `SRMessagesUsageReport` |\n| `.phoneUsageReport` | Phone call usage | `SRPhoneUsageReport` |\n\n### User Activity Sensors\n\n| Sensor | Type | Sample Type |\n|---|---|---|\n| `.accelerometer` | Acceleration data | `CMAccelerometerData` |\n| `.rotationRate` | Rotation rate | `CMGyroData` |\n| `.pedometerData` | Step/distance data | `CMPedometerData` |\n| `.visits` | Visited locations | `SRVisit` |\n| `.mediaEvents` | Media interactions | `SRMediaEvent` |\n| `.faceMetrics` | Face expressions | `SRFaceMetrics` |\n| `.heartRate` | Heart rate | Heart rate data |\n| `.odometer` | Speed/slope | Odometer data |\n| `.siriSpeechMetrics` | Siri speech | `SRSpeechMetrics` |\n| `.telephonySpeechMetrics` | Phone speech | `SRSpeechMetrics` |\n| `.wristTemperature` | Wrist temp (sleep) | `SRWristTemperatureSession` |\n| `.photoplethysmogram` | PPG stream | `SRPhotoplethysmogramSample` |\n| `.electrocardiogram` | ECG stream | `SRElectrocardiogramSample` |\n\n### Environment Sensors\n\n| Sensor | Type | Sample Type |\n|---|---|---|\n| `.ambientLightSensor` | Ambient light | `SRAmbientLightSample` |\n| `.ambientPressure` | Pressure/temp | Pressure data |\n\n## SRSensorReader\n\n`SRSensorReader` is the central class for accessing sensor data. Each instance\nreads from a single sensor.\n\n```swift\nimport SensorKit\n\n// Create a reader for one sensor\nlet lightReader = SRSensorReader(sensor: .ambientLightSensor)\nlet keyboardReader = SRSensorReader(sensor: .keyboardMetrics)\n\n// Assign delegate to receive callbacks\nlightReader.delegate = self\nkeyboardReader.delegate = self\n```\n\nThe reader communicates entirely through `SRSensorReaderDelegate`:\n\n| Delegate Method | Purpose |\n|---|---|\n| `sensorReader(_:didChange:)` | Authorization status changed |\n| `sensorReaderWillStartRecording(_:)` | Recording is about to start |\n| `sensorReader(_:startRecordingFailedWithError:)` | Recording failed to start |\n| `sensorReaderDidStopRecording(_:)` | Recording stopped |\n| `sensorReader(_:didFetch:)` | Devices fetched |\n| `sensorReader(_:fetching:didFetchResult:)` | Sample received |\n| `sensorReader(_:didCompleteFetch:)` | Fetch completed |\n| `sensorReader(_:fetching:failedWithError:)` | Fetch failed |\n\n## Recording and Fetching Data\n\n### Start and Stop Recording\n\n```swift\n// Begin recording -- sensor stays active as long as any app has a stake\nreader.startRecording()\n\n// Stop recording -- framework deactivates the sensor when\n// no app or system process is using it\nreader.stopRecording()\n```\n\n### Fetch Data\n\nBuild an `SRFetchRequest` with a time range and target device, then pass it to\nthe reader:\n\n```swift\nlet request = SRFetchRequest()\nrequest.device = SRDevice.current\nrequest.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400 * 2)  // 2 days ago\nrequest.to = SRAbsoluteTime.current()\n\nreader.fetch(request)\n```\n\nReceive results through the delegate:\n\n```swift\nfunc sensorReader(\n    _ reader: SRSensorReader,\n    fetching request: SRFetchRequest,\n    didFetchResult result: SRFetchResult<AnyObject>\n) -> Bool {\n    let timestamp = result.timestamp\n\n    switch reader.sensor {\n    case .ambientLightSensor:\n        if let sample = result.sample as? SRAmbientLightSample {\n            let lux = sample.lux\n            let chromaticity = sample.chromaticity\n            let placement = sample.placement\n            processSample(lux: lux, chromaticity: chromaticity, at: timestamp)\n        }\n    case .keyboardMetrics:\n        if let sample = result.sample as? SRKeyboardMetrics {\n            let words = sample.totalWords\n            let speed = sample.typingSpeed\n            processKeyboard(words: words, speed: speed, at: timestamp)\n        }\n    case .deviceUsageReport:\n        if let sample = result.sample as? SRDeviceUsageReport {\n            let wakes = sample.totalScreenWakes\n            let unlocks = sample.totalUnlocks\n            processUsage(wakes: wakes, unlocks: unlocks, at: timestamp)\n        }\n    default:\n        break\n    }\n\n    return true  // Return true to continue receiving results\n}\n\nfunc sensorReader(_ reader: SRSensorReader, didCompleteFetch request: SRFetchRequest) {\n    print(\"Fetch complete for \\(reader.sensor)\")\n}\n\nfunc sensorReader(\n    _ reader: SRSensorReader,\n    fetching request: SRFetchRequest,\n    failedWithError error: any Error\n) {\n    print(\"Fetch failed: \\(error)\")\n}\n```\n\n### Data Holding Period\n\nSensorKit imposes a **24-hour holding period** on newly recorded data. Fetch\nrequests whose time range overlaps this period return no results. Design data\ncollection workflows around this delay.\n\n## SRDevice\n\n`SRDevice` identifies the hardware source for sensor samples. Use it to\ndistinguish data from iPhone versus Apple Watch.\n\n```swift\n// Get the current device\nlet currentDevice = SRDevice.current\nprint(\"Model: \\(currentDevice.model)\")\nprint(\"System: \\(currentDevice.systemName) \\(currentDevice.systemVersion)\")\n\n// Fetch all available devices for a sensor\nreader.fetchDevices()\n```\n\nHandle fetched devices through the delegate:\n\n```swift\nfunc sensorReader(_ reader: SRSensorReader, didFetch devices: [SRDevice]) {\n    for device in devices {\n        let request = SRFetchRequest()\n        request.device = device\n        request.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400)\n        request.to = SRAbsoluteTime.current()\n        reader.fetch(request)\n    }\n}\n\nfunc sensorReader(_ reader: SRSensorReader, fetchDevicesDidFailWithError error: any Error) {\n    print(\"Failed to fetch devices: \\(error)\")\n}\n```\n\n### SRDevice Properties\n\n| Property | Type | Description |\n|---|---|---|\n| `model` | `String` | User-defined device name |\n| `name` | `String` | Framework-defined device name |\n| `systemName` | `String` | OS name (iOS, watchOS) |\n| `systemVersion` | `String` | OS version |\n| `productType` | `String` | Hardware identifier |\n| `current` | `SRDevice` | Class property for the running device |\n\n## Common Mistakes\n\n### DON'T: Attempt to use SensorKit without the entitlement\n\n```swift\n// WRONG -- fails at runtime with SRError.invalidEntitlement\nlet reader = SRSensorReader(sensor: .ambientLightSensor)\nreader.startRecording()\n\n// CORRECT -- obtain entitlement from Apple first, configure manual\n// provisioning profile, then use SensorKit\n```\n\n### DON'T: Expect immediate data access\n\n```swift\n// WRONG -- fetching data recorded moments ago returns nothing\nreader.startRecording()\n// ... record for a few minutes ...\nlet request = SRFetchRequest()\nrequest.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 300)\nrequest.to = SRAbsoluteTime.current()\nreader.fetch(request)  // Empty results due to 24-hour hold\n\n// CORRECT -- fetch data that is at least 24 hours old\nrequest.from = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400 * 3)\nrequest.to = SRAbsoluteTime(CFAbsoluteTimeGetCurrent() - 86400)\nreader.fetch(request)\n```\n\n### DON'T: Forget to set the delegate before fetching\n\n```swift\n// WRONG -- no delegate means no callbacks, results are silently lost\nlet reader = SRSensorReader(sensor: .accelerometer)\nreader.startRecording()\nreader.fetch(request)\n\n// CORRECT -- assign delegate first\nreader.delegate = self\nreader.startRecording()\nreader.fetch(request)\n```\n\n### DON'T: Skip per-sensor Info.plist usage detail\n\n```swift\n// WRONG -- missing NSSensorKitUsageDetail for the sensor\n// Authorization sheet shows no explanation, user is less likely to approve\n\n// CORRECT -- add usage detail for every sensor you request\n// See Info.plist Configuration section above\n```\n\n### DON'T: Ignore SRError codes\n\n```swift\n// WRONG -- generic error handling\nfunc sensorReader(_ reader: SRSensorReader, fetching: SRFetchRequest, failedWithError error: any Error) {\n    print(\"Error\")\n}\n\n// CORRECT -- handle specific error codes\nfunc sensorReader(_ reader: SRSensorReader, fetching: SRFetchRequest, failedWithError error: any Error) {\n    if let srError = error as? SRError {\n        switch srError.code {\n        case .invalidEntitlement:\n            // Entitlement missing or sensor not in entitlement array\n            break\n        case .noAuthorization:\n            // User has not authorized this sensor\n            break\n        case .dataInaccessible:\n            // Data in 24-hour holding period or otherwise unavailable\n            break\n        case .fetchRequestInvalid:\n            // Invalid time range or device\n            break\n        case .promptDeclined:\n            // User declined the authorization prompt\n            break\n        @unknown default:\n            break\n        }\n    }\n}\n```\n\n## Review Checklist\n\n- [ ] Apple-approved research study in place before development\n- [ ] `com.apple.developer.sensorkit.reader.allow` entitlement lists only needed sensors\n- [ ] Manual provisioning profile with explicit App ID and SensorKit capability\n- [ ] `NSSensorKitUsageDescription` in Info.plist with clear study purpose\n- [ ] `NSSensorKitPrivacyPolicyURL` in Info.plist with valid privacy policy URL\n- [ ] `NSSensorKitUsageDetail` entries for every requested sensor\n- [ ] `Required` key set appropriately for essential vs. optional sensors\n- [ ] Authorization requested before recording, status checked before fetching\n- [ ] Delegate assigned before calling `startRecording()` or `fetch(_:)`\n- [ ] Fetch request time ranges account for 24-hour data holding period\n- [ ] `SRError` codes handled in all failure delegate methods\n- [ ] `fetchDevices()` used to discover available devices before fetching\n- [ ] `stopRecording()` called when data collection is complete\n- [ ] `sensorReader(_:fetching:didFetchResult:)` returns `true` to continue or `false` to stop\n\n## References\n\n- Extended patterns (delegate wiring, multi-sensor manager, sample type details): [references/sensorkit-patterns.md](references/sensorkit-patterns.md)\n- [SensorKit framework](https://sosumi.ai/documentation/sensorkit)\n- [SRSensorReader](https://sosumi.ai/documentation/sensorkit/srsensorreader)\n- [SRSensor](https://sosumi.ai/documentation/sensorkit/srsensor)\n- [SRDevice](https://sosumi.ai/documentation/sensorkit/srdevice)\n- [SRFetchRequest](https://sosumi.ai/documentation/sensorkit/srfetchrequest)\n- [Configuring your project for sensor reading](https://sosumi.ai/documentation/sensorkit/configuring-your-project-for-sensor-reading)\n- [com.apple.developer.sensorkit.reader.allow](https://sosumi.ai/documentation/bundleresources/entitlements/com.apple.developer.sensorkit.reader.allow)","tags":["sensorkit","swift","ios","skills","dpearson2699","accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills"],"capabilities":["skill","source-dpearson2699","skill-sensorkit","topic-accessibility","topic-agent-skills","topic-ai-coding","topic-apple","topic-claude-code","topic-codex-skills","topic-cursor-skills","topic-ios","topic-ios-development","topic-liquid-glass","topic-localization","topic-mapkit"],"categories":["swift-ios-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/dpearson2699/swift-ios-skills/sensorkit","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add dpearson2699/swift-ios-skills","source_repo":"https://github.com/dpearson2699/swift-ios-skills","install_from":"skills.sh"}},"qualityScore":"0.684","qualityRationale":"deterministic score 0.68 from registry signals: · indexed on github topic:agent-skills · 468 github stars · SKILL.md body (15,741 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-22T00:53:44.516Z","embedding":null,"createdAt":"2026-04-18T22:01:15.588Z","updatedAt":"2026-04-22T00:53:44.516Z","lastSeenAt":"2026-04-22T00:53:44.516Z","tsv":"'/documentation/bundleresources/entitlements/com.apple.developer.sensorkit.reader.allow)':1547 '/documentation/sensorkit)':1518 '/documentation/sensorkit/configuring-your-project-for-sensor-reading)':1543 '/documentation/sensorkit/srdevice)':1530 '/documentation/sensorkit/srfetchrequest)':1534 '/documentation/sensorkit/srsensor)':1526 '/documentation/sensorkit/srsensorreader)':1522 '/privacy-policy':389 '/resources/accessing-sensorkit-data/).':210 '1':197 '2':211,819,820 '24':255,265,958,1185,1195,1356,1461 '26':85 '3':221,1202 '300':1176 '4':236 '5':254 '6.3':83 '7':285 '86400':818,1052,1201,1206 'acceler':592 'acceleromet':16,320,474,591,1233 'accelerometer/gyroscope':127 'access':2,57,113,282,667,1154 'account':1459 'across':189 'activ':293,381,395,560,568,585,765 'add':296,1274 'ago':822,1161 'ambient':13,59,315,404,653 'ambient-light-sensor':314 'ambientlightsensor':463,473,652,690,850,1134 'ambientpressur':656 'api':122 'app':95,182,229,280,567,576,770,783,1405 'appl':91,102,192,199,214,357,1001,1140,1386 'apple-approv':90,198,1385 'appropri':1434 'approv':29,52,92,200,219,250,1272,1387 'around':981 'array':1341 'assess':407 'assign':696,1238,1449 'attempt':1116 'author':38,144,145,238,435,437,465,482,498,516,539,716,1262,1348,1377,1440 'authorizationstatus':534,537 'avail':146,149,546,1020,1478 'available-sensor':148 'begin':761 'bool':843 'break':512,518,521,545,916,1342,1351,1363,1371,1379,1382 'build':343,793 'call':581,1451,1483 'callback':700,1224 'capabl':234,369,1409 'case':497,500,513,538,541,849,873,894,1332,1343,1352,1364,1372 'central':664 'cfabsolutetimegetcurr':817,1051,1175,1200,1205 'chanc':432 'chang':524,718 'check':486,1445 'checklist':170,173,1384 'chromat':861,869,870 'class':665,1106 'clear':1414 'cmaccelerometerdata':594 'cmgyrodata':598 'cmpedometerdata':602 'code':350,354,359,1291,1313,1467 'collect':40,979,1486 'com.apple.developer.sensorkit.reader.allow':106,216,313,1394,1544 'common':164,167,1112 'common-mistak':166 'communic':707 'complet':746,934,1488 'configur':140,143,371,1142,1284,1535 'content':129 'continu':922,1495 'coremot':124 'correct':1136,1188,1237,1273,1309 'creat':680 'current':490,1006,1104 'currentdevic':1009 'currentdevice.model':1013 'currentdevice.systemname':1016 'currentdevice.systemversion':1017 'data':7,17,45,80,111,156,161,188,246,257,261,272,290,451,511,593,601,620,624,659,669,755,792,952,965,978,997,1153,1158,1190,1354,1463,1485 'datainaccess':1353 'day':286,821 'deactiv':778 'declin':503,1375 'default':520,544,915,1381 'defin':1080,1087 'delay':983 'deleg':527,697,711,831,1031,1215,1221,1239,1448,1472,1503 'delet':271 'deni':417,501,542 'descript':392,402,1075 'design':977 'detail':1254,1276,1511 'develop':358,1393 'devic':20,50,62,326,548,555,736,802,1007,1021,1028,1038,1041,1043,1048,1069,1081,1088,1111,1370,1479 'device-usag':325 'deviceusagereport':554,895 'didchang':533,715 'didcompletefetch':744,929 'didfetch':735,1037 'didfetchresult':740,840,1491 'direct':504 'discov':1477 'distinguish':996 'due':1183 'ecg':77,643 'electrocardiogram':642 'empti':1181 'enabl':180,235 'entir':708 'entitl':34,107,137,138,213,295,300,303,352,1122,1138,1334,1340,1395 'entri':1426 'environ':409,646 'error':476,480,485,945,947,951,1062,1064,1070,1295,1304,1306,1308,1312,1321,1323,1327 'essenti':1436 'event':27 'everi':1278,1428 'example.com':388 'example.com/privacy-policy':387 'expect':1151 'explan':1266 'explicit':228,365,1404 'express':613 'extend':1501 'face':71,612 'facemetr':611 'fail':484,728,751,950,1066,1125 'failedwitherror':749,944,1303,1320 'failur':1471 'fals':1497 'fetch':155,160,186,737,739,745,748,750,754,791,837,933,941,949,966,1018,1027,1068,1157,1189,1217,1301,1318,1447,1454,1455,1481,1490 'fetchdevic':1474 'fetchdevicesdidfailwitherror':1061 'fetchrequestinvalid':1365 'file':304 'first':454,517,1141,1240 'forget':1211 'framework':195,777,1086,1515 'framework-defin':1085 'func':529,833,925,937,1033,1057,1297,1314 'general':119 'general-purpos':118 'generic':1294 'get':1004 'give':267 'grade':5,43 'grant':215 'handl':1026,1296,1310,1468 'hardwar':988,1102 'heart':75,616,618 'heartrat':615 'hold':258,953,960,1187,1358,1464 'hour':256,266,959,1186,1196,1357,1462 'id':230,1406 'ident':356 'identifi':986,1103 'ignor':1289 'immedi':1152 'import':457,678 'impos':956 'inaccess':263 'info.plist':139,370,1252,1283,1412,1419 'infoplist':142 'infoplist-configur':141 'instanc':671 'interact':609 'invalid':1366 'invalidentitl':1333 'io':47,84,1094 'iphon':190,999 'key':373,1432 'keyboard':23,64,329,559 'keyboard-metr':328 'keyboardmetr':475,558,695,874 'keyboardread':692 'keyboardreader.delegate':703 'least':1194 'less':1269 'let':459,479,686,691,810,844,852,857,860,863,876,881,884,897,902,905,1008,1044,1130,1170,1229,1325 'level':15,396 'light':14,60,316,405,654 'lightread':687 'lightreader.delegate':701 'like':1270 'list':305,1396 'locat':605 'long':767 'lost':1228 'lux':858,867,868 'manag':1508 'manual':222,346,362,1143,1400 'mean':1222 'measur':393 'media':26,608 'mediaev':607 'messag':332,575 'messages-usag':331 'messagesusagereport':574 'method':712,1473 'metric':24,65,70,72,330 'minut':1169 'miss':1257,1335 'mistak':165,168,1113 'model':1012,1076 'moment':1160 'monitor':380,522 'motion':61,319,322 'motion-acceleromet':318 'motion-rotation-r':321 'multi':1506 'multi-sensor':1505 'multipl':467 'must':96 'name':1082,1083,1089,1093 'need':128,427,443,1398 'newli':259,963 'noauthor':1344 'notdetermin':514 'noth':1163 'nssensorkitprivacypolicyurl':386,1417 'nssensorkitusagedescript':377,1410 'nssensorkitusagedetail':390,1258,1425 'obtain':1137 'odomet':621,623 'offer':430 'old':1197 'on-wrist':339 'one':684 'onwristst':562 'option':1438 'os':1092,1098 'otherwis':1361 'overlap':971 'overview':130,134,176 'overview-and-requir':133 'pass':804 'pattern':22,382,1502 'pedomet':338 'pedometerdata':599 'per':252,1250 'per-sensor':251,1249 'period':954,961,973,1359,1465 'phone':335,580,630 'phone-usag':334 'phone/messaging':67 'phoneusagereport':579 'photoplethysmogram':638 'physic':394 'place':1391 'placement':864 'polici':1423 'ppg':79,639 'present':241 'pressur':658 'pressure/temp':657 'print':481,932,948,1011,1014,1065,1307 'prior':288 'privaci':507,1422 'process':786 'processkeyboard':887 'processsampl':866 'processusag':908 'producttyp':1100 'profil':224,364,366,1145,1402 'project':1537 'prompt':1378 'promptdeclin':1373 'properti':1072,1073,1107 'propos':100,205 'provid':56 'provis':223,363,1144,1401 'purpos':120,713,1416 'rang':799,970,1368,1458 'rate':19,76,324,597,617,619 'read':12,672,1540 'reader':299,460,488,531,682,706,808,835,927,939,1035,1059,1131,1230,1299,1316 'reader.authorizationstatus':496 'reader.delegate':1241 'reader.fetch':825,1055,1179,1207,1235,1244 'reader.fetchdevices':1025 'reader.sensor':848,936 'reader.startrecording':499,540,774,1135,1164,1234,1243 'reader.stoprecording':543,790 'receiv':104,699,742,827,923 'reconsid':434 'record':153,158,184,260,289,403,493,720,727,732,752,759,762,776,964,1159,1165,1443 'recording-and-fetching-data':157 'refer':174,175,1500 'references/sensorkit-patterns.md':1512,1513 'request':436,455,464,483,515,811,826,838,930,942,967,1045,1056,1171,1180,1208,1236,1245,1281,1429,1441,1456 'request.device':813,1047 'request.from':815,1049,1173,1198 'request.to':823,1053,1177,1203 'requir':32,132,136,178,196,226,375,400,411,1431 'research':4,30,36,42,53,93,99,181,201,243,385,448,508,1388 'research-grad':3,41 'researchandcare.org':207 'restrict':88 'result':828,841,924,976,1182,1225 'result.sample':854,878,899 'result.timestamp':846 'return':917,919,974,1162,1492 'review':169,172,1383 'review-checklist':171 'rotat':18,323,596 'rotationr':595 'run':1110 'runtim':1127 'sampl':552,572,589,650,741,853,877,898,992,1509 'sample.chromaticity':862 'sample.lux':859 'sample.placement':865 'sample.totalscreenwakes':904 'sample.totalunlocks':907 'sample.totalwords':883 'sample.typingspeed':886 'section':1285 'see':1282 'self':702,704,1242 'sensor':6,44,110,121,147,150,187,244,253,294,308,317,419,440,449,462,468,472,509,547,549,550,569,570,586,587,647,648,668,676,685,689,694,763,780,991,1024,1133,1232,1251,1261,1279,1337,1350,1399,1430,1439,1507,1539 'sensorkit':1,9,33,39,55,86,179,212,233,298,368,458,679,955,1119,1148,1408,1514 'sensorread':530,714,725,734,738,743,747,834,926,938,1034,1058,1298,1315,1489 'sensorreaderdidstoprecord':731 'sensorreaderwillstartrecord':719 'set':344,348,506,1213,1433 'share':278 'sheet':247,452,1263 'show':446,1264 'sign':347,351,355,360 'silent':1227 'singl':675 'siri':626 'sirispeechmetr':625 'skill' 'skill-sensorkit' 'skip':1248 'sleep':384,408,636 'sosumi.ai':1517,1521,1525,1529,1533,1542,1546 'sosumi.ai/documentation/bundleresources/entitlements/com.apple.developer.sensorkit.reader.allow)':1545 'sosumi.ai/documentation/sensorkit)':1516 'sosumi.ai/documentation/sensorkit/configuring-your-project-for-sensor-reading)':1541 'sosumi.ai/documentation/sensorkit/srdevice)':1528 'sosumi.ai/documentation/sensorkit/srfetchrequest)':1532 'sosumi.ai/documentation/sensorkit/srsensor)':1524 'sosumi.ai/documentation/sensorkit/srsensorreader)':1520 'sourc':989 'source-dpearson2699' 'specif':1311 'speech':69,627,631 'speed':885,890,891 'speed/slope':622 'srabsolutetim':816,1050,1174,1199,1204 'srabsolutetime.current':824,1054,1178 'srambientlightsampl':655,856 'srauthorizationstatus':535 'srdevic':162,163,984,985,1039,1071,1105,1527 'srdevice.current':814,1010 'srdeviceusagereport':557,901 'srelectrocardiogramsampl':645 'srerror':1290,1326,1329,1466 'srerror.code':1331 'srerror.invalidentitlement':1129 'srfacemetr':614 'srfetchrequest':795,812,839,931,943,1046,1172,1302,1319,1531 'srfetchresult':842 'srkeyboardmetr':561,880 'srmediaev':610 'srmessagesusagereport':578 'srphoneusagereport':583 'srphotoplethysmogramsampl':641 'srsensor':1523 'srsensorread':151,152,461,532,660,661,688,693,836,928,940,1036,1060,1132,1231,1300,1317,1519 'srsensorreader.requestauthorization':471 'srsensorreaderdeleg':710 'srsensorusageambientlightsensor':401 'srsensorusagemot':391 'srspeechmetr':628,632 'srvisit':606 'srwristdetect':566 'srwristtemperaturesess':637 'stake':773 'standard':126 'start':724,730,756 'startrecord':1452 'startrecordingfailedwitherror':726 'state':565 'status':491,523,717,1444 'stay':764 'step/distance':600 'stop':733,758,775,1499 'stoprecord':1482 'stream':640,644 'string':1077,1084,1091,1097,1101 'studi':31,37,54,94,202,220,310,379,399,426,442,1389,1415 'style':361 'submit':97,203 'swift':82,456,494,528,677,760,809,832,1003,1032,1123,1155,1218,1255,1292 'switch':495,536,847,1330 'system':240,421,445,785,1015 'systemnam':1090 'systemvers':1096 'target':81,801 'telephonyspeechmetr':629 'temp':635 'temperatur':74 'three':372 'time':269,798,969,1367,1457 'timestamp':845,872,893,914 'topic-accessibility' 'topic-agent-skills' 'topic-ai-coding' 'topic-apple' 'topic-claude-code' 'topic-codex-skills' 'topic-cursor-skills' 'topic-ios' 'topic-ios-development' 'topic-liquid-glass' 'topic-localization' 'topic-mapkit' 'true':413,918,920,1493 'type':551,553,571,573,588,590,649,651,1074,1510 'unavail':1362 'unknown':519,1380 'unlock':906,911,912 'url':1424 'usag':21,63,68,245,327,333,336,450,510,556,577,582,1253,1275 'use':8,10,123,311,788,993,1118,1147,1475 'user':237,249,268,416,502,584,1079,1267,1345,1374 'user-defin':1078 'valid':1421 'valu':349 'version':1099 'versus':1000 'visit':66,337,603,604 'vs':1437 'wake':903,909,910 'want':276 'warn':422 'watch':193,563,1002 'watcho':49,1095 'whose':968 'wire':1504 'without':1120 'word':882,888,889 'workflow':980 'wrist':73,341,564,634 'wristtemperatur':633 'wrong':1124,1156,1219,1256,1293 'www.researchandcare.org':209 'www.researchandcare.org/resources/accessing-sensorkit-data/).':208 'xcode':225,342 'xml':312,376 'yourapp.entitlements':353","prices":[{"id":"edd78424-637a-4906-ba14-32a49409b328","listingId":"fa1af623-ded5-481a-834a-6cd5f5aea81f","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"dpearson2699","category":"swift-ios-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:01:15.588Z"}],"sources":[{"listingId":"fa1af623-ded5-481a-834a-6cd5f5aea81f","source":"github","sourceId":"dpearson2699/swift-ios-skills/sensorkit","sourceUrl":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/sensorkit","isPrimary":false,"firstSeenAt":"2026-04-18T22:01:15.588Z","lastSeenAt":"2026-04-22T00:53:44.516Z"}],"details":{"listingId":"fa1af623-ded5-481a-834a-6cd5f5aea81f","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"dpearson2699","slug":"sensorkit","github":{"repo":"dpearson2699/swift-ios-skills","stars":468,"topics":["accessibility","agent-skills","ai-coding","apple","claude-code","codex-skills","cursor-skills","ios","ios-development","liquid-glass","localization","mapkit","networking","storekit","swift","swift-concurrency","swiftdata","swiftui","widgetkit","xcode"],"license":"other","html_url":"https://github.com/dpearson2699/swift-ios-skills","pushed_at":"2026-04-21T19:26:16Z","description":"Agent Skills for iOS 26+, Swift 6.3, SwiftUI, and modern Apple frameworks","skill_md_sha":"81f5f0bfec06b5c38a4cce334e3ef53e61fb033e","skill_md_path":"skills/sensorkit/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/dpearson2699/swift-ios-skills/tree/main/skills/sensorkit"},"layout":"multi","source":"github","category":"swift-ios-skills","frontmatter":{"name":"sensorkit","description":"Access research-grade sensor data using SensorKit. Use when reading ambient light levels, accelerometer data, rotation rates, device usage patterns, keyboard metrics, or media events for approved research studies. Requires SensorKit entitlement and research study authorization."},"skills_sh_url":"https://skills.sh/dpearson2699/swift-ios-skills/sensorkit"},"updatedAt":"2026-04-22T00:53:44.516Z"}}