Docs ▸ Platforms
Mac signing and notarization
Steam only accepts Mac builds that are signed with an Apple Developer ID and notarized. On a Mac, build does both when these environment variables are set:
# once: a "Developer ID Application" certificate (Xcode → Settings → Accounts → Manage Certificates; needs the paid Apple Developer Program)
# once: a notarytool login stored in your keychain (it asks for an app-specific password)
xcrun notarytool store-credentials gameshipper --apple-id you@example.com --team-id ABCDE12345
export GAMESHIPPER_MAC_IDENTITY="Developer ID Application: Your Name (ABCDE12345)"
export GAMESHIPPER_NOTARY_PROFILE=gameshipper
npx gameshipper build --target mac # signs, notarizes (usually a few minutes) and staplesFor CI, use an App Store Connect API key instead of the profile: GAMESHIPPER_NOTARY_KEY (the .p8 file's path, not the key itself), GAMESHIPPER_NOTARY_KEY_ID and GAMESHIPPER_NOTARY_ISSUER. The first signing may ask for keychain access: click "Always Allow". The variables are never read from gameshipper.json, because the identity contains your legal name and game repositories are often public.
Without them the Mac app is ad-hoc signed: it runs on your Mac, and build warns MAC_UNSIGNED. With only GAMESHIPPER_MAC_IDENTITY it's signed but not notarized (MAC_NOT_NOTARIZED). Every Mac build uses the hardened runtime with as few entitlements as work: JIT (for JavaScript) and the microphone everywhere, and, when the build includes Steam, library validation off and DYLD variables allowed in the game's main process, because Steam injects its overlay with DYLD_INSERT_LIBRARIES and the game loads Valve-signed libraries. An ad-hoc signed build also has library validation off in every process: without a Team ID, Electron couldn't load its own framework. The App Sandbox isn't used. Signing happens after your plugins' afterPackage hooks.
| Code | |
|---|---|
APPLE_CREDENTIALS_INVALID |
The variables are half-set or mixed (a notary login without an identity, a keychain without a profile, a profile with API key variables, say); the message names them. Stops the build before anything is built; exit code 2. |
MAC_IDENTITY_NOT_FOUND |
GAMESHIPPER_MAC_IDENTITY isn't in your keychain. The message counts the identities that are there by certificate type, without their names (run security find-identity -v -p codesigning to see them); exit code 2. |
MAC_SIGN_FAILED, NOTARIZE_FAILED, STAPLE_FAILED, NOTARIZE_TOOL_MISSING |
Signing or notarizing failed; the Mac target fails. The fix names the log in .gameshipper/logs/ with codesign's output, notarytool's own reason (usually a login problem) or Apple's report. Stapling the ticket is tried 3 times, 5 seconds apart, before STAPLE_FAILED. |
MAC_UNSIGNED, MAC_NOT_NOTARIZED, MAC_BUNDLE_ID_DEFAULT, MAC_SIGN_HOST, MAC_ADHOC_SIGN_FAILED |
Warnings: how far the Mac app got, and what to set to go further. |