Shopify 12 min read

Shopify App Types Explained: Public, Custom, and Private Apps

A developer's guide to choosing between public, custom, and private Shopify apps — covering OAuth flows, API access, review requirements, and which type fits your use case.

A
Aumlytics Team
·

When merchants ask us to build something Shopify doesn’t do out of the box, the first question we ask is: what type of app do you need? The answer determines the entire architecture — OAuth flow, API access levels, distribution method, and ongoing maintenance model.

Most non-developers assume “an app is an app.” In practice, Shopify has three distinct app types, each with different capabilities, constraints, and review processes. Building the wrong type wastes weeks.


The Three App Types

1. Public Apps

What they are: Apps distributed through the Shopify App Store. Any merchant can install them. Shopify reviews all public apps before they’re listed.

How access works: OAuth 2.0 — merchants install the app through the App Store, grant permissions via a consent screen, and the app receives a permanent access token scoped to that shop.

Who builds them: ISVs (independent software vendors), agencies building products, developers who want to sell to multiple merchants.

Key characteristics:

  • Requires Shopify Partner account
  • Must pass Shopify’s app review (can take 1–6 weeks)
  • Access to all public Shopify APIs
  • Billing must use Shopify’s Billing API (for App Store apps)
  • Must be built with an HTTPS server that handles OAuth callbacks

Official reference: Shopify Public Apps documentation


2. Custom Apps

What they are: Apps built for a single merchant only. Installed directly from the Shopify Admin — no App Store listing, no Shopify review process.

How access works: Custom apps use static Admin API access tokens generated in the Shopify Admin. No OAuth flow — the merchant creates the app in their admin and gets a token.

Who builds them: Agencies building merchant-specific solutions, internal development teams, integrations with proprietary systems.

Key characteristics:

  • No App Store listing or Shopify review
  • Faster to deploy (no review queue)
  • Static access tokens (no OAuth needed)
  • Can only be installed on ONE specific shop
  • Billing handled outside Shopify (invoice the merchant directly)
  • Access to all public APIs the merchant grants

Official reference: Custom apps in Shopify Admin


3. Private Apps (Legacy — Deprecated)

Shopify deprecated private apps in early 2022. If you’re still using a private app, it still works, but you cannot create new ones. Shopify replaced them with Custom Apps.

If you have a legacy private app integration, migrate it to a Custom App — the access token format changed and some API functionality is restricted for private apps going forward.

Reference: Private apps deprecation notice


Choosing the Right Type: Decision Tree

Does this app need to work on multiple Shopify stores?

  • Yes → Public App
  • No → Custom App

Does the merchant need to install it through the App Store?

  • Yes → Public App
  • No, it’s just for us → Custom App

Do you need Shopify Billing API (charging merchants through Shopify)?

  • Yes → Public App (Billing API only works in public/unlisted apps)
  • No → Custom App

Is speed of deployment critical (weeks vs months)?

  • Custom App can be live in days; Public App review takes 1–6 weeks minimum

Common use cases by type:

Use CaseApp Type
Sell an app to thousands of merchantsPublic
Build a custom order management tool for one clientCustom
Connect a merchant’s ERP to ShopifyCustom
Build a loyalty/rewards system to distributePublic
Internal analytics dashboard for one brandCustom
Migrate from an old private appCustom

Building a Public App: Technical Requirements

Public apps must meet Shopify’s technical requirements. Here’s what that means in practice.

OAuth 2.0 Flow

Public apps authenticate merchants through OAuth. When a merchant installs your app:

  1. Shopify redirects them to your app’s install URL with an HMAC-signed request
  2. Your app validates the HMAC signature
  3. Your app redirects the merchant to Shopify’s OAuth consent screen with the required scopes
  4. Merchant approves — Shopify redirects back to your callback URL with a code
  5. Your app exchanges the code for a permanent access token
  6. Store the access token securely (encrypted, per-shop)
