Built for Shopify Guidelines
This skill enforces Shopify's Built for Shopify (BFS) quality standards during development to ensure apps meet the highest quality bar for the Shopify App Store.
Reference: https://shopify.dev/docs/apps/launch/built-for-shopify/requirements
Quick Compliance Checklist
Use this checklist when reviewing code or building features:
BFS Compliance Review:
- [ ] App is embedded in Shopify admin (App Bridge)
- [ ] Uses session token authentication
- [ ] Primary workflows stay within Shopify admin
- [ ] No additional login/signup required
- [ ] Uses theme app extensions (not Asset API for writes)
- [ ] Meets Web Vitals targets (LCP ≤2.5s, CLS ≤0.1, INP ≤200ms)
- [ ] Uses Polaris components matching admin styling
- [ ] Mobile responsive design
- [ ] Uses nav menu (s-app-nav) and contextual save bar
- [ ] Error messages are red, contextual, and helpful
- [ ] No dark patterns or pressure tactics
- [ ] Premium features are disabled and labeled
- [ ] Promotional content is dismissible
1. Integration Requirements
Embedding (MANDATORY)
Apps MUST be embedded in the Shopify admin:
<!-- Add to <head> of every document -->
<script src="https://cdn.shopify.com/shopifycloud/app-bridge.js"></script>
// Use session token authentication
import { authenticate } from "@shopify/shopify-app-remix/server";
export async function loader({ request }) {
const { session } = await authenticate.admin(request);
// ...
}
Primary Workflows
All primary app workflows MUST be completable within the Shopify admin:
- No external website required for core functionality
- Third-party connection settings must be accessible in-app
- Simplified monitoring/reporting on app homepage
Clean Installation
For storefront apps, use theme app extensions instead of Asset API:
<!-- extensions/theme-extension/blocks/my-block.liquid -->
{% schema %}
{
"name": "My App Block",
"target": "section",
"settings": []
}
{% endschema %}
Do NOT use Asset API to create, modify, or delete theme files (reading is allowed).
2. Performance Requirements
Web Vitals Targets (75th percentile)
| Metric | Target | Description |
|---|---|---|
| LCP | ≤ 2.5s | Largest Contentful Paint |
| CLS | ≤ 0.1 | Cumulative Layout Shift |
| INP | ≤ 200ms | Interaction to Next Paint |
Optimization Strategies
// Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'));
// Use React.memo for expensive renders
const ExpensiveList = memo(({ items }) => (
// ...
));
// Avoid layout shifts with skeleton loaders
<Suspense fallback={<SkeletonPage />}>
<AppContent />
</Suspense>
Storefront Performance
- Must not reduce Lighthouse score by more than 10 points
- Checkout requests: p95 ≤ 500ms, failure rate ≤ 0.1%
3. Design Requirements
Familiar (Match Shopify Admin)
Use Polaris web components to match admin styling:
<!-- Use s-page for page structure -->
<s-page>
<s-title-bar title="My Page">
<s-button slot="primary-action">Save</s-button>
</s-title-bar>
<s-layout>
<s-layout-section>
<s-card>
<s-text>Content in cards</s-text>
</s-card>
</s-layout-section>
</s-layout>
</s-page>
Rejection reasons to avoid:
- Custom button colors (use Polaris defaults)
- Serif/script fonts
- Non-standard background colors
- Content not in card containers
- Poor contrast (must meet WCAG 2.1 AA)
Navigation
Use App Bridge nav menu:
<s-app-nav>
<s-nav-item href="/dashboard" selected>Dashboard</s-nav-item>
<s-nav-item href="/settings">Settings</s-nav-item>
</s-app-nav>
Do NOT:
- Create custom navigation menus
- Use emojis in nav items
- Have separate "Home" link (app name should link to home)
Contextual Save Bar
Use for all form inputs:
import { useAppBridge } from "@shopify/app-bridge-react";
import { SaveBar } from "@shopify/app-bridge/actions";
function SettingsForm() {
const app = useAppBridge();
const showSaveBar = () => {
const saveBar = SaveBar.create(app, {
saveAction: { disabled: false, loading: false },
discardAction: { disabled: false, loading: false },
});
saveBar.dispatch(SaveBar.Action.SHOW);
};
// ...
}
Modals
Use s-modal with proper slots:
<s-modal heading="Confirm Action">
<p>Modal content here</p>
<s-button slot="secondary-action">Cancel</s-button>
<s-button slot="primary-action" variant="primary">Confirm</s-button>
</s-modal>
Mobile Responsiveness
- No horizontal scrolling on mobile
- Content must wrap/stack appropriately
- All content accessible (no hidden without expand mechanism)
4. Helpful UX Requirements
Onboarding
- Concise, guiding merchants to completion
- Dismissible after completion
- No requirement to install additional apps
- Justify any merchant information requests
Homepage
Must include:
- Theme block/embed status (if applicable)
- Relevant metrics/analytics
- Dynamic content (not just static links)
Error Messages
<!-- CORRECT: Red, contextual, persistent -->
<s-text-field
label="Email"
error="Please enter a valid email address"
/>
<!-- WRONG: Using toast for errors -->
<!-- WRONG: Non-red error colors -->
<!-- WRONG: Top-of-page errors for field issues -->
5. User-Friendly Requirements (No Dark Patterns)
Prohibited Practices
| Don't | Why |
|---|---|
| Countdown timers for upgrades | Pressures merchants |
| "No thanks, I prefer less sales" | Guilt/shame language |
| Auto-appearing modals/popovers | Distracts merchants |
| Guarantee outcomes ("increase sales 18%") | False claims |
| Review incentives ("5-star for Pro") | Manipulative |
| Non-dismissible promotions | Overwhelms merchants |
| Shopify-like icons/colors | Impersonation |
Premium Features
<!-- Features must be visually AND functionally disabled -->
<s-card>
<s-text variant="headingMd">Advanced Analytics</s-text>
<s-badge tone="info">Pro Plan</s-badge>
<s-button disabled>View Analytics</s-button>
<s-link url="/upgrade">Upgrade to unlock</s-link>
</s-card>
- Shopify Plus-only features must be hidden (not just disabled) for non-Plus merchants
6. Category-Specific Requirements
If Building: Ads/Analytics/Affiliate Apps
// MUST use Web Pixel extensions, NOT script tags
// extensions/web-pixel/src/index.ts
import { register } from "@shopify/web-pixels-extension";
register(({ analytics }) => {
analytics.subscribe("page_viewed", (event) => {
// Track event
});
});
If Building: Email/SMS Marketing Apps
- Sync customer data to/from Shopify
- Use Shopify segments via customer segment action extension
- Use visitors API for identifying store visitors
If Building: Discount Apps
# Use discount functions or native APIs
# Do NOT use draft orders for custom discounts
# Use discountRedeemCodeBulkAdd for multiple codes
mutation {
discountRedeemCodeBulkAdd(
discountId: "gid://shopify/DiscountCodeNode/123"
codes: [{ code: "CODE1" }, { code: "CODE2" }]
) {
bulkCreation {
id
}
}
}
If Building: Subscription Apps
- Use Selling Plan API, Subscription Contract API, Customer Payment Method API
- Use theme app blocks for product pages
- Display subscription info clearly (name, price, savings)
- Use Customer Account UI extensions for subscription management
If Building: Fulfillment Apps
- Wait for merchant fulfillment requests before fulfilling
- Respond to fulfillment requests within 4 hours
- Respond to cancellation requests within 1 hour
- Add tracking info within 1 hour of fulfillment creation
- 99% completion rate, 99.9% callback success rate
If Building: Returns Apps
Sync all return lifecycle events:
- returnCreate, reverseDeliveryCreateWithShipping
- reverseFulfillmentOrderDispose, returnLineItemRemoveFromReturn
- returnCancel, returnClose, refundCreate
Code Review Checklist
When reviewing Shopify app code for BFS compliance:
Technical:
- [ ] App Bridge script in <head>
- [ ] Session token auth (no cookie auth)
- [ ] Theme app extensions (no Asset API writes)
- [ ] Web Pixel extensions (no script tags for tracking)
- [ ] Proper API usage for app category
UI/UX:
- [ ] Polaris components throughout
- [ ] s-app-nav for navigation
- [ ] Contextual save bar for forms
- [ ] s-modal with proper slots
- [ ] Responsive design
- [ ] WCAG 2.1 AA contrast
Content:
- [ ] No outcome guarantees
- [ ] No pressure tactics
- [ ] Dismissible promotional content
- [ ] Disabled + labeled premium features
- [ ] Clear error messages (red, contextual)
- [ ] Helpful onboarding
- [ ] Dynamic homepage content