Architectural Bug: Shopify Mobile App triggers premature products/create webhooks via background initialization

Issue Description:
When a merchant opens the “Add New Product” screen on the Shopify Mobile App, the client application immediately triggers a background database INSERT to generate a product_id (presumably to handle immediate media/image uploads).

Because Shopify’s core database default for the status enum column is active, this background insertion immediately publishes a blank product skeleton to the database. This causes the platform to fire a products/create webhook payload to third-party developer apps containing null/empty data with an active status state.

Impact:
This behavior creates billions of unnecessary cloud execution tasks globally. Third-party apps are forced to ingest, parse, and handle ghost payloads for products that are not actually created yet, resulting in massive wasted cloud computing costs and data pollution in external ERPs and inventory systems.

Proposed Technical Solution (Non-Breaking):
Introduce an internal state flag or origin identifier field (e.g., is_initialized_skeleton: true) to the schema when the mobile app initiates this background record. The webhook event dispatcher should evaluate this flag and suppress the products/create event until the merchant explicitly hits the “Save” button in the mobile UI, at which point the flag is updated and the webhook fires cleanly with complete data.

Please escalate this to the Core Platform / Webhooks engineering team for review.


Hi @TwoDots! You’re right that a products/create fires as soon as you open the Add product screen in the mobile app, before you tap Save. That part is expected. The app persists a real product record up front so media and variants have something to attach to, so the topic firing is correct rather than a side effect.

I reproduced it on a dev store and the payload is a bit different from what you described though. The product is created with status: "draft" and published_at: null, not active, and the body is fully populated (real handle, a Default Title variant at 0.00, options, inventory item) rather than null or empty. Because it’s a draft it isn’t published to any sales channel, so it won’t surface on a storefront. I also backed out of the screen without saving and a products/delete fired for that record, so abandoned drafts don’t stick around as ghosts.

If you’re fanning these events out to marketplaces, an ERP, or other downstream systems, the create then delete churn on abandoned drafts is the real pain, so the goal is to never let the skeletons reach your pipeline in the first place. The cleanest way to do that is delivery filtering. Add filter = "status:active" to the subscription (available from API version 2024-07) and Shopify suppresses the draft deliveries server side, so you only get the webhook once the product is actually active. If you’d rather handle it in your consumer, subscribe to products/update and react to the status transition from draft to active, treating the initial create as provisional and honoring products/delete for anything you staged. Either approach gives you a clean “this product is now live, go sync it” trigger without needing a skeleton flag.

If you do hit a case where a product comes through with status: "active" and a genuinely empty payload before save, grab the product ID and the raw payload and I’ll dig into that specific one.