// Step 1: Validate incoming install request
import { createHmac } from 'crypto';

function validateHmac(query) {
  const { hmac, ...rest } = query;
  const message = Object.keys(rest)
    .sort()
    .map(key => `${key}=${rest[key]}`)
    .join('&');
  const expected = createHmac('sha256', process.env.SHOPIFY_API_SECRET)
    .update(message)
    .digest('hex');
  return hmac === expected;
}

// Step 2: Build auth URL
function buildAuthUrl(shop, state) {
  const scopes = 'read_orders,write_products,read_customers';
  const redirectUri = `https://yourapp.com/auth/callback`;
  return `https://${shop}/admin/oauth/authorize?client_id=${process.env.SHOPIFY_API_KEY}&scope=${scopes}&redirect_uri=${redirectUri}&state=${state}`;
}

// Step 3: Exchange code for token
async function getAccessToken(shop, code) {
  const response = await fetch(`https://${shop}/admin/oauth/access_token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: process.env.SHOPIFY_API_KEY,
      client_secret: process.env.SHOPIFY_API_SECRET,
      code,
    }),
  });
  const { access_token } = await response.json();
  return access_token;
}

Shopify’s official recommendation since 2023 is to build apps with the Remix framework using the @shopify/shopify-app-remix package. This handles the entire OAuth flow, session management, and App Bridge integration automatically.

# Create a new Shopify app with Remix
npm init @shopify/app@latest
# Select: Start by building a new app
# Select: Remix

The Remix template gives you:

  • OAuth flow handled by shopifyApp() middleware
  • Session storage (SQLite for dev, configurable for production)
  • App Bridge integration for embedded admin UI
  • Polaris component library pre-configured
  • TypeScript by default

Reference: Shopify Remix app template

Required API Scopes

When requesting scopes in your OAuth flow, request only what you need. Shopify reviewers flag apps that request excessive permissions.

// Minimal scopes for common use cases:

// Read orders only
const scopes = 'read_orders';

// Full order management
const scopes = 'read_orders,write_orders';

// Product management
const scopes = 'read_products,write_products';

// Customer data (requires justification in app review)
const scopes = 'read_customers';

// Store information
const scopes = 'read_content,read_themes';

Full scopes list: Shopify API access scopes


Building a Custom App: Step-by-Step

Custom apps are much simpler — no OAuth, no review, no deployment server required for many use cases.

Step 1: Create the App in Shopify Admin

  1. Log into the merchant’s Shopify Admin
  2. SettingsApps and sales channelsDevelop apps
  3. Click Create an app
  4. Give it a name (e.g., “ERP Integration”)
  5. Click Configure Admin API scopes → select the permissions you need
  6. Click Install app → confirm

Step 2: Get the Access Token

  1. After installing, click API credentials
  2. Under Admin API access tokenReveal token once — copy it immediately (shown once only)
  3. Store it securely (environment variable, secret manager)

Step 3: Make API Calls

// Custom app API call — no OAuth, just your static token
const SHOP = 'your-store.myshopify.com';
const TOKEN = process.env.SHOPIFY_ADMIN_TOKEN;

// REST Admin API (legacy but still works)
const response = await fetch(
  `https://${SHOP}/admin/api/2024-10/orders.json?status=any&limit=10`,
  {
    headers: {
      'X-Shopify-Access-Token': TOKEN,
      'Content-Type': 'application/json',
    },
  }
);
const { orders } = await response.json();

// GraphQL Admin API (recommended for new integrations)
const graphqlResponse = await fetch(
  `https://${SHOP}/admin/api/2024-10/graphql.json`,
  {
    method: 'POST',
    headers: {
      'X-Shopify-Access-Token': TOKEN,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      query: `{
        orders(first: 10, query: "status:any") {
          edges {
            node {
              id
              name
              totalPriceSet { shopMoney { amount currencyCode } }
            }
          }
        }
      }`,
    }),
  }
);

