Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Python script for notarizing an app (e.g. a .dmg)
#!/usr/bin/env python3
# Notarize a file (e.g. a .dmg)
# Usage: <Apple ID username> <Apple ID password> <file>
# Note: The --primary-bundle-id flag is hard-coded below, so you'll want to
# change that!
# See
# for information on how to prepare your app for notarization.
from argparse import ArgumentParser
from subprocess import check_output
from plistlib import loads
from time import sleep
def main():
parser = ArgumentParser()
parser.add_argument('username', help='Apple ID user')
parser.add_argument('password', help='Apple ID password')
parser.add_argument('path', help='File to be notarized (e.g. .dmg)')
args = parser.parse_args()
print('requesting notarization of {}...'.format(args.path))
request_uuid = loads(check_output([
'--primary-bundle-id', 'com.yourdomain.yourapp.dmg',
'--username', args.username,
'--password', args.password,
'--file', args.path,
'--output-format', 'xml'
for i in range(200):
response = loads(check_output([
'--notarization-info', request_uuid,
'--username', args.username,
'--password', args.password,
'--output-format', 'xml'
if response['notarization-info']['Status'] == 'success':
print('notarization succeeded, see {}'.format(response['notarization-info']['LogFileURL']))
print('stapling notarization to {}'.format(args.path))
print(check_output(['xcrun', 'stapler', 'staple', args.path]).decode('utf-8'))
if response['notarization-info']['Status'] == 'invalid':
raise RuntimeError('notarization failed, response was\n{}'.format(response))
raise RuntimeError('notarization timed out, last response was\n{}'.format(response))
if __name__ == '__main__':
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment