Before submitting version 1.1 of my journal app Lanternly, I pasted the same four-line block at the end of 39 App Store descriptions, for both iOS and macOS. It's a dull block: a rule line, the license agreement, the privacy policy, the terms. Without it, though, a subscription app risks coming back flagged under 3.1.2, even when the subscription itself, the paywall and the StoreKit code are all done right.
Below I go through where this requirement actually comes from, why App Store Connect has a field for the privacy policy but none for the terms, and what text I ended up using. Apple's wording is quoted verbatim and was checked on 13 October 2026.
Where Apple requires it#
Funnily enough, guideline 3.1.2 itself contains no links and never mentions the word EULA. Section 3.1.2(c) asks you to explain clearly what the user gets for the money and refers to Schedule 2 of the Apple Developer Program License Agreement. The actual requirements live in three other places.
Schedule 2, section 3.8(b). It lists what must be shown "clearly and conspicuously" for an auto-renewable subscription: title, duration, price. And then, as a separate line:
Links to Your Privacy Policy and Terms of Use must be accessible within Your Licensed Application.
That one is about the app itself.
The Auto-renewable subscriptions page adds the metadata:
Please note that your app and App Store metadata must include links to your Terms of Use and Privacy Policy.
Guideline 5.1.1(i) covers the privacy policy for every app, subscription or not:
All apps must include a link to their privacy policy in the App Store Connect metadata field and within the app in an easily accessible manner.
So that's two links, and each one is needed in two places: inside the app and on the store listing.
Why the terms have no field of their own#
The privacy policy is easy. App Information has a Privacy Policy URL field. It's required for iOS and macOS and is filled in separately for each locale.
There is no "Terms of Use URL" field in App Store Connect. There is a License Agreement field, and the documentation describes it like this:
Apple provides a standard EULA (End-User License Agreement) that applies in all regions. You may provide a custom license agreement that supersedes the Apple EULA for one or more regions.
That leaves two options:
| Option | What you do | When it fits |
|---|---|---|
| Your own EULA in the License Agreement field | Paste the full text of your terms; it replaces the standard one | You have a lawyer and one set of terms for every region |
| Standard EULA + links in the description | Leave the field alone and put the links at the end of the Description | Almost every indie app |
I went with the second. Lanternly does have its own terms, but they describe the subscription and the app, while Apple's standard EULA handles the license for the software itself perfectly well.
The block itself#
This is what sits at the end of every Lanternly description. Regular text goes above the rule line, and only the links go below it:
_____________________
LICENSED APPLICATION END USER LICENSE AGREEMENT - https://www.apple.com/legal/macapps/stdeula/
Privacy Policy - https://dodecaidr.pro/en/projects/lanternly/privacy-policy/
Terms and Conditions - https://dodecaidr.pro/en/projects/lanternly/terms-of-service/A few decisions are hidden in it.
The line labels are in English in every language. Only the document URL changes; the labels stay the same. Whoever reviews the app recognizes "LICENSED APPLICATION END USER LICENSE AGREEMENT" at a glance, whatever language the rest of the description is in. This is my choice, not something Apple asks for.
A link to the standard EULA, even though I didn't change it. Without it, the metadata has the privacy policy and my terms but not the license that's actually in force. I show all three documents so the reviewer doesn't have to guess.
Bare, full links with the protocol. An App Store description is plain text with no HTML support. A URL without https:// may not turn into a link.
Every link opens without a login and without redirects. I've been burned by this already. The Mac version was rejected under guideline 1.5 because the Support URL went through a redirect to a social network and didn't open for the reviewer. So before submitting, run every URL from the listing through curl -sIL and make sure the chain ends in a 200 and not a login page.
The block takes 280 of the 4000 characters. That turned out to matter for the French description, which didn't fit. I removed the "Privacy policy / Terms of use" lines from the middle of the description, since they duplicated the block, and the French text came in at 3917 characters.
Above the block: a paragraph about the subscription#
The links cover the documents. But 3.8(b) also asks you to show the terms of the subscription itself. I don't put the price in the description: it differs from country to country, and the paywall shows it in the buyer's currency. Everything else goes into one paragraph:
Lanternly+ is a monthly, six-month or yearly subscription with a 7-day free trial.
Payment is charged to your Apple account at confirmation of purchase.
The subscription renews automatically unless cancelled at least 24 hours
before the end of the current period. Manage or cancel it in your Apple account settings.In the description, the free week is mentioned as a property of the subscription. Inside the app, the line about the week shows up only if the person is still eligible for the trial (isEligibleForIntroOffer). Otherwise it would be a promise the store won't keep.
The same links inside the app#
The other half of the requirement lives in code. On Lanternly's paywall, under the purchase button, there's a row: "Restore · Terms · Privacy". A minimal working version in SwiftUI and StoreKit 2:
import SwiftUI
import StoreKit
enum LegalLinks {
// Document language follows the app's UI language, not the device region
private static var lang: String {
(Bundle.main.preferredLocalizations.first ?? "en").hasPrefix("ru") ? "ru" : "en"
}
static var privacy: URL { URL(string: "https://example.com/\(lang)/privacy-policy/")! }
static var terms: URL { URL(string: "https://example.com/\(lang)/terms-of-service/")! }
}
struct PaywallLegalRow: View {
var body: some View {
HStack(spacing: 6) {
Button("Restore") { Task { try? await AppStore.sync() } }
Text("·")
Link("Terms", destination: LegalLinks.terms)
Text("·")
Link("Privacy", destination: LegalLinks.privacy)
}
.font(.footnote)
.foregroundStyle(.secondary)
.lineLimit(1)
}
}Note the preferredLocalizations. The device region is a poor hint here: someone with a Russian interface who lives in Germany has a German region. The UI language, on the other hand, is the language they just read the paywall in. The Restore button sits in the same row for the same reason as the links: Apple requires it on the subscription purchase screen.
When you have many languages#
Lanternly's interface comes in two languages, while its store listing exists in 39. The documents on the website are available in five: English, Russian, Spanish, Japanese and Chinese. The rule I settled on: a locale links to the document in its own language if there is one. Spanish locales go to /es/, Japanese to /ja/, both Chinese locales to /zh-CN/, and everything else to /en/.
The Privacy Policy URL field in App Information is localized too. The documentation calls it required for iOS and macOS, so it's easy to forget when you add a locale: it lives in a different section, away from the description.
What Apple doesn't spell out#
- Which metadata field the terms link has to go in. The subscriptions page says "App Store metadata" and doesn't name a field. The description is the obvious choice, but custom text in License Agreement would formally work too.
- Whether the block is needed in every locale. It isn't stated anywhere. I put it in all of them: the reviewer may open the listing in any language, and 280 characters is a small price.
- Whether the standard EULA is enough instead of your own terms. For many apps, apparently yes. But if your subscription provides a service with its own rules, you need terms of your own, and they are best written with a lawyer.
A short checklist before submitting: Privacy Policy URL is filled in for every locale, the block with three links sits at the end of the description, every URL returns 200 without a login, and the paywall has Restore, Terms and Privacy. How I translated and checked the rest of the fields across these 39 listings is in the next article.



