Repository navigation
Privacy Drift
Privacy drift is the gap between what your SDKs actually collect and what your disclosures say they collect. Someone adds Sentry to the iOS app. Now your PrivacyInfo.xcprivacy and your App Store privacy label are both wrong, and nothing tells you until App Review or a regulator does. STARCHART catches it in the PR. This page explains how SDKs are detected from the code layer, lists the full SDK catalog, covers where disclosures are read from (manifests, store labels, privacy policies) and what the three privacy rules enforce. It then walks through real starchart privacy output from the demo and how to fix each finding, and ends with the known limitations.
flowchart LR
L[Lockfiles and manifests<br>Package.resolved, package.json, …] --> P[package nodes<br>pkg:swift/sentry-cocoa]
P --> D{detected?<br>dependsOn in or direct}
D -->|yes| C[catalog match<br>or meta.privacy override]
C --> T[data types per platform]
M[PrivacyInfo.xcprivacy] --> S[disclosures]
A[sc:PrivacyLabel / sc:PrivacyPolicy<br>meta.declares] --> S
T --> R[privacy rules]
S --> R
-
Code ingestion turns lockfiles and manifests into
packagenodes (pkg:<type>/<name>) and addsfile --dependsOn--> packageedges where code imports them. - Each detected package is matched against the catalog (or its per-package override), which gives the Apple data types it collects and which platforms it ships on.
- Disclosures are collected from every
*.xcprivacyfile in the repo and fromsc:PrivacyLabel/sc:PrivacyPolicyartifacts. - The three rules compare the two per platform.
A node counts as a package when kind is package or its id starts with pkg:. It is detected when either:
- some code node depends on it (an incoming
dependsOnedge), or - it is a declared, direct dependency (
meta.declared === true,meta.direct === trueormeta.transitive === false).
So a dependency listed in package.json counts even if no file imports it yet. In the demo, @sentry/nextjs is listed but unused, and it is still detected. Transitive-only pins (for example, Package.resolved entries the project never declares) are not.
Catalog package patterns use * as a wildcard and match case-insensitively. One package can match more than one catalog entry, and each match is reported.
Every detection is scoped to platforms from the package's type (the pkg:<type>/ prefix) and name. A disclosure only has to cover SDKs on its own platforms.
| Package id | Platforms |
|---|---|
pkg:swift/…, pkg:cocoapods/…, pkg:carthage/…
|
ios |
pkg:gradle/…, pkg:maven/…
|
android |
pkg:pub/… |
ios, android |
pkg:npm/… with react-native, expo, capacitor, cordova or ionic in the name |
ios, android |
pkg:npm/… with node as a name segment, or server anywhere in the name |
server |
any other pkg:npm/…
|
web |
| any other package type (go, cargo, …) | server |
an id that isn't pkg:<eco>/<name>
|
ios, android, web, server |
If the code layer has any event nodes (analytics calls like track("pro_checkout_started")), STARCHART adds a synthetic detection app-events (package event:*) collecting ProductInteraction. Its platforms come from the emitting files' extensions: .swift/.m/.mm → ios, .kt/.kts/.java → android, .ts/.tsx/.js/.jsx/.mjs/.cjs/.vue/.svelte → web, .go/.py/.rb/.rs → server. An unknown emitter means all platforms. This is skipped entirely when any detected SDK already collects ProductInteraction, on any platform.
The catalog lives in rules/packs/privacy-catalog.ts. Data types use Apple's NSPrivacyCollectedDataType short names.
- Default types are enforced: every applicable disclosure must declare them.
-
Optional types are only collected when you use a feature (
identify(),sendDefaultPii, session replay). They show up instarchart privacyoutput but are not enforced. - Tracking is Apple's ATT sense: data linked with third-party data for advertising.
SDK (id) |
Packages | Default data types | Optional | Tracking |
|---|---|---|---|---|
Sentry (sentry) |
pkg:npm/@sentry/*pkg:swift/sentry-cocoapkg:cocoapods/Sentrypkg:gradle/io.sentry:*
|
CrashData, PerformanceData, OtherDiagnosticData
|
DeviceID (when sendDefaultPii is enabled) |
no |
PostHog (posthog) |
pkg:npm/posthog-jspkg:npm/posthog-nodepkg:npm/posthog-react-nativepkg:swift/posthog-iospkg:cocoapods/PostHogpkg:gradle/com.posthog:*pkg:gradle/com.posthog.android:*
|
ProductInteraction, DeviceID
|
UserID (when identify() is called) |
no |
Firebase Analytics (firebase-analytics) |
pkg:npm/firebasepkg:npm/@firebase/analyticspkg:npm/@react-native-firebase/analyticspkg:swift/firebase-ios-sdkpkg:cocoapods/FirebaseAnalyticspkg:gradle/com.google.firebase:firebase-analytics*
|
ProductInteraction, DeviceID, CoarseLocation
|
— | no |
Firebase Crashlytics (firebase-crashlytics) |
pkg:npm/@react-native-firebase/crashlyticspkg:cocoapods/FirebaseCrashlyticspkg:gradle/com.google.firebase:firebase-crashlytics*
|
CrashData, DeviceID
|
— | no |
Amplitude (amplitude) |
pkg:npm/@amplitude/*pkg:npm/amplitude-jspkg:swift/amplitude-swiftpkg:swift/amplitude-iospkg:cocoapods/Amplitude*pkg:gradle/com.amplitude:*
|
ProductInteraction, DeviceID
|
UserID (when setUserId() is called) |
no |
Mixpanel (mixpanel) |
pkg:npm/mixpanelpkg:npm/mixpanel-browserpkg:npm/mixpanel-react-nativepkg:swift/mixpanel-swiftpkg:swift/mixpanel-iphonepkg:cocoapods/Mixpanel*pkg:gradle/com.mixpanel.android:*
|
ProductInteraction, DeviceID
|
UserID (when identify() is called) |
no |
Segment (segment) |
pkg:npm/@segment/analytics-nextpkg:npm/@segment/analytics-nodepkg:npm/@segment/analytics-react-nativepkg:npm/analytics-nodepkg:swift/analytics-swiftpkg:swift/analytics-iospkg:gradle/com.segment.analytics.kotlin:*pkg:gradle/com.segment.analytics.android:*
|
ProductInteraction, DeviceID
|
UserID (when identify() is called) |
no |
RevenueCat (revenuecat) |
pkg:swift/purchases-iospkg:cocoapods/RevenueCatpkg:npm/react-native-purchasespkg:npm/@revenuecat/*pkg:gradle/com.revenuecat.purchases:*
|
PurchaseHistory, UserID, DeviceID
|
— | no |
Facebook SDK (facebook) |
pkg:swift/facebook-ios-sdkpkg:cocoapods/FBSDK*pkg:npm/react-native-fbsdk-nextpkg:gradle/com.facebook.android:*
|
DeviceID, ProductInteraction, AdvertisingData
|
— | yes |
Google Mobile Ads (google-mobile-ads) |
pkg:swift/google-mobile-adspkg:swift/swift-package-manager-google-mobile-adspkg:cocoapods/Google-Mobile-Ads-SDKpkg:npm/react-native-google-mobile-adspkg:gradle/com.google.android.gms:play-services-ads*
|
DeviceID, AdvertisingData, CoarseLocation
|
— | yes |
Stripe (stripe) |
pkg:swift/stripe-iospkg:swift/stripe-ios-spmpkg:cocoapods/Stripe*pkg:npm/@stripe/stripe-jspkg:npm/@stripe/stripe-react-nativepkg:gradle/com.stripe:*
|
PaymentInfo, PurchaseHistory
|
EmailAddress (when collected at checkout) |
no |
Datadog (datadog) |
pkg:npm/@datadog/browser-rum*pkg:npm/@datadog/browser-logspkg:npm/@datadog/mobile-react-nativepkg:swift/dd-sdk-iospkg:cocoapods/Datadog*pkg:gradle/com.datadoghq:*
|
CrashData, PerformanceData, OtherDiagnosticData
|
ProductInteraction (RUM action tracking / session replay) |
no |
Bugsnag (bugsnag) |
pkg:npm/@bugsnag/*pkg:swift/bugsnag-cocoapkg:cocoapods/Bugsnag*pkg:gradle/com.bugsnag:*
|
CrashData, OtherDiagnosticData
|
DeviceID |
no |
LogRocket (logrocket) |
pkg:npm/logrocketpkg:npm/@logrocket/*pkg:swift/logrocket-iospkg:cocoapods/LogRocketpkg:gradle/com.logrocket:*
|
ProductInteraction, OtherUsageData
|
CrashData |
no |
Catalog notes from the source:
-
Firebase Analytics: the umbrella
firebaseandfirebase-ios-sdkpackages are assumed to include Analytics. Override them if you only use other Firebase products. - Segment: destinations configured in Segment may collect more. Declare them as separate packages or override.
- LogRocket: session replay records user interactions.
- The server-side npm packages
posthog-node,@segment/analytics-nodeandanalytics-nodemap to theserverplatform (the name containsnode), so only a privacy policy covers them.
Only these 14 SDKs are in the catalog. Anything else collects nothing as far as STARCHART knows, until you add a per-package override.
STARCHART works in Apple short names. The manifest key is the short name with NSPrivacyCollectedDataType in front. Each type also maps to a Google Play Data Safety category, which is used when reporting against Android labels.
| Short name | Manifest key | Play Data Safety category |
|---|---|---|
Name |
NSPrivacyCollectedDataTypeName |
Personal info: Name |
EmailAddress |
NSPrivacyCollectedDataTypeEmailAddress |
Personal info: Email address |
PhoneNumber |
NSPrivacyCollectedDataTypePhoneNumber |
Personal info: Phone number |
PhysicalAddress |
NSPrivacyCollectedDataTypePhysicalAddress |
Personal info: Address |
UserID |
NSPrivacyCollectedDataTypeUserID |
Personal info: User IDs |
DeviceID |
NSPrivacyCollectedDataTypeDeviceID |
Device or other IDs |
PaymentInfo |
NSPrivacyCollectedDataTypePaymentInfo |
Financial info: User payment info |
PurchaseHistory |
NSPrivacyCollectedDataTypePurchaseHistory |
Financial info: Purchase history |
PreciseLocation |
NSPrivacyCollectedDataTypePreciseLocation |
Location: Precise location |
CoarseLocation |
NSPrivacyCollectedDataTypeCoarseLocation |
Location: Approximate location |
Contacts |
NSPrivacyCollectedDataTypeContacts |
Contacts: Contacts |
PhotosorVideos |
NSPrivacyCollectedDataTypePhotosorVideos |
Photos and videos: Photos |
AudioData |
NSPrivacyCollectedDataTypeAudioData |
Audio: Voice or sound recordings |
SearchHistory |
NSPrivacyCollectedDataTypeSearchHistory |
App activity: In-app search history |
BrowsingHistory |
NSPrivacyCollectedDataTypeBrowsingHistory |
Web browsing: Web browsing history |
OtherUserContent |
NSPrivacyCollectedDataTypeOtherUserContent |
App activity: Other user-generated content |
ProductInteraction |
NSPrivacyCollectedDataTypeProductInteraction |
App activity: App interactions |
AdvertisingData |
NSPrivacyCollectedDataTypeAdvertisingData |
App activity: Other actions |
OtherUsageData |
NSPrivacyCollectedDataTypeOtherUsageData |
App activity: Other actions |
CrashData |
NSPrivacyCollectedDataTypeCrashData |
App info and performance: Crash logs |
PerformanceData |
NSPrivacyCollectedDataTypePerformanceData |
App info and performance: Diagnostics |
OtherDiagnosticData |
NSPrivacyCollectedDataTypeOtherDiagnosticData |
App info and performance: Other app performance data |
Wherever you declare types (label or policy meta.declares, meta.privacy overrides), STARCHART normalizes each entry and accepts any of:
- the full key:
NSPrivacyCollectedDataTypeCrashData - the short name, case-insensitive:
CrashData,crashdata - a Play category, full or short:
App info and performance: Crash logs,Crash logs
Two Apple types share the Play category "Other actions", so declaring Other actions declares both AdvertisingData and OtherUsageData. Unknown strings are dropped silently. Double-check your spelling.
STARCHART finds every **/*.xcprivacy file under the project root, skipping node_modules, Pods, DerivedData, .build, Carthage, .git and hidden directories. Pods are ignored on purpose: third-party SDK manifests describe the SDK, not your app. Each manifest found is an ios disclosure.
A manifest is parsed as an XML property list:
| Key | Used for |
|---|---|
NSPrivacyTracking |
Tracking check (privacy-tracking). A missing key is treated as "not set". |
NSPrivacyCollectedDataTypes[].NSPrivacyCollectedDataType |
The declared types. Only recognized NSPrivacyCollectedDataType… keys count. |
…Linked, …Tracking, …Purposes
|
Parsed, not enforced yet. |
NSPrivacyTrackingDomains, NSPrivacyAccessedAPITypes
|
Parsed, not enforced yet. |
A manifest that fails to parse still counts as a disclosure for privacy-disclosure-exists. privacy-disclosed reports the parse error with the byte offset.
Store privacy labels and privacy policies have no file STARCHART can parse, so you describe them as artifacts:
artifacts:
- id: privacy:appstore-label
label: App Store privacy label
type: sc:PrivacyLabel
meta:
platform: ios # or platforms: [ios, android]
declares: [NSPrivacyCollectedDataTypePurchaseHistory, NSPrivacyCollectedDataTypeUserID, NSPrivacyCollectedDataTypeDeviceID]
tracking: false
owners: ["@zero"]
- id: web:privacy-policy
type: sc:PrivacyPolicy
binding: { adapter: fs, path: apps/web/app/privacy/page.mdx }
meta:
platform: web
declares: [CrashData, PerformanceData, OtherDiagnosticData, DeviceID, ProductInteraction]| Field | Meaning |
|---|---|
type |
sc:PrivacyLabel (store label) or sc:PrivacyPolicy. |
meta.declares |
Required. A list of data types in any accepted spelling. An artifact without a declares list is ignored completely, not treated as declaring nothing. |
meta.tracking |
Optional boolean. Only an explicit false can fail privacy-tracking. |
meta.platform / meta.platforms
|
ios, android, web, server. Without it, platforms come from the binding: appstore → ios, playstore → android. Anything else, including no binding, means all four platforms. |
A label whose only platform is android is treated as a Play Data Safety label. Its messages use Play category names (does not declare "App info and performance: Crash logs").
Set meta.platform on every label. An unbound label with no platform applies to web and server SDKs too.
Enable them with packs: [privacy] (the demo also runs core, appstore and seo). All three are listed on Rule Packs.
| Rule | Severity | Fails when |
|---|---|---|
privacy-disclosed |
error | A detected SDK's default data type is missing from any disclosure whose platforms overlap the SDK's. Every applicable disclosure is checked, so the manifest and the label are each reported. Also: a manifest can't be parsed. |
privacy-tracking |
error | A tracking SDK applies to a manifest that doesn't set NSPrivacyTracking to true, or to a label or policy with meta.tracking: false. |
privacy-disclosure-exists |
warn | SDKs collect data on a platform and no disclosure of any kind covers that platform. The message names the disclosure to add, and says "collects" for one package, "collect" for several. |
The hint in privacy-disclosure-exists depends on the platform:
| Platform | Suggested disclosure |
|---|---|
| ios | a PrivacyInfo.xcprivacy or an App Store privacy label (sc:PrivacyLabel) |
| android | a Play Data Safety label (sc:PrivacyLabel, platform android) |
| web, server | a privacy policy (sc:PrivacyPolicy with meta.declares) |
The catalog is a starting point. If you configure Sentry without performance monitoring, or use an SDK the catalog doesn't know, put meta.privacy on the package node:
| Key | Effect |
|---|---|
collects |
Replaces the enforced default types. |
optional |
Replaces the reported optional types. |
tracking |
Replaces the tracking flag. |
Setting any of these replaces all catalog matches for that package with one detection. Fields you leave out are taken from the first matching catalog entry, or empty and false for packages not in the catalog. The source column then reads <package> meta.privacy.
Package nodes come from code ingestion, so there's no dedicated YAML section for them. Declare a document with the package's id and a meta block. STARCHART merges it into the ingested package node, and the node stays kind: package (it isn't counted as a world artifact). This was verified on a copy of the demo:
# .starchart/artifacts/overrides.yaml
artifacts:
- id: pkg:swift/sentry-cocoa
meta:
privacy:
collects: [CrashData]
optional: [PerformanceData]sentry pkg:swift/sentry-cocoa [ios]
collects: CrashData (optional: PerformanceData)
The merge only works if the id matches an ingested package exactly. Check the id with starchart query --kind package.
Library users can also pass a whole custom catalog: detectCollection(graph, myCatalog).
starchart privacyIt prints every detection (SDK id, package, platforms, a tracking marker, default and optional types), then the privacy pack's violations. There is no --format flag. For JSON, use starchart rules -f json and filter on "pack": "privacy".
Exit codes: 1 when any privacy violation is an error, 2 when rules are invalid or a configured pack is unknown, 0 otherwise.
Include privacy in packs:. The command runs the same evaluation as starchart rules and keeps only violations with pack === "privacy". If no entry in packs: is privacy (or pack-privacy, @starchart/pack-privacy), it prints the detections, then a warning instead of a verdict, and exits 0 without evaluating any rules. Real output from a copy of the demo with privacy removed from packs::
sentry pkg:npm/@sentry/nextjs [web]
collects: CrashData, OtherDiagnosticData, PerformanceData (optional: DeviceID)
…
sentry pkg:swift/sentry-cocoa [ios]
collects: CrashData, OtherDiagnosticData, PerformanceData (optional: DeviceID)
! the privacy rule pack is not enabled; add "privacy" to packs in .starchart/config.yaml to check disclosures
Real output from the demo (examples/pro-universe):
sentry pkg:npm/@sentry/nextjs [web]
collects: CrashData, OtherDiagnosticData, PerformanceData (optional: DeviceID)
posthog pkg:npm/posthog-js [web]
collects: DeviceID, ProductInteraction (optional: UserID)
revenuecat pkg:swift/purchases-ios [ios]
collects: DeviceID, PurchaseHistory, UserID
sentry pkg:swift/sentry-cocoa [ios]
collects: CrashData, OtherDiagnosticData, PerformanceData (optional: DeviceID)
error privacy-disclosed pkg:swift/purchases-ios collects DeviceID but PrivacyInfo.xcprivacy (apps/ios/Resources/PrivacyInfo.xcprivacy) does not declare NSPrivacyCollectedDataTypeDeviceID (apps/ios/Resources/PrivacyInfo.xcprivacy)
error privacy-disclosed pkg:swift/purchases-ios collects UserID but PrivacyInfo.xcprivacy (apps/ios/Resources/PrivacyInfo.xcprivacy) does not declare NSPrivacyCollectedDataTypeUserID (apps/ios/Resources/PrivacyInfo.xcprivacy)
error privacy-disclosed pkg:swift/sentry-cocoa collects CrashData but privacy label privacy:appstore-label does not declare CrashData (.starchart/artifacts/marketing.yaml)
error privacy-disclosed pkg:swift/sentry-cocoa collects CrashData but PrivacyInfo.xcprivacy (apps/ios/Resources/PrivacyInfo.xcprivacy) does not declare NSPrivacyCollectedDataTypeCrashData (apps/ios/Resources/PrivacyInfo.xcprivacy)
error privacy-disclosed pkg:swift/sentry-cocoa collects OtherDiagnosticData but privacy label privacy:appstore-label does not declare OtherDiagnosticData (.starchart/artifacts/marketing.yaml)
error privacy-disclosed pkg:swift/sentry-cocoa collects OtherDiagnosticData but PrivacyInfo.xcprivacy (apps/ios/Resources/PrivacyInfo.xcprivacy) does not declare NSPrivacyCollectedDataTypeOtherDiagnosticData (apps/ios/Resources/PrivacyInfo.xcprivacy)
error privacy-disclosed pkg:swift/sentry-cocoa collects PerformanceData but privacy label privacy:appstore-label does not declare PerformanceData (.starchart/artifacts/marketing.yaml)
error privacy-disclosed pkg:swift/sentry-cocoa collects PerformanceData but PrivacyInfo.xcprivacy (apps/ios/Resources/PrivacyInfo.xcprivacy) does not declare NSPrivacyCollectedDataTypePerformanceData (apps/ios/Resources/PrivacyInfo.xcprivacy)
warn privacy-disclosure-exists pkg:npm/@sentry/nextjs, pkg:npm/posthog-js collect CrashData, DeviceID, OtherDiagnosticData, PerformanceData, ProductInteraction on web but no disclosure exists; add a privacy policy (sc:PrivacyPolicy with meta.declares)
8 error · 1 warn · 0 info
What happened here:
- The demo's manifest declares only
PurchaseHistory. RevenueCat also collectsUserIDandDeviceID, and Sentry addsCrashData,PerformanceDataandOtherDiagnosticData. - The App Store label (
platform: ios) already lists RevenueCat's three types, but none of Sentry's. - The web app ships Sentry and PostHog, and no disclosure covers
webat all. - The analytics event
pro_checkout_started(emitted from the web pricing page) doesn't add anapp-eventsdetection, because PostHog already collectsProductInteraction.
1. Declare the missing types in the manifest. Add one entry per type to NSPrivacyCollectedDataTypes in apps/ios/Resources/PrivacyInfo.xcprivacy. The message gives the exact key.
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeCrashData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array><string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string></array>
</dict>Repeat for UserID, DeviceID, PerformanceData and OtherDiagnosticData. STARCHART only checks the type key. Set Linked, Tracking and Purposes to the truth for your app.
2. Update the store label, then mirror it in the chart. Change the label in App Store Connect first. That's the real disclosure. Then make the artifact say the same:
declares: [NSPrivacyCollectedDataTypePurchaseHistory, NSPrivacyCollectedDataTypeUserID, NSPrivacyCollectedDataTypeDeviceID, CrashData, PerformanceData, OtherDiagnosticData]3. Add a disclosure for web. Add the web:privacy-policy artifact shown above, with platform: web and the five web types, after the policy text actually says so.
4. Tracking findings. If an ATT-sense tracking SDK (Facebook, Google Mobile Ads) is detected, set NSPrivacyTracking to <true/>, list your tracking domains, and set meta.tracking: true on the labels. If you have configured the SDK not to track, override it with meta.privacy.tracking: false on the package.
5. The catalog is wrong for you. Override per package (see Per-package overrides), don't declare data you don't collect.
After fixes 1 to 3 on a copy of the demo:
sentry pkg:npm/@sentry/nextjs [web]
collects: CrashData, OtherDiagnosticData, PerformanceData (optional: DeviceID)
posthog pkg:npm/posthog-js [web]
collects: DeviceID, ProductInteraction (optional: UserID)
revenuecat pkg:swift/purchases-ios [ios]
collects: DeviceID, PurchaseHistory, UserID
sentry pkg:swift/sentry-cocoa [ios]
collects: CrashData, OtherDiagnosticData, PerformanceData (optional: DeviceID)
✓ every collected data type is disclosed
Put npx --yes @space-pirate-zero/starchart rules in CI and the PR that adds an SDK fails until the disclosures catch up. See GitHub Action.
- The catalog is a community default, not legal advice. It is compiled from vendor documentation and covers 14 SDKs. Vendors change what they collect, and your configuration changes it too. Review the entries you depend on and override them.
-
XML plists only. The manifest parser handles XML property lists (
dict,array,string,integer,real,true/false,date,data). Binary plists fail with a parse error. Convert them withplutil -convert xml1. -
Every manifest must declare everything for iOS. Each
*.xcprivacyoutside the ignored directories is checked against every iOS SDK. A manifest for an app extension that doesn't link the SDK will still be flagged. -
Only default types are enforced. Optional types (
identify(),sendDefaultPii, session replay) are reported, not required. If you use those features, add the types tometa.privacy.collects. - Linked, purposes, tracking domains and required-reason APIs are parsed but not checked yet.
-
Store labels aren't read from App Store Connect or Play Console. The
sc:PrivacyLabelartifact is your statement of what the label says. Keep it honest. -
The
app-eventsdetection is suppressed globally as soon as any SDK on any platform collectsProductInteraction, even when the events are emitted on a different platform.
★ STARCHART
☠ a Space Pirate Zero joint
STARCHART Every dependency. Code to cosmos.
Guides
Concepts
- Three-Layer Model
- Facts and Entities
- Artifacts and Bindings
- Edge Types
- Node IDs
- Impact Analysis
- Lockfile and Drift
- Rollout Ordering
Authoring
Code layer
Commands & API
Adapters & engine
- Adapters Overview
- Adapter: fs
- Adapter: url
- Adapter: Stripe
- Adapter: App Store Connect
- Writing an Adapter
- Audit and Break Detection
- Apply, Revert and Journals
- Future Universe Preview
- Viewer and Serve
- Reality X-Ray
Rules & analysis
Integrations
Project