API keys hardcoded in an iOS app, and which ones matter

Anything compiled into an app can be read out of it. That makes a secret in source not secret. But not every key in an app is a secret: publishable client keys are designed to ship, and rotating one breaks live customers, so the two cases need opposite advice.

Can cause rejectionsource.hardcoded-secrets

Why it matters

An IPA is a zip file. Strings in the binary are readable with standard tools, and obfuscating them delays rather than prevents it. A key that grants access to something on your server has to live on your server.

Publishable keys are the opposite case. A RevenueCat appl_ key, a Stripe pk_live_ key, a Google API key and similar vendor-documented publishable prefixes identify the app to the vendor and grant nothing on their own. They belong in the bundle, and there is nothing to rotate.

That distinction matters more than it looks: rotating a publishable key on a live app breaks purchases for every existing customer. Advice that treats all keys as secrets causes the outage it was trying to prevent.

The name a literal is assigned to decides nothing. A constant called apiKey holding a reverse-DNS string is a Keychain account or a defaults key, not a credential, and reporting it would train you to ignore the check.

How to fix it

  1. For a key that was meant to stay secret: move the operation behind your own backend so the app calls you and you call the vendor, then rotate the key, and only once nothing on a device still needs it.
  2. For a publishable key: leave it. Confirm against the vendor’s documentation that the prefix is the publishable one, and move on.
  3. If you cannot avoid a credential on the device, store it in the Keychain and fetch it at runtime rather than compiling it in.

The guidelines behind it

Read from Apple’s App Review Guidelines as last updated October 16, 2026.

Worth knowing

Matches inside test targets are excluded.

What ReviewAhead checks

Hardcoded secrets. Credential-shaped literals in source ship inside the app bundle.

  • AWS keys, Stripe live keys, GitHub tokens, Google API keys, Slack tokens, private keys, and long credential-shaped assignments.
  • Classifies every match by its value first: reverse-DNS or otherwise too regular to be issued is not reported, nor is a placeholder, a URL or a path.
  • Reports a documented publishable prefix as an improvement that says it belongs in the bundle, and a long high-entropy literal as a risk.
  • Masks the matched credential before it becomes evidence, so the report does not become a second place the secret exists.

Apple’s own documentation for this requirement: developer.apple.com. Where this page and Apple disagree, Apple is right and this page is a bug.

Scan my projectScan your Xcode project and see whether this one is a problem in your app, free.

All 38 App Store readiness checks