← Shopify App BuilderCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Shopify App Builder
Snapshot Sep 30, 2026 · 23:13 UTC · version 1.4.1
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "Prepare a Shopify app for Built for Shopify status. Covers current quality criteria, performance, accessibility, Shopify admin integration, compliance webhooks, observability, support, application readiness, and ongoing eligibility.",
"included_files": [],
"name": "built-for-shopify-standards",
"skill_md_contents": "---\nname: built-for-shopify-standards\ndescription: \"Prepare a Shopify app for Built for Shopify status. Covers current quality criteria, performance, accessibility, Shopify admin integration, compliance webhooks, observability, support, application readiness, and ongoing eligibility.\"\n---\n\n# Built for Shopify Standards\n\nThe official quality bar for Shopify App Store apps. Qualifying apps receive the Built for Shopify highlight and badge, additional App Store promotion, eligibility for promotion on other merchant surfaces, and priority review for future app submissions. BFS does not create a separate revenue-share tier.\n\nThis skill is the full requirement matrix as of May 2026, with rejection patterns, a 50-item self-check, and a decision tree to tell you whether you're ready to apply.\n\n---\n\n## 1. When to use this skill\n\nTrigger this skill when:\n\n- You're planning to submit an app for the Built for Shopify (BFS) designation\n- You got a \"fails to meet Built for Shopify standards\" rejection and want to fix it\n- You're scoping a v1 app and want to build to BFS from the start (cheaper than retrofitting)\n- A merchant or partner mentioned your app \"isn't Built for Shopify yet\"\n- You're doing a 90-day audit before reapplying after a previous BFS failure\n- You're deciding whether the promotional benefits justify the implementation and ongoing-compliance work\n- You want to know exactly what \"integration depth\" means in BFS-speak (it's specific)\n- You're comparing your app against a competitor that has the badge and want to close the gap\n- You're hitting LCP, INP, CLS, or API p95 problems and want to know the actual gate numbers\n- You're wiring up GDPR webhooks and want to confirm BFS still requires all three\n\nDon't use this skill for:\n\n- General App Store submission (different bar — that's `app-validation`)\n- Performance debugging itself (that's `app-performance` — this skill references those thresholds but doesn't reteach them)\n- Polaris implementation details (that's a separate UI/design skill)\n- Listing copy or screenshots (that's `app-listing-optimization`)\n- Pricing strategy (that's `app-pricing-strategy`)\n\nThis skill is the audit framework. The fix-it skills live elsewhere.\n\n---\n\n## 2. What Built for Shopify actually is\n\n### 2.1 It's a designation, not a category\n\nA common misunderstanding: founders think \"Built for Shopify\" is a category they apply to and join. It isn't. Every BFS app stays in its primary category (Marketing, Fulfillment, etc.) and additionally earns a **badge** that displays on the App Store listing and in search results.\n\nThe badge says, in effect: \"Shopify has tested this app against a defined quality bar and it currently passes.\" It's not a permanent stamp — Shopify re-evaluates apps continuously and apps **lose BFS status** if they fall below thresholds (e.g., LCP regresses, support response time slips, a customer complaint storm hits, you start failing accessibility checks).\n\n### 2.2 Why merchants notice the badge\n\nShopify documents these benefits:\n\n- A Built for Shopify highlight on the app listing\n- A badge on App Store cards, including search results and category pages\n- A merchant-facing search filter for Built for Shopify apps\n- Additional promotion in the Shopify App Store and eligibility for promotion on other key merchant surfaces\n- Priority review for future app submissions from BFS developers\n\nTreat any claim about conversion lift, install velocity, ranking weight, or guaranteed featuring as an experiment to measure for your app, not as an official BFS guarantee.\n\n### 2.3 The revenue share angle (verify the exact terms before relying on it)\n\nShopify's revenue share for App Store developers has shifted multiple times. As of the most recent published policy update:\n\n- **First $1M USD in lifetime gross app revenue earned from January 1, 2025**: 0% revenue share (you keep 100%)\n- **Above $1M lifetime**: 15% revenue share (you keep 85%)\n\nCritical clarifications:\n\n- Earnings before Jan 1, 2025 don't count toward the $1M threshold.\n- Revenue is aggregated across apps and associated developer accounts. Associated accounts must be declared; don't split related accounts to avoid the threshold.\n- All billing is also subject to a 2.9% processing fee, applicable sales tax, and possible regional fees.\n- Very large developers have separate eligibility rules, so verify Shopify's current policy for your organization.\n- This 0%/15% structure applies whether or not you have BFS — BFS does **not** currently grant a special revenue share tier on top of this (an older \"Built for Shopify gets 15%/20% while non-BFS gets nothing\" model existed in some historical content; that's outdated)\n\n**Action**: Before submitting financial projections or making a strategic decision based on revenue share, re-read `https://shopify.dev/docs/apps/launch/distribution/revenue-share` and the latest changelog entry. Shopify has changed this policy three times in the last four years.\n\n### 2.4 What BFS does NOT do\n\nUseful to know so you don't oversell internally:\n\n- It does **not** guarantee installs (the badge helps; it doesn't replace marketing)\n- It does **not** exempt you from App Store guideline violations (you can still get pulled for trademark issues, security failures, etc.)\n- It does **not** give you direct contact with Shopify reviewers (you still go through standard channels)\n- It does **not** make your app eligible for the Shopify Plus Certified App Program (that's a separate, much higher bar)\n- It is **not** the same as the Shopify Plus Technology Partner badge\n\n---\n\n## 3. Full requirement matrix (May 2026)\n\nThree pillars: **Performance**, **Design**, **Integration**. Plus operational gates: support, observability, compliance. All must be met simultaneously and continuously.\n\n### 3.1 Performance pillar\n\n| Requirement | Threshold | Measurement | Window |\n|---|---|---|---|\n| **LCP** (Largest Contentful Paint) — admin embedded | ≤ 2.5s at p75 | Web Vitals API via App Bridge | 28 days, min 100 launches |\n| **INP** (Interaction to Next Paint) — admin embedded | ≤ 200ms at p75 | Web Vitals API via App Bridge | 28 days, min 100 launches |\n| **CLS** (Cumulative Layout Shift) — admin embedded | ≤ 0.1 at p75 | Web Vitals API via App Bridge | 28 days, min 100 launches |\n| **API p95 latency** (your server endpoints) | < 500ms | Shopify Partner dashboard / your APM | 28 days |\n| **API failure rate** | < 0.1% | Shopify Partner dashboard / your APM | 28 days, min 1000 requests |\n| **Storefront Lighthouse delta** (if you ship theme app extensions) | ≤ 10 points reduction | Lighthouse run with/without your extension | Spot check |\n| **Storefront JS budget per surface** (theme app extensions) | ≤ 50KB gzipped (rule of thumb) | Your bundle audit | Per release |\n| **Webhook ACK latency** | < 5s (target < 2s) | Your monitoring + Shopify retry logs | Continuous |\n\nSee `../app-performance/SKILL.md` for the fix-it playbook for every metric above. This skill enforces the gate while the companion skill provides the remediation workflow.\n\n### 3.2 Design pillar\n\n| Requirement | Standard |\n|---|---|\n| **Polaris adherence** | Use Polaris components for all admin UI; deviations must match Polaris visual language |\n| **App Bridge version** | Latest App Bridge (currently 4.x, loaded via CDN script in `<head>`, before your bundle) |\n| **Embedded experience** | App renders embedded in Shopify admin by default; primary workflows complete inside the admin |\n| **Mobile responsive** | All admin views functional on Shopify mobile admin app (iOS + Android) |\n| **Polaris CSS loaded exactly once** | At the root, no duplicate imports, no per-route loading |\n| **Accessibility** | WCAG 2.1 Level AA (matches Polaris's own target) |\n| **Dark mode** | Polaris components handle automatically; custom UI must support it |\n| **Internationalization** | Use Polaris's i18n system; locale awareness for all merchant-facing text |\n| **Visual consistency** | Spacing, typography, color tokens come from Polaris; no ad-hoc CSS for these |\n| **Loading states** | Skeletons match final dimensions to prevent CLS |\n| **Empty states** | Provided for every list, table, and dashboard view |\n| **Error states** | Human-readable error messages, never raw error codes or stack traces |\n\n### 3.3 Integration pillar\n\nThis is the BFS-specific one most apps fail. \"Integration depth\" means: **your app feels like a native part of Shopify, not a third-party iframe**. The reviewer is checking that you've used at least one — and often several — of these surfaces:\n\n| Integration surface | What it does | When BFS reviewers expect it |\n|---|---|---|\n| **Admin Action extensions** | Buttons in the admin's resource pages (Orders, Products, Customers) that invoke your app | If your app operates on Orders/Products/Customers, expected |\n| **Admin Block extensions** | Inline blocks that render your app's UI inside the admin's native resource pages | Strong differentiator; expected for \"deep\" integrations |\n| **Admin Link extensions** | Navigation links that appear in the admin sidebar pointing to your embedded app | Baseline; almost every BFS app has these |\n| **ResourcePicker API** | Native Shopify picker for products, collections, variants — instead of you building your own | Required if your app needs merchants to select these |\n| **Bulk action support** | Selecting many resources at once and invoking your app on the batch | Expected for any app that operates on lists of resources |\n| **Theme App Extensions (App Blocks)** | Storefront UI that merchants add to themes via the theme editor | Required if your app touches the storefront |\n| **Shopify Functions** | Server-side logic that runs in Shopify's infra (discounts, delivery customization, payment customization) | Required if your app modifies checkout/discount/delivery logic |\n| **Web Pixels** | Customer behavior tracking that respects the consent layer | Required for any storefront analytics/tracking app |\n| **Checkout UI Extensions** | UI in checkout (Plus/Shopify Payments only) | Required for checkout-modifying apps |\n| **Metafields + Metaobjects** | First-class storage of your app's data on Shopify's side | Strongly preferred over a private DB for merchant-visible data |\n| **Flow connectors / triggers / actions** | Integration with Shopify Flow | Expected if your app has events worth automating |\n\n**Rule of thumb**: A BFS app uses at least 3 of these. An app that ships only the embedded admin and reads/writes via GraphQL with no other surfaces will frequently get \"lacks integration depth\" feedback.\n\n### 3.4 Compliance pillar\n\n| Requirement | Detail |\n|---|---|\n| **Mandatory privacy webhooks** | All three handlers implemented and returning 200: `customers/data_request`, `customers/redact`, `shop/redact` |\n| **Privacy webhook HMAC verification** | Every webhook handler verifies the `X-Shopify-Hmac-Sha256` header before processing |\n| **Privacy policy** | Public URL, no login required, mentions GDPR + CCPA + data retention period |\n| **Terms of Service** | Public URL, includes app limitations and refund policy |\n| **OAuth scopes minimal** | Request only scopes you actually use; reviewers compare requested vs. observed |\n| **OAuth flow standard** | Use Shopify's official OAuth flow — no custom session schemes |\n| **Session tokens (not third-party cookies)** | For embedded apps; third-party cookies in 2026 are blocked by every modern browser anyway |\n| **HTTPS everywhere** | Valid SSL on every endpoint, including webhook handlers and the support email's domain |\n| **Sensitive data encryption** | Access tokens, API keys, customer PII encrypted at rest |\n| **Data residency** | Honor merchant region preferences if you store EU customer data |\n| **Uninstall hygiene** | App deletes all merchant data on `shop/redact` and removes any theme code it injected |\n\n### 3.5 Support pillar\n\n| Requirement | Standard |\n|---|---|\n| **Support email** | Functional, monitored, on your own domain (not gmail.com) |\n| **Public help center / docs** | Searchable, covers setup + top 10 questions |\n| **Response time SLA** | Public commitment; BFS reviewers expect **≤ 24 business hours** as the floor |\n| **Live chat or messaging channel** | Not strictly required but strongly preferred for higher-tier BFS visibility |\n| **Status page** | Public uptime + incident history (StatusPage.io free tier or similar) |\n| **In-app help** | Contextual help links from inside your app to the relevant doc |\n| **Onboarding** | Merchant reaches first value in < 2 minutes from install |\n\n### 3.6 Observability pillar\n\n| Requirement | Why |\n|---|---|\n| **Web Vitals API wired up** | BFS literally cannot measure your app without this. App Bridge ships an API; you call `shopify.webVitals.onReport(...)` and forward to your monitoring |\n| **Error tracking** | Sentry, Datadog, Axiom, etc. Track every server error and unhandled client exception |\n| **APM** | Per-route latency p50/p95/p99 for every loader and action |\n| **Webhook delivery monitoring** | Track ACK time and failure rate; alert when retries spike |\n| **GraphQL throttle monitoring** | Alert when `extensions.cost.actualQueryCost` consistently exceeds 50% of bucket |\n| **Audit log retention** | At minimum 30 days of structured logs for support debugging |\n\n---\n\n## 4. Performance gates — exact numbers\n\nThese are the BFS gates as of May 2026. They are p75 (75th percentile of merchant launches) over a rolling 28-day window. You need a minimum sample size before BFS can measure you at all, so a brand-new app needs to run for ~30 days with real merchants before it's even eligible.\n\n### 4.1 Core Web Vitals (admin embedded)\n\n| Metric | Pass | Window | Min sample |\n|---|---|---|---|\n| LCP | ≤ 2.5s p75 | 28 days | 100 launches |\n| INP | ≤ 200ms p75 | 28 days | 100 launches |\n| CLS | ≤ 0.1 p75 | 28 days | 100 launches |\n\n**Important**: Google has been increasing the weight of real-user (CrUX) data over lab data in its own ranking. Shopify follows suit — Lighthouse scores on your raw URL are advisory, not the gate. The gate is what App Bridge's Web Vitals API reports from actual merchant sessions. If you haven't wired that up, you can't be measured, you can't pass, you can't get BFS.\n\n### 4.2 Server / API\n\n| Metric | Pass | Window |\n|---|---|---|\n| API p95 latency | < 500ms | 28 days |\n| API failure rate | < 0.1% | 28 days, min 1000 requests |\n\nBuild a cushion: target p95 ≤ 400ms and failure rate ≤ 0.05% so a single bad week doesn't sink you.\n\n### 4.3 Storefront impact (theme app extensions only)\n\n| Metric | Pass |\n|---|---|\n| Lighthouse performance delta | ≤ 10 points reduction with your extension installed |\n| Per-surface JS budget | ≤ 50KB gzipped (rule of thumb) |\n\nMeasure delta by running Lighthouse on a clean test theme, then installing your extension to the same theme and re-running. The difference must be < 10 points.\n\n### 4.4 Webhook latency\n\n| Metric | Pass |\n|---|---|\n| Webhook handler ACK | < 5s (Shopify retries at 5s) |\n| Target | < 2s with heavy work queued |\n\nThe way to pass: HMAC verify, persist the job to a queue, return 200. A worker handles the actual processing.\n\n---\n\n## 5. Accessibility gates — WCAG 2.1 AA\n\nPolaris components already meet WCAG 2.1 AA by default. So if you use Polaris everywhere and don't add custom UI, you get this for free. The places apps trip up:\n\n### 5.1 Where apps lose accessibility points\n\n| Failure | Fix |\n|---|---|\n| **Custom forms not using Polaris `<TextField>`, `<Select>`, etc.** | Replace with Polaris components |\n| **Missing `<label>` association on form inputs** | Polaris does this automatically; custom inputs need `htmlFor` + matching `id` |\n| **Color contrast below 4.5:1 for text** (or 3:1 for large text) | Use Polaris color tokens; never set custom hex colors for text |\n| **Focus not visible on keyboard tab** | Don't override Polaris focus rings; if you must, ensure visible outline at 2px+ |\n| **Modals trap focus poorly** | Use Polaris `<Modal>`, not a hand-rolled overlay; it manages focus correctly |\n| **Images missing `alt`** | Every `<img>` has `alt` (empty string for decorative is fine) |\n| **Icon-only buttons missing `accessibilityLabel`** | Polaris `<Button>` requires this; set it on every icon-only button |\n| **Dynamic content not announced** | Use `<Toast>` or `<Banner>` from Polaris; they handle ARIA live regions |\n| **Tables without proper `<th>` scope** | Use Polaris `<IndexTable>` or `<DataTable>` |\n| **Custom dropdowns without keyboard nav** | Use Polaris `<Popover>` or `<Combobox>` |\n| **Form errors not associated with fields** | Polaris `<TextField error=\"...\">` handles this; custom forms need `aria-describedby` |\n| **Skip links missing on long pages** | Add a \"Skip to main content\" link as the first focusable element |\n| **Heading order broken** (`<h1>` → `<h3>` skipping `<h2>`) | Audit with axe DevTools |\n\n### 5.2 Required keyboard interactions\n\nEvery interactive element must be reachable and operable by keyboard alone:\n\n- Tab — moves to next focusable element\n- Shift+Tab — previous\n- Enter — activates buttons and links\n- Space — activates buttons (not links), toggles checkboxes\n- Arrow keys — navigate within composite widgets (menus, tabs, listboxes)\n- Escape — closes modals, popovers, dropdowns\n\nTest this manually: unplug your mouse and try to do every primary workflow. If you can't, you don't pass.\n\n### 5.3 Screen reader testing\n\nTest with at least one screen reader before submission:\n\n- **VoiceOver** (macOS, free, built-in) — Cmd+F5 to enable\n- **NVDA** (Windows, free) — most-used in real-world WCAG audits\n- **JAWS** (Windows, paid) — enterprise reality\n\nWalk through onboarding + primary workflows. Every screen should be understandable from audio alone.\n\n### 5.4 Automated audit tools\n\nRun all three on every release:\n\n- **axe DevTools** (browser extension) — catches ~40% of issues\n- **Lighthouse** accessibility section\n- **WAVE** (browser extension) — visual annotations of issues\n\nThese tools combined catch maybe 50-60% of WCAG violations. The other 40% require manual testing.\n\n---\n\n## 6. UX / Polaris compliance\n\n### 6.1 The Polaris rule\n\nIf Polaris has a component for it, use Polaris's component. Don't build your own button, your own modal, your own form field. Reviewers explicitly look for this. Custom components that visually match Polaris are not enough — they're trying to verify that you've adopted Polaris's accessibility, dark mode, i18n, and responsive behavior.\n\n### 6.2 App Bridge 4.x requirement\n\nAll BFS apps must use the **latest version of App Bridge**. As of May 2026, that's App Bridge 4.x.\n\nMigration from earlier versions:\n\n- **App Bridge 1.x / 2.x** — fully deprecated; rewrite required\n- **App Bridge 3.x** — supported but not BFS-eligible; upgrade\n- **App Bridge 4.x** — the current target; loaded via CDN script\n\nHow to load App Bridge 4.x correctly:\n\n```html\n<head>\n <!-- This MUST come before your bundle -->\n <meta name=\"shopify-api-key\" content=\"YOUR_API_KEY\" />\n <script src=\"https://cdn.shopify.com/shopifycloud/app-bridge.js\"></script>\n <!-- Then your app bundle -->\n <script type=\"module\" src=\"/build/entry.js\"></script>\n</head>\n```\n\nThe script tag is non-negotiable. Bundling App Bridge into your app bundle (via npm) instead of loading it from Shopify's CDN will fail BFS — Shopify needs to control which version runs so they can ship security patches without your redeploy.\n\n### 6.3 Mobile responsive\n\nShopify's mobile admin app (iOS + Android) renders your embedded app in a webview. Your UI must work at:\n\n- 375px wide (iPhone SE / small Android) — minimum\n- 768px wide (iPad portrait)\n- 1024px+ wide (desktop)\n\nPolaris components handle this automatically. Custom layouts must use CSS Grid / Flexbox responsively.\n\n### 6.4 Embedded by default\n\nYour app must open inside the Shopify admin's iframe. Opening into a new browser tab, or requiring the merchant to leave the admin to use your app, is a BFS fail.\n\nExceptions:\n\n- Non-Shopify-related external integrations (e.g., connecting your Stripe account for billing) can open in a new tab\n- Long-running file downloads can navigate the parent\n\n---\n\n## 7. Integration depth — what counts\n\nThis section deserves its own treatment because \"lacks integration depth\" is the single most common qualitative rejection.\n\n### 7.1 What reviewers are checking\n\nThe reviewer asks: **\"Does this app feel like a native part of Shopify, or like a third-party tool with a Shopify OAuth wrapper?\"**\n\nSignals of \"native\":\n\n- Merchant can do most of their work without leaving the admin\n- The app shows up in contextual locations (Order detail, Product detail, etc.)\n- The app uses Shopify's native UI primitives (ResourcePicker, IndexTable, AppBridge actions) instead of building parallel versions\n- The app extends Shopify's surfaces (Functions, Theme App Extensions, Flow) where relevant\n\nSignals of \"wrapper\":\n\n- Merchant has to leave the admin or open external tabs frequently\n- The app builds its own product picker instead of using ResourcePicker\n- The app dumps merchants into a generic dashboard with no contextual entry points from Orders/Products/Customers\n- The app reads/writes via GraphQL but ships no extensions\n\n### 7.2 Integration surfaces ranked by impact\n\nFrom most to least impactful for \"integration depth\" feedback:\n\n1. **Admin Block extensions** — render your UI inside a native resource page. Strongest signal of native integration.\n2. **Admin Action extensions** — buttons in the admin that invoke your app. Strong signal.\n3. **Theme App Extensions (App Blocks)** — merchant adds your storefront UI via the theme editor. Required for storefront-touching apps.\n4. **Shopify Functions** — server-side logic in Shopify infra. Strong signal for checkout/discount/delivery apps.\n5. **ResourcePicker API** — using Shopify's native picker instead of your own. Cheap to implement, big signal.\n6. **Bulk action handling** — invoking your app on a multi-select of resources. Cheap to implement.\n7. **Metafields / Metaobjects** — store data on the Shopify side rather than only in your DB. Makes data visible in admin contexts.\n8. **Flow connectors** — exposing triggers and actions to Shopify Flow.\n9. **Web Pixels** — for any tracking/analytics apps.\n10. **Admin Link extensions** — sidebar nav entries. Baseline; everyone has these.\n\n**Target**: Implement at least 3 of these. Apps with 1-2 frequently get \"lacks integration depth.\" Apps with 5+ rarely do.\n\n### 7.3 GraphQL Admin API expectations\n\nUse the latest stable API version. Shopify versions are supported for a limited window. When this release was audited, the current stable version was `2026-07`; verify the version schedule before each release.\n\nBFS apps must use a non-deprecated version. Don't ship pinned to `2024-04` and expect to pass.\n\n### 7.4 REST Admin API is legacy\n\nShopify classified the REST Admin API as legacy on October 1, 2024, and new public apps have been required to use GraphQL exclusively since April 1, 2025. Shopify has not announced a blanket end-of-2026 shutdown for every REST resource. Existing integrations should track their API versions and migrate resource by resource.\n\n---\n\n## 8. GDPR webhooks — non-negotiable\n\nAll three must be implemented, working, HMAC-verified, and responsive within 30 seconds (Shopify's compliance webhook timeout is more lenient than regular webhooks but still finite).\n\n### 8.1 The three handlers\n\n#### `customers/data_request`\n\nSent when a merchant or customer requests all customer data your app holds for a specific customer.\n\nPayload includes:\n\n```json\n{\n \"shop_id\": 123,\n \"shop_domain\": \"example.myshopify.com\",\n \"orders_requested\": [123, 456],\n \"customer\": { \"id\": 789, \"email\": \"customer@example.com\", \"phone\": \"+1...\" },\n \"data_request\": { \"id\": 999 }\n}\n```\n\nYour handler: collect all data you store about this customer, return it in a format you can deliver to the merchant (email a JSON file, generate a download link, etc.). The webhook itself just needs to return 200; the data delivery happens out-of-band.\n\n#### `customers/redact`\n\nSent 10 days after a customer's deletion request (Shopify's mandatory waiting period).\n\nPayload:\n\n```json\n{\n \"shop_id\": 123,\n \"shop_domain\": \"example.myshopify.com\",\n \"customer\": { \"id\": 789, \"email\": \"customer@example.com\", \"phone\": \"+1...\" },\n \"orders_to_redact\": [123, 456]\n}\n```\n\nYour handler: delete or anonymize all data you hold for this customer. Cascade through related records. Log the deletion for compliance audit.\n\n#### `shop/redact`\n\nSent 48 hours after a merchant uninstalls your app.\n\nPayload:\n\n```json\n{\n \"shop_id\": 123,\n \"shop_domain\": \"example.myshopify.com\"\n}\n```\n\nYour handler: delete all data you hold for this shop. This is your `DROP TABLE WHERE shop = X` moment. After 48 hours of uninstall, you have no legitimate reason to retain merchant data.\n\n### 8.2 Implementation requirements\n\n- HMAC verify on the raw body, not parsed JSON\n- Return 200 within 30 seconds (push to queue if work is heavy)\n- Idempotent on `X-Shopify-Webhook-Id`\n- Logged for audit purposes\n- Tested with Shopify's webhook testing tool before submission\n\n### 8.3 Common compliance webhook fails\n\n- Returning 200 but doing nothing (Shopify spot-checks; will fail you)\n- HMAC verification skipped or wrong\n- Handler timeout (work too heavy, no queue)\n- Webhook URL on HTTP not HTTPS\n- Privacy policy doesn't mention the data retention timeline\n\n---\n\n## 9. Observability requirements\n\nBFS reviewers don't just check that your app passes today — they check that you can observe and respond when it doesn't. The expectation:\n\n### 9.1 Web Vitals API wired\n\n```ts\nimport { shopify } from \"@shopify/app-bridge-react\";\n\nshopify.webVitals.onReport((metric) => {\n fetch(\"/api/web-vitals\", {\n method: \"POST\",\n body: JSON.stringify(metric),\n });\n});\n```\n\nWithout this, your app appears in BFS dashboards with \"no data\" — you'll be told to wire it up before further review.\n\n### 9.2 Error tracking\n\n- Server errors → Sentry / Datadog / equivalent\n- Client errors → same\n- Alert thresholds defined (e.g., >0.1% error rate)\n- On-call rotation if you have a team\n\n### 9.3 APM\n\n- Per-route p50/p95/p99 latency\n- Alert when p95 crosses 80% of the BFS gate (e.g., 400ms when the gate is 500ms)\n\n### 9.4 Audit logs\n\n- Structured logs (JSON, not plain text)\n- 30+ day retention\n- Search by shop, merchant, webhook ID, request ID\n\n### 9.5 Status page\n\n- Public uptime over last 90 days\n- Incident history\n- Subscribe-for-updates link\n\n---\n\n## 10. Support requirements\n\n### 10.1 Response time SLA\n\nBFS reviewers expect you to publicly commit to **≤ 24 business hours** as the floor. Most successful BFS apps publish 12 business hours; the best publish 4 business hours.\n\nWhere to display:\n\n- App Store listing description\n- Your help center home page\n- In-app help link\n\n### 10.2 Help center\n\n- Public, no login required\n- Searchable\n- Covers setup + top 10 FAQ\n- Includes a contact form or email link prominently\n- Updated within 24h when features ship\n\nHosted options: Intercom, HelpScout, Zendesk Guide, Crisp, GitBook, or even a well-structured Notion page (with custom domain).\n\n### 10.3 In-app help\n\nContextual help links from inside the embedded app to the relevant docs. Example: a \"Help with this page\" link in every primary view that deep-links to the matching help article.\n\n### 10.4 Live channel (preferred, not required)\n\nLive chat or messaging shifts perception of support quality substantially. BFS reviewers note it. If you can't staff live chat, async via Crisp / Intercom / Drift with a clear \"we respond within X\" badge is fine.\n\n---\n\n## 11. Revenue share specifics (verify before relying)\n\nRe-stating the current state for clarity. **Verify against Shopify's revenue share docs before doing financial modeling — this policy has changed multiple times.**\n\n### 11.1 Current structure (post-Jan 2025 update)\n\n| Lifetime revenue | Revenue share | You keep |\n|---|---|---|\n| First $1M USD (lifetime gross app revenue earned since Jan 1, 2025) | 0% | 100% |\n| Above $1M lifetime | 15% | 85% |\n\n### 11.2 What changed\n\n- Prior policy: $1M was an **annual** exemption that reset each calendar year. A successful app could collect $1M every year and pay 0% on all of it.\n- Updated policy: the first $1M in qualifying lifetime gross app revenue earned since Jan 1, 2025 is subject to 0% revenue share; revenue above the threshold is subject to 15%.\n- This applies to **all** App Store apps — BFS or not. BFS does not currently grant an additional revenue share break on top of this.\n- A separate 2.9% processing fee, taxes, and possible regional fees still apply.\n- Developers above Shopify's stated annual app-earnings or company-revenue thresholds don't qualify for the $1M exemption.\n\n### 11.3 Partner-level aggregation\n\nRevenue from multiple apps and all associated developer accounts is aggregated. Shopify requires developers to disclose associated accounts, while payouts remain separate at the Partner account level.\n\n### 11.4 Strategic implications\n\n- Evaluate BFS using its documented highlight, badge, search-filter, promotional, and priority-review benefits\n- The lifetime $1M means high-MRR apps hit 15% faster than they used to; factor that into pricing\n- Never create or omit associated accounts to evade revenue aggregation; follow the Partner Program Agreement\n\n---\n\n## 12. Application / audit process\n\n### 12.1 Eligibility\n\nYou can't apply until Shopify's automated checks confirm you meet baseline. The Partner Dashboard shows which prerequisites you've passed and which you haven't. Apply only when everything green-lights.\n\nPrerequisites that get auto-checked:\n\n- Listing meets App Store guidelines\n- App Bridge 4.x detected on your embedded URL\n- GDPR webhooks present and returning 200 in test calls\n- API version current (non-deprecated)\n- Web Vitals data flowing\n- 100+ launches over 28 days\n- API p95 within threshold\n\n### 12.2 The application\n\nWhen eligible, the Partner Dashboard surfaces a \"Apply for Built for Shopify\" button. The application asks:\n\n- Confirm support SLA (with public-facing URL)\n- Confirm privacy policy URL\n- Confirm uninstall hygiene (data deletion within 48h of `shop/redact`)\n- Demonstrate integration surfaces used\n- Demo video of primary workflows (recommended)\n- Test store credentials (for the human reviewer to validate)\n\n### 12.3 Review timeline\n\nTypical: **2-4 weeks** for a human reviewer to walk through your app, test workflows, run accessibility checks, validate integration depth, and either approve or send feedback.\n\n### 12.4 Feedback cycle\n\nIf you don't pass, you get specific feedback. Common feedback categories:\n\n- \"Performance below threshold on X\" — re-measure after fixing, re-apply\n- \"Lacks integration depth\" — add 1-2 more integration surfaces\n- \"Accessibility issue: keyboard navigation broken in modal Z\" — fix and re-apply\n- \"Support SLA not publicly visible\" — publish and re-apply\n- \"Polaris compliance: custom UI in section X\" — refactor\n\nYou can re-apply once you've addressed feedback. There's no penalty for multiple cycles, but each cycle re-starts the 2-4 week review.\n\n### 12.5 Continuous evaluation\n\nOnce you have BFS, you don't keep it forever. Shopify re-evaluates continuously:\n\n- Performance regression for 2+ weeks → warning\n- Performance regression sustained → BFS revoked, you can re-earn it after fixing\n- Support complaints accumulating → review\n- Major guideline violation → BFS revoked\n\n---\n\n## 13. Top 15 BFS rejection reasons\n\nRanked by how often they appear in real rejection feedback. Fix all of these proactively before applying.\n\n| # | Rejection reason | Fix |\n|---|---|---|\n| 1 | **Web Vitals API not wired** | Implement `shopify.webVitals.onReport()` and send to monitoring; wait 28 days for data |\n| 2 | **App Bridge not 4.x or loaded incorrectly** | Load from CDN in `<head>` before bundle; remove npm-bundled App Bridge |\n| 3 | **Performance below threshold** (LCP, INP, CLS, or API p95) | See app-performance skill; address cold starts, bundle size, GraphQL serial awaits, N+1 |\n| 4 | **GDPR webhooks missing or non-functional** | All three implemented, HMAC-verified, return 200 within 30s |\n| 5 | **Lacks integration depth** (admin-only iframe, no extensions) | Add Admin Block + Action + ResourcePicker, minimum 3 surfaces total |\n| 6 | **OAuth scopes excessive** | Audit; remove every scope you don't use in the last 30 days of logs |\n| 7 | **Accessibility failures** (custom UI breaks keyboard nav or screen readers) | Replace custom UI with Polaris components; audit with axe DevTools |\n| 8 | **Theme injection without cleanup** | Use Theme App Extensions (App Blocks); they're auto-removed on uninstall |\n| 9 | **Support SLA not publicly committed** | Publish 24-hour SLA on listing + help center + in-app |\n| 10 | **Privacy policy hidden or missing GDPR mention** | Public URL, explicit GDPR + CCPA + retention period |\n| 11 | **Storefront performance impact > 10 Lighthouse points** | Audit theme app extension; trim JS, lazy-load, async-load |\n| 12 | **API version deprecated** | Bump to the latest supported stable version; remove pinned unsupported versions |\n| 13 | **Onboarding > 2 minutes to first value** | Cut steps; pre-fill defaults; show immediate value (sample data, preview) |\n| 14 | **Embedded app opens in new tab** | Render inside admin iframe by default; only external for things like Stripe Connect |\n| 15 | **Help docs missing or stale** | Build help center; cover top 10 FAQ; link in-app contextually |\n\n---\n\n## 14. Pre-audit self-check (50 items)\n\nRun this before clicking the Apply button. Every item must be checked. If any are unchecked, fix first.\n\n### Performance (15)\n\n- [ ] App Bridge Web Vitals API wired and sending to monitoring\n- [ ] 100+ launches recorded over 28-day window\n- [ ] LCP p75 ≤ 2.5s in Web Vitals dashboard\n- [ ] INP p75 ≤ 200ms in Web Vitals dashboard\n- [ ] CLS p75 ≤ 0.1 in Web Vitals dashboard\n- [ ] API p95 latency ≤ 400ms (cushion below 500ms gate)\n- [ ] API failure rate ≤ 0.05% (cushion below 0.1% gate)\n- [ ] Initial route bundle ≤ 350KB gzipped\n- [ ] All internal `<Link>` use `prefetch=\"intent\"`\n- [ ] Loaders use `defer` for non-critical data\n- [ ] Cache-Control headers on stable loader responses\n- [ ] Server runs on always-on infrastructure (no scale-to-zero)\n- [ ] DB connection pooling enabled (Hyperdrive, PgBouncer, or Accelerate)\n- [ ] No N+1 in any loader (verified via Prisma query logs)\n- [ ] Storefront extensions ≤ 50KB gzipped per surface and ≤ 10 Lighthouse point delta\n\n### Design / Polaris (10)\n\n- [ ] App Bridge 4.x loaded from CDN in `<head>` before bundle\n- [ ] Polaris CSS imported exactly once at root\n- [ ] All admin UI uses Polaris components, not custom equivalents\n- [ ] `<AppProvider>` and `<Frame>` mounted once at root\n- [ ] Dark mode works (or doesn't break) across all views\n- [ ] Internationalization wired (Polaris i18n provider)\n- [ ] Mobile responsive at 375px, 768px, 1024px+\n- [ ] Skeletons match final dimensions (no CLS on data load)\n- [ ] Empty states present on every list / table / dashboard\n- [ ] Error states present and human-readable on every async operation\n\n### Accessibility (8)\n\n- [ ] All form inputs use Polaris components (label association handled)\n- [ ] Color contrast ≥ 4.5:1 for text (Polaris tokens guarantee this)\n- [ ] Keyboard navigation works for all primary workflows (test mouse-unplugged)\n- [ ] Focus visible on every interactive element\n- [ ] Icon-only buttons have `accessibilityLabel`\n- [ ] Screen reader test passed (VoiceOver or NVDA) on onboarding + primary workflow\n- [ ] axe DevTools shows zero violations on every route\n- [ ] Heading order valid (no skipped levels)\n\n### Integration depth (7)\n\n- [ ] At least 3 integration surfaces used (Admin Action, Admin Block, Theme App Extension, Functions, ResourcePicker, etc.)\n- [ ] ResourcePicker used for any product/collection/variant selection (not custom picker)\n- [ ] Bulk actions supported if app operates on lists of resources\n- [ ] Theme App Extensions used if app touches storefront (no Liquid injection)\n- [ ] Shopify Functions used if app modifies discounts/delivery/payments\n- [ ] Metafields/Metaobjects used for merchant-visible data\n- [ ] Current supported stable API version — no deprecated versions\n\n### Compliance (5)\n\n- [ ] All three GDPR webhooks implemented: `customers/data_request`, `customers/redact`, `shop/redact`\n- [ ] All webhook handlers HMAC-verified on raw body\n- [ ] Privacy policy public, mentions GDPR + CCPA + retention period\n- [ ] Terms of Service public, includes app limitations\n- [ ] OAuth scopes minimal — every requested scope is used\n\n### Support + observability (5)\n\n- [ ] Support email on own domain, functional, monitored\n- [ ] Public help center with top 10 FAQ + search\n- [ ] Response SLA publicly committed (≤ 24 business hours)\n- [ ] Sentry / Datadog / equivalent tracking all errors\n- [ ] Status page public (uptime + incident history)\n\nIf 50/50 checked, you're ready to apply. If any unchecked, fix first — re-applying is cheap, but the 28-day measurement window is expensive.\n\n---\n\n## 15. Decision tree — am I ready to apply\n\n```\nShould I apply for Built for Shopify?\n│\n├── Has the app been live with real merchants for 30+ days?\n│ ├── No → Wait. You need 28 days of Web Vitals + API data.\n│ │ Even if every fix is in place, Shopify can't measure you yet.\n│ └── Yes → Continue\n│\n├── Is App Bridge Web Vitals API wired and reporting data?\n│ ├── No → Wire it up first. Without data, you're invisible to BFS.\n│ │ Then wait 28 days for data to accumulate.\n│ └── Yes → Continue\n│\n├── Are all three Web Vitals (LCP, INP, CLS) within threshold in the Partner Dashboard?\n│ ├── No → Run app-performance skill. Fix what's failing.\n│ │ Re-measure after 14-28 days of the fix being live.\n│ └── Yes → Continue\n│\n├── Is API p95 ≤ 400ms and failure rate ≤ 0.05% over the last 28 days?\n│ ├── No → Fix server perf or stability. See app-performance skill.\n│ │ Re-measure after fixes.\n│ └── Yes → Continue\n│\n├── Are all three GDPR webhooks implemented, HMAC-verified, returning 200?\n│ ├── No → Implement them. Non-negotiable.\n│ └── Yes → Continue\n│\n├── Are at least 3 integration surfaces used (Admin Action, Block, Functions, etc.)?\n│ ├── No → Add more. \"Lacks integration depth\" is the #5 rejection reason.\n│ │ Pick the 1-2 cheapest surfaces for your app type and ship them.\n│ └── Yes → Continue\n│\n├── Does the app pass automated accessibility audits (axe DevTools) on every route?\n│ ├── No → Fix violations. Most are 5-minute Polaris component swaps.\n│ └── Yes → Continue\n│\n├── Have you done a manual keyboard-only walk-through of onboarding + primary workflow?\n│ ├── No → Do it. Today. It will reveal issues automated tools miss.\n│ └── Yes → Continue\n│\n├── Is your support SLA (≤ 24 business hours) publicly committed in 2+ places?\n│ ├── No → Publish on listing, help center, in-app help.\n│ └── Yes → Continue\n│\n├── Have you tested uninstall hygiene — does shop/redact actually delete all data within 48h?\n│ ├── No → Test it. Install, populate data, uninstall, wait 48h, verify deletion.\n│ └── Yes → Continue\n│\n├── Is the API version current and supported?\n│ ├── No → Upgrade. Old versions are an auto-reject.\n│ └── Yes → Continue\n│\n├── Have you walked through the 50-item self-check and checked every box?\n│ ├── No → Walk through it. Don't apply with unchecked items.\n│ └── Yes → Apply.\n│\n└── APPLY\n └── Expect 2-4 weeks. If approved, badge appears immediately.\n If rejected, you'll get specific feedback. Fix, re-apply.\n Each cycle is 2-4 weeks. Don't argue with feedback.\n```\n\n---\n\n## 16. After approval — maintenance\n\nGetting BFS isn't a one-time event. Keep it by:\n\n- **Watching Web Vitals weekly** in the Partner Dashboard. Two-week regressions trigger warnings.\n- **Watching API p95 daily** in your APM. Alert when it crosses 400ms.\n- **Auditing bundle size in CI**. Don't let a regression ship.\n- **Monitoring support response time**. If it slips past 24h, hire or automate.\n- **Re-running accessibility audits** on every release. Polaris updates can introduce regressions in your custom layers.\n- **Reviewing API version annually**. Bump to the current version before yours deprecates.\n- **Re-validating GDPR webhooks quarterly**. Send a test request, verify response.\n\nBFS is a flywheel — apps that maintain it get more visibility, more installs, better reviews, which compounds. Apps that lose it usually do so quietly (a perf regression, a slow support quarter) and never notice until ranking drops 60%.\n\n---\n\n## Closing principle\n\nBuilt for Shopify isn't a marketing badge. It's a contract: you commit to a quality bar, Shopify points merchants at you in exchange. The hard part isn't passing the audit once — it's continuing to pass it while you ship features, grow merchants, and the gates inch tighter each year.\n\nBuild the foundation right (Polaris everywhere, App Bridge 4.x, performance budget in CI, GDPR webhooks day one, observability before launch) and BFS is a 30-day formality. Try to retrofit it later and you'll spend three months refactoring around tech debt that should never have shipped.\n\nThe earliest your app can be ready for BFS is **day 1 of design**. The latest it can be ready is **never**, because the bar moves.\n\nPick day 1.\n\nSources:\n- [Built for Shopify requirements (Shopify)](https://shopify.dev/docs/apps/launch/built-for-shopify/requirements)\n- [About Built for Shopify (Shopify)](https://shopify.dev/docs/apps/launch/built-for-shopify)\n- [Revenue share for Shopify App Store developers (Shopify)](https://shopify.dev/docs/apps/launch/distribution/revenue-share)\n- [Update to Shopify's app developer revenue share (Shopify changelog)](https://shopify.dev/changelog/update-to-shopifys-app-developer-revenue-share)\n- [Latest version of App Bridge required for Built for Shopify (Shopify changelog)](https://shopify.dev/changelog/latest-version-of-app-bridge-required-for-built-for-shopify)\n- [Polaris Accessibility (Shopify)](https://polaris-react.shopify.com/foundations/accessibility)\n- [Privacy law compliance (Shopify)](https://shopify.dev/docs/apps/build/compliance/privacy-law-compliance)\n- [Common app rejections (Shopify)](https://shopify.dev/docs/apps/store/common-rejections)\n- [App Bridge documentation (Shopify)](https://shopify.dev/docs/api/app-bridge-library)\n"
}SHA-256 of public snapshot: 4f4ca85ac5b959a2b559a80407a7520c8c6a5168d091c10e2687ece9431fa37f