Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generate privacy policies, terms of service, and EULAs for Apple platform apps. Detects data collection patterns, third-party SDKs, and generates region-specific legal documents with Apple Privacy Nutrition Label mapping. Use when user needs legal documents or data collection disclosure for App Store submission.
.claude/skills/thomasmoreai-privacy-policy/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 98% | 54 |
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 84% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 186% | 0% |
| case-22 | ✗→✓ | ▲ Improved | 152% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 49% | 0% |
| case-07 | ✓→✓ | = Same ✓ | 155% | 0% |
Generate ready-to-use privacy policies, terms of service, and EULAs tailored to your app's data practices, third-party services, and target markets.
> Disclaimer: This skill generates template legal documents based on common indie app scenarios. Consult a qualified lawyer for apps handling sensitive data (health, financial, children's data), apps with complex data sharing arrangements, or apps operating in highly regulated industries. These templates are a strong starting point -- not a substitute for legal counsel.
Use this skill when the user:
Before generating documents, gather context from the project.
Glob: **/privacy*.md, **/privacy*.html, **/privacy*.txt
Glob: **/terms*.md, **/terms*.html, **/terms*.txt
Glob: **/eula*.md, **/eula*.html, **/eula*.txt
Glob: **/legal/**If existing documents found, ask user whether to replace or update them.
Grep: "Firebase" or "GoogleAnalytics" or "Crashlytics"
Grep: "Mixpanel" or "Amplitude" or "PostHog"
Grep: "AdMob" or "AppLovin" or "UnityAds"
Grep: "FacebookSDK" or "GoogleSignIn" or "SignInWithApple"
Grep: "Sentry" or "Bugsnag" or "DataDog"
Grep: "RevenueCat" or "Adapty" or "Qonversion"
Grep: "TelemetryDeck" or "Plausible" or "CountlySDK"Note detected SDKs to auto-populate data collection sections.
Grep: "UserDefaults" -- Local preferences storage
Grep: "CoreData" or "SwiftData" or "NSPersistentContainer" -- Local database
Grep: "CloudKit" or "CKContainer" -- Cloud sync
Grep: "URLSession" or "Alamofire" -- Network calls
Grep: "HealthKit" or "HKHealthStore" -- Health data
Grep: "CLLocationManager" or "CoreLocation" -- Location data
Grep: "AVCaptureSession" or "PHPhotoLibrary" -- Camera/photos
Grep: "Contacts" or "CNContactStore" -- Contacts access
Grep: "ATTrackingManager" -- App Tracking Transparency
Grep: "ASAuthorizationAppleIDProvider" -- Sign in with AppleGrep: "NSCameraUsageDescription" or "NSPhotoLibraryUsageDescription"
Grep: "NSLocationWhenInUseUsageDescription" or "NSLocationAlwaysUsageDescription"
Grep: "NSHealthShareUsageDescription" or "NSHealthUpdateUsageDescription"
Grep: "NSContactsUsageDescription" or "NSMicrophoneUsageDescription"
Grep: "NSUserTrackingUsageDescription"Ask the user via AskUserQuestion:
Read templates.md for the document templates.
Based on configuration answers, include or exclude sections:
| Answer | Sections Added | | ------------------- | -------------------------------------------------------------- | | No user data | Minimal privacy policy (no collection, no sharing) | | Anonymous analytics | Analytics disclosure, third-party services list | | Account with email | Account data, authentication, data retention | | Personal info | Full data collection, user rights, data portability | | Health/financial | Sensitive data handling, enhanced security, additional consent | | Children under 13 | COPPA section, parental consent, limited data collection |
Replace template placeholders with detected or user-provided values:
[APP_NAME] -- App display name[DEVELOPER_NAME] -- Developer or company name[CONTACT_EMAIL] -- Privacy contact email[EFFECTIVE_DATE] -- Document effective date[WEBSITE_URL] -- Developer website or privacy page URLInclude sections based on target markets:
GDPR (European Union users):
CCPA (California users):
DPDP (India users):
COPPA (children under 13):
Based on detected data practices, generate a mapping for App Store Connect:
Apple Privacy Nutrition Label Mapping
=====================================
Data Types to Declare:
- [ ] Contact Info: Email Address -- Used for: App Functionality, Account
- [ ] Identifiers: User ID -- Used for: App Functionality
- [ ] Usage Data: Product Interaction -- Used for: Analytics
- [ ] Diagnostics: Crash Data -- Used for: App Functionality
- [ ] Diagnostics: Performance Data -- Used for: Analytics
Data Linked to User: [List items linked to user identity]
Data Used to Track: [List items used for cross-app tracking, if any]
Tracking: [Yes/No -- triggers ATT requirement if Yes]Generate documents in Markdown format. Place files based on user's hosting preference:
docs/privacy-policy.md, docs/terms-of-service.md, docs/eula.mdResources/Legal/privacy-policy.md, etc.docs/ with guidance for in-app integrationWhen submitting to the App Store, Apple asks about data practices. Map generated privacy policy to these questions:
| Apple Question | Where to Find Answer | | ------------------------------------------------- | ---------------------------------------- | | Do you or your third-party partners collect data? | "Information We Collect" section | | Data types collected | Privacy Nutrition Label mapping (Step 4) | | Is data linked to user identity? | "How We Use Information" section | | Is data used for tracking? | "Third-Party Services" section |
Declare these data types based on your app's practices:
| If Your App... | Declare These Types | | ----------------------- | ------------------------------------------- | | Has user accounts | Contact Info, Identifiers | | Uses analytics | Usage Data (Product Interaction) | | Has crash reporting | Diagnostics (Crash Data, Performance Data) | | Shows ads | Identifiers (Device ID), Usage Data | | Uses location | Location (Precise or Coarse) | | Accesses photos | Photos or Videos | | Accesses health data | Health & Fitness | | Uses Sign in with Apple | Contact Info (Email), Identifiers (User ID) |
ATT is required when your app:
ATT is NOT required for:
docs/ folder in your repo/docshttps://yourusername.github.io/yourapp/privacy-policyswift// Option 1: WKWebView for hosted HTML import WebKit struct LegalDocumentView: UIViewRepresentable { let url: URL func makeUIView(context: Context) -> WKWebView { WKWebView() } func updateUIView(_ webView: WKWebView, context: Context) { webView.load(URLRequest(url: url)) } } // Option 2: Bundled Markdown rendered as Text struct PrivacyPolicyView: View { var body: some View { ScrollView { Text(LocalizedStringKey(privacyPolicyMarkdown)) .padding() .textSelection(.enabled) } .navigationTitle("Privacy Policy") } }
After generation, provide:
docs/
├── privacy-policy.md # Privacy policy with region-specific sections
├── terms-of-service.md # Terms of service (if requested)
└── eula.md # End-user license agreement (if requested)Provide a checklist the user can follow in App Store Connect.
NSUserTrackingUsageDescription to Info.plistgenerators/consent-flow -- GDPR/CCPA consent UI generationgenerators/account-deletion -- Account deletion flow (App Store requirement)generators/permission-priming -- Pre-permission UI for ATTmonetization/ -- Subscription terms and pricing disclosures| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 21,534 | 5,626 | -74% | 1 | 1 | 0% | 3,695 | 3,269 | -12% | 0 | 0 | — |
case-02 | fail→fail | 17,623 | 22,580 | +28% | 1 | 1 | 0% | 2,809 | 6,739 | +140% | 0 | 0 | — |
case-03 | fail→fail | 26,398 | 25,636 | -3% | 1 | 1 | 0% | 4,987 | 7,718 | +55% | 0 | 0 | — |
case-04 | fail→pass | 13,889 | 13,887 | -0% | 1 | 1 | 0% | 3,310 | 6,087 | +84% | 0 | 0 | — |
case-05 | fail→fail | 22,025 | 21,891 | -1% | 1 | 1 | 0% | 3,969 | 7,221 | +82% | 0 | 0 | — |
case-06 | pass→pass | 15,631 | 9,469 | -39% | 1 | 1 | 0% | 3,334 | 4,978 | +49% | 0 | 0 | — |
case-07 | pass→pass | 8,962 | 8,052 | -10% | 1 | 1 | 0% | 1,746 | 4,447 | +155% | 0 | 0 | — |
case-08 | pass→pass | 7,150 | 5,180 | -28% | 1 | 1 | 0% | 1,364 | 3,828 | +181% | 0 | 0 | — |
case-09 | pass→pass | 11,057 | 5,411 | -51% | 1 | 1 | 0% | 2,283 | 4,002 | +75% | 0 | 0 | — |
case-10 | pass→pass | 11,804 | 5,495 | -53% | 1 | 1 | 0% | 2,259 | 3,966 | +76% | 0 | 0 | — |
case-20 | pass→pass | 3,375 | 4,082 | +21% | 1 | 1 | 0% | 488 | 3,612 | +640% | 0 | 0 | — |
case-11 | pass→pass | 13,488 | 9,234 | -32% | 1 | 1 | 0% | 2,223 | 4,402 | +98% | 0 | 0 | — |
case-12 | pass→pass | 13,755 | 11,974 | -13% | 1 | 1 | 0% | 2,535 | 5,216 | +106% | 0 | 0 | — |
case-13 | pass→pass | 10,616 | 9,517 | -10% | 1 | 1 | 0% | 2,005 | 4,589 | +129% | 0 | 0 | — |
case-14 | pass→pass | 10,240 | 9,848 | -4% | 1 | 1 | 0% | 2,064 | 4,708 | +128% | 0 | 0 | — |
case-15 | pass→pass | 12,695 | 4,156 | -67% | 1 | 1 | 0% | 1,045 | 3,664 | +251% | 0 | 0 | — |
case-16 | pass→pass | 5,703 | 3,607 | -37% | 1 | 1 | 0% | 1,056 | 3,529 | +234% | 0 | 0 | — |
case-17 | pass→pass | 4,996 | 4,940 | -1% | 1 | 1 | 0% | 866 | 3,780 | +336% | 0 | 0 | — |
case-18 | pass→pass | 2,830 | 2,033 | -28% | 1 | 1 | 0% | 427 | 3,211 | +652% | 0 | 0 | — |
case-19 | pass→pass | 3,985 | 2,695 | -32% | 1 | 1 | 0% | 808 | 3,355 | +315% | 0 | 0 | — |
case-21 | fail→pass | 6,458 | 1,678 | -74% | 1 | 1 | 0% | 1,086 | 3,107 | +186% | 0 | 0 | — |
case-22 | fail→pass | 7,225 | 1,553 | -79% | 1 | 1 | 0% | 1,236 | 3,118 | +152% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +14 percentage points is the difference between those two pass rates over the 21 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.