Reference: Shopify Admin API GraphQL


The Shopify App Review Process (Public Apps)

If you’re building a public app, plan for the review process. Here’s what Shopify checks:

Technical Requirements

  • App loads within 3 seconds on a standard connection
  • Embedded admin UI uses App Bridge (no iframes, no pop-ups outside App Bridge)
  • OAuth flow is CSRF-protected (state parameter)
  • Webhook endpoints respond within 5 seconds
  • App handles GDPR webhooks: customers/redact, shop/redact, customers/data_request

Design Requirements

  • Embedded pages use Polaris components (Shopify’s design system)
  • No dark patterns — pricing must be clearly displayed
  • Settings page must exist with clear descriptions of what the app does

GDPR Webhooks (Required)

Every public app must handle three GDPR webhooks:

// These are mandatory — your app will be rejected without them

// 1. Customer data request (respond within 30 days)
app.post('/webhooks/customers/data_request', async (req, res) => {
  // Find and return all data you store for this customer
  res.status(200).send();
});

// 2. Customer redact (delete customer data)
app.post('/webhooks/customers/redact', async (req, res) => {
  // Delete all PII for this customer from your database
  res.status(200).send();
});

// 3. Shop redact (delete all shop data after uninstall)
app.post('/webhooks/shop/redact', async (req, res) => {
  // Delete all data associated with this shop
  res.status(200).send();
});

Reference: GDPR webhooks for Shopify apps


Billing API: Public Apps Only

If you’re building a public app and want to charge merchants, you must use Shopify’s Billing API. Shopify takes a 20% revenue share.

// Create a subscription (using @shopify/shopify-app-remix)
import { authenticate } from '../shopify.server';

export async function action({ request }) {
  const { billing } = await authenticate.admin(request);

  // Check if merchant already has a subscription
  const { hasActivePayment, appSubscriptions } = await billing.check({
    plans: ['Professional Plan'],
    isTest: false,
  });

  if (!hasActivePayment) {
    // Redirect to subscription confirmation
    await billing.request({
      plan: 'Professional Plan',
      isTest: false,
      returnUrl: 'https://yourapp.com/admin',
    });
  }
}

Billing types:

  • Recurring — monthly or annual subscription
  • One-time — single charge
  • Usage-based — charge per unit (orders, API calls, etc.)

Reference: Shopify Billing API


Deployment

Custom Apps

Since there’s no user-facing OAuth flow, custom apps can be simple scripts, serverless functions, or lightweight Node.js apps. Common deployment targets:

  • AWS Lambda — for event-driven integrations (webhook handlers)
  • Railway / Fly.io — for always-on apps with a UI
  • Vercel — for Remix-based custom apps

Public Apps

Must be always-on with low latency. Shopify tests response times during review.

  • Fly.io — recommended by Shopify (used in their starter templates)
  • Railway — simple deployment, good for Remix apps
  • AWS / GCP — for enterprise-scale apps

Common Questions

Can I convert a custom app to a public app later? Not directly — they’re different authentication models. You’d need to rebuild the OAuth flow and go through app review. Plan which type you need upfront.

Do I need a server for a custom app? No — if you’re just syncing data on a schedule, a serverless function (Lambda, Cloud Functions) with a static access token is sufficient. You only need a persistent server if you handle webhooks or have an admin UI.

What’s the difference between the REST and GraphQL Admin APIs? Both give you access to the same data. GraphQL is more efficient (request exactly the fields you need), better for complex queries, and Shopify’s focus for new features. REST still works for everything but some new endpoints are GraphQL-only.


We build custom Shopify apps for merchants who’ve outgrown what the App Store offers. Book a free consultation to discuss your requirements and get an honest scope estimate.

#shopify#shopify-app#app-development#oauth#shopify-api#remix

Want This Implemented Correctly?

Let our team apply these concepts to your specific setup — with QA validation and 30 days of support.