From shopify-apps
Expert guidance for building Shopify Apps using modern best practices. Use when developing Shopify Apps, creating app extensions, working with Shopify APIs (GraphQL Admin/Storefront), implementing webhooks, managing app authentication/authorization, building embedded apps, creating custom app extensions (checkout UI, product subscription, theme extensions), or any Shopify app development task. Assumes Shopify Dev MCP server is available at https://shopify.dev/docs/apps/build/devmcp for accessing Shopify's development resources and documentation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/shopify-apps:shopify-appsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Expert guidance for building Shopify Apps with modern architecture, authentication patterns, and best practices based on current Shopify documentation.
Expert guidance for building Shopify Apps with modern architecture, authentication patterns, and best practices based on current Shopify documentation.
This skill provides expertise in:
Shopify Dev MCP Server: This skill assumes the Shopify Dev MCP server is available and connected. The MCP server provides:
When documentation is needed, use the MCP server to fetch the latest information from Shopify's official docs.
npm init @shopify/app@latest
# or
shopify app init
shopify.app.tomlModern Shopify apps use Session Tokens (for embedded apps) and OAuth (for authorization):
// Session token validation (embedded apps)
import { authenticate } from './shopify.server';
export async function loader({ request }) {
const { session, admin } = await authenticate.admin(request);
// session contains shop, accessToken, etc.
}
// OAuth installation flow
// Handled automatically by Shopify App Remix/CLI templates
Key principles:
Admin API queries (for app backend):
const response = await admin.graphql(
`#graphql
query getProducts($first: Int!) {
products(first: $first) {
edges {
node {
id
title
handle
status
}
}
}
}`,
{ variables: { first: 10 } }
);
const data = await response.json();
Storefront API queries (for customer-facing features):
const response = await fetch(`https://${shop}/api/2024-01/graphql.json`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Storefront-Access-Token': storefrontAccessToken,
},
body: JSON.stringify({ query, variables }),
});
Best practices:
Build custom UI in checkout flow:
// extensions/checkout-ui/src/Checkout.jsx
import {
reactExtension,
useApi,
Banner,
} from '@shopify/ui-extensions-react/checkout';
export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />
);
function Extension() {
const { cost } = useApi();
return (
<Banner status="info">
Your order total: {cost.totalAmount.amount}
</Banner>
);
}
Extension targets:
purchase.checkout.block.render - Checkout pagepurchase.checkout.cart-line-item.render-after - After cart itemspurchase.thank-you.block.render - Thank you pageInject app functionality into themes:
{% comment %} extensions/theme-extension/blocks/app-block.liquid {% endcomment %}
<div class="app-block" {{ block.shopify_attributes }}>
<h3>{{ block.settings.heading }}</h3>
<p>{{ block.settings.description }}</p>
</div>
{% schema %}
{
"name": "App Block",
"target": "section",
"settings": [
{
"type": "text",
"id": "heading",
"label": "Heading"
}
]
}
{% endschema %}
Enable subscription functionality:
// Configure subscription plans
const subscriptionPlan = {
name: "Monthly subscription",
options: {
deliveryPolicy: {
interval: "MONTH",
intervalCount: 1
},
pricingPolicy: {
percentage: 10 // 10% discount
}
}
};
Initialize App Bridge:
import createApp from '@shopify/app-bridge';
const app = createApp({
apiKey: process.env.SHOPIFY_API_KEY,
host: new URLSearchParams(location.search).get('host'),
});
Use Polaris components for consistent UI:
import { Page, Card, Button } from '@shopify/polaris';
function AppPage() {
return (
<Page title="Dashboard">
<Card sectioned>
<Button primary>Save</Button>
</Card>
</Page>
);
}
Navigation:
import { Redirect } from '@shopify/app-bridge/actions';
const redirect = Redirect.create(app);
redirect.dispatch(Redirect.Action.ADMIN_PATH, '/products');
Register webhooks:
// shopify.server.js or similar
await shopify.webhooks.addHandlers({
PRODUCTS_CREATE: {
deliveryMethod: DeliveryMethod.Http,
callbackUrl: '/webhooks/products/create',
},
ORDERS_PAID: {
deliveryMethod: DeliveryMethod.Http,
callbackUrl: '/webhooks/orders/paid',
},
});
Handle webhook requests:
export async function action({ request }) {
const { topic, shop, payload } = await authenticate.webhook(request);
switch (topic) {
case 'PRODUCTS_CREATE':
await handleProductCreate(shop, payload);
break;
case 'ORDERS_PAID':
await handleOrderPaid(shop, payload);
break;
}
return new Response();
}
Webhook security:
Implement usage-based or subscription billing:
// Create a subscription charge
const response = await admin.graphql(
`#graphql
mutation appSubscriptionCreate($name: String!, $returnUrl: URL!) {
appSubscriptionCreate(
name: $name
returnUrl: $returnUrl
lineItems: [{
plan: {
appRecurringPricingDetails: {
price: { amount: 10, currencyCode: USD }
interval: EVERY_30_DAYS
}
}
}]
) {
userErrors {
field
message
}
confirmationUrl
appSubscription {
id
status
}
}
}`,
{ variables: { name: "Premium Plan", returnUrl: `${appUrl}/billing/callback` } }
);
// Redirect merchant to confirmationUrl for approval
Local development:
shopify app dev
# Starts local server with tunnel for OAuth
Testing webhooks locally:
shopify app webhooks trigger --topic=products/create
Partner Dashboard testing:
customers/data_request, customers/redact, shop/redactFor processing large datasets:
const bulkOperation = await admin.graphql(
`#graphql
mutation {
bulkOperationRunQuery(
query: """
{
products {
edges {
node {
id
title
}
}
}
}
"""
) {
bulkOperation {
id
status
}
}
}`
);
// Poll for completion or use webhook
Store custom data on Shopify resources:
// Create metafield
await admin.graphql(
`#graphql
mutation createMetafield($metafields: [MetafieldsSetInput!]!) {
metafieldsSet(metafields: $metafields) {
metafields {
id
namespace
key
value
}
}
}`,
{
variables: {
metafields: [{
ownerId: productId,
namespace: "app",
key: "custom_data",
value: JSON.stringify({ setting: true }),
type: "json"
}]
}
}
);
For public-facing app features:
// Configure in Partner Dashboard: /apps/your-app -> App proxy
// Liquid: GET /apps/your-app-slug
// Backend: https://your-app.com/proxy
export async function loader({ request }) {
const url = new URL(request.url);
const shop = url.searchParams.get('shop');
// Return HTML/JSON for storefront
return json({ data: "public data" });
}
This skill includes detailed reference documentation for advanced topics:
When detailed API information or current examples are needed, use the Shopify Dev MCP server to access:
Primary documentation source: https://shopify.dev/docs/apps/build
npx claudepluginhub stilero/claude-plugins --plugin shopify-appsGuides Shopify app development with Remix template: app types, OAuth flow, session tokens, App Bridge, webhooks, extensions, and embedded admin apps.
Build Shopify apps, extensions, and themes using GraphQL Admin API, Shopify CLI, Polaris UI, and Liquid. Covers routing, CLI commands, access scopes, and GraphQL patterns.
Guides Shopify app architecture choices: embedded Remix admin apps, Hydrogen headless storefronts, standalone integrations, theme extensions. Use for architecture decisions.