# Publish your macOS App outside the App Store

> How to publish your macOS app outside the App Store: notarization, code signing, Sparkle auto-updates, licensing, and lessons from building Picmal.

Source: https://picmal.app/blog/publish-your-macos-app-outside-the-app-store

When I first started building <a href="https://picmal.app/" target="_blank">Picmal</a>, a simple image converter for macOS, the App Store was the obvious destination. That changed quickly.

After paying for the Apple Developer license and getting my first version ready, I hit an unexpected wall: every time users tried to save an image, a permission dialog appeared. It was intrusive and ruined the experience. The cause was Apple’s sandbox.

The only way around it was to skip the App Store entirely and distribute the app independently.

But before that, some context. I built Picmal because I was tired of the same ritual every time I needed to convert an image: open a browser, find an online converter, upload the file, wait for it to process on some server, download the result. I wanted something that ran locally and didn't involve a browser tab.

So I decided to make it native, even though I had never built a fully native app before. That was challenge number one. Challenge number two was finding a smooth way to share it without the App Store.

After some research, I discovered <a href="https://gumroad.com/" target="_blank">Gumroad</a>. It turned out to be the simplest way to sell and distribute my app directly. Here's how I did it:

## Step 1: Build and Export the App from Xcode

Once your app is ready for release, do the following:

![Xcode direct distribution option for exporting macOS app outside App Store](/images/blog/publish-your-macos-app-outside-the-app-store/direct-distribution.webp)

1. In Xcode, go to **Product > Archive**. Select the method **"Direct distribution"**.
2. Wait until the build status shows **"Ready for Distribution"**.
3. Click on **"Export"** and you will export the `.app` file.

![Xcode export dialog showing app ready for distribution](/images/blog/publish-your-macos-app-outside-the-app-store/expo-app-store.webp)

## Step 2: Create a DMG Installer

Shipping a bare `.app` file feels unfinished. I used <a href="https://github.com/sindresorhus/create-dmg" target="_blank">create-dmg</a>, a CLI tool by Sindre Sorhus that produces a proper DMG with an Applications folder shortcut and a clean layout:

```bash
# Install create-dmg if you haven't already
brew install create-dmg

# Create the DMG installer
create-dmg \
  --volname "Your App Name" \
  --window-pos 200 120 \
  --window-size 600 300 \
  --icon-size 100 \
  --icon "YourApp.app" 175 120 \
  --hide-extension "YourApp.app" \
  --app-drop-link 425 120 \
  "YourApp.dmg" \
  "source_folder/"
```

![Terminal output showing create-dmg tool generating a DMG installer for macOS app](/images/blog/publish-your-macos-app-outside-the-app-store/create-dmg.webp)

You'll have a DMG, but it's not ready yet. Without notarization, macOS will block it with this lovely warning:

![macOS security warning dialog showing malware detection for unsigned app](/images/blog/publish-your-macos-app-outside-the-app-store/malware.webp)

## Step 3: Notarize DMG installer

Save a credentials profile first, so you don't have to dig up passwords every time you release an update:

```bash
xcrun notarytool store-credentials --apple-id "your-email@example.com" \
  --team-id "YOUR_TEAM_ID_HERE" \
  --password "your-app-specific-password" \
  your-app-profile
```

> **Note:** The password you use here must be an <a href="https://support.apple.com/en-us/102654" target="_blank">app-specific password</a> generated from your Apple ID account. Regular Apple ID passwords will not work for notarization. If you haven't created one before, follow <a href="https://support.apple.com/en-us/102654" target="_blank">Apple's instructions</a> to generate an app-specific password for use with `notarytool`.

After creating the profile you need to notarize the DMG file with your newly created profile:

```bash
xcrun notarytool submit YourApp.dmg --keychain-profile "your-app-profile" --wait
```

Now you need to staple the DMG:

```bash
xcrun stapler staple YourApp.dmg
```

Verify the notarization worked:

```bash
spctl --assess --type open --context context:primary-signature -v YourApp.dmg

# Expected output:
# YourApp.dmg: accepted
# source=Notarized Developer ID
```

If the output says `accepted`, you're done. Upload the DMG to Gumroad (or wherever you sell) and start shipping.
