Spend on SKUs that can’t convert, pause the ad, hold the budget, recover the wasted spend within minutes.
At a glance
Real-time alert listing active paid-ads (Google Shopping, Meta Catalogue, TikTok Shopping) that point at Adobe Commerce SKUs currently out of stock. Every dollar of ad spend on a zero-stock SKU is wasted, the click can’t convert. Pause the ad, redirect the budget, recover within minutes.
| What it counts | Cross-reference: any active ad asset (Google Ads product feed, Meta product catalogue, TikTok shopping feed) whose sku matches an Adobe Commerce product where the calculated salable_qty is zero or stock_status = 0 (Out of Stock). Returns the list of offending ads plus the rolling 7-day spend on each. |
| API field | Adobe side: product stock_status and salable_qty from Inventory MSI (GET /rest/V1/inventory/source-items and the getInventoryStatus query). Cross-referenced against ad-platform feeds. |
| VAT / tax treatment | Spend figures are pulled from each ad platform in their reporting currency; ad spend is typically exclusive of VAT (tax invoiced separately by Google/Meta). The Adobe stock check is tax-irrelevant. |
| Shipping inclusion | n/a, this card concerns ad spend and SKU stock, not transactional revenue. |
| Discounts | n/a for the headline. The “potential lost revenue” estimate (sub-card) uses grand_total average per SKU which is post-discount. |
| Credit Memo refund treatment | n/a for the alert. The spend figure is gross of any ad-platform refunds (which are rare). |
state machine inclusion | n/a, this card doesn’t sum order revenue. The companion “potential lost revenue” estimate (in the breakdown) does use state-agnostic order data. |
pending_payment quirk | Indirect impact: if a SKU has 50 orders in pending_payment and Adobe Commerce hasn’t decremented stock for them (because they never paid), the SKU may still appear “in stock” here even though buyers are queueing up to claim the inventory. The card uses salable_qty (which DOES factor in reserved stock for pending orders) to avoid this trap. If your Adobe Commerce installation is older than 2.3 (no MSI), this protection isn’t available, fall back to physical qty. |
Multi-currency grand_total vs base_grand_total | Spend on each ad platform is in that platform’s reporting currency. The card displays per-platform spend without FX conversion; the rolled-up total at the top is in the merchant’s primary currency, FX-converted at indicative daily rates. Treat with mild caution. |
Store View scope (store_id) | All Store Views considered. A SKU out of stock at Source Stock A (US warehouse) but in stock at Source Stock B (UK warehouse) is not flagged here, the card uses Adobe’s MSI cross-source salable_qty which sums available across all stock sources visible to the customer. For region-locked merchants (UK warehouse only ships UK), per-Store-View MSI configuration matters, set up a per-region variant if your stock-sources are region-restricted. |
| Time window | RT (real-time). Stock decrements and ad-feed sync usually within 5-15 minutes. |
| Alert trigger | any active ad on Adobe SKU with stock_level=0, fires immediately when a SKU’s salable_qty hits zero while at least one matching ad is still active. |
| Roles | owner, marketing, finance |
Calculation
Calculated automatically from your Adobe Commerce data. See the At a glance summary above for what the metric tracks and the worked example below for a typical reading.Worked example
A homewares brand on Adobe Commerce 2.4.6 with US, UK, and B2B Store Views. Snapshot taken Tuesday 12 Apr 26, 14:00 GMT.| SKU | Adobe salable_qty | Active ads | 7-day spend | Lost-conversion estimate |
|---|---|---|---|---|
LMP-COPPER-12 (Copper Pendant Lamp) | 0 | Google Shopping (US, UK), Meta Catalogue (US) | $1,420 | ~682 AOV) |
RUG-MOROCCAN-200 (Moroccan Rug 200x290) | 0 | Google Shopping (UK), TikTok Shopping (UK) | £680 | ~£5,400 (8 typical orders/wk × £675 AOV) |
CHAIR-HARRIS-OAK (Harris Oak Chair) | 0 (back-orderable Y) | Meta Catalogue (US, UK) | $920 | n/a, allow_backorders=1 so not waste |
LMP-COPPER-9 (Copper Pendant Lamp Small) | 0 | Google Shopping (US) | $310 | ~600 AOV) |
| Active waste (this card) | 6 ads on 3 SKUs | ~$2,650 / wk | ~$15,400 / wk potential lost orders |
CHAIR-HARRIS-OAK): Adobe Commerce has allow_backorders = 1 on this product, so the SKU is technically salable_qty = 0 but the customer can still place an order (it just ships when restocked). The card detects this from the backorders field on the product entity and excludes it from the alert. The merchant doesn’t need to pause those ads; they’re still converting.
What this is telling the merchant:
- 6 ads across 3 truly-out-of-stock SKUs are burning ~$2,650/week. Pause them and the budget redirects to in-stock SKUs immediately.
- The Copper Pendant Lamp (both sizes) is the biggest waste, $1,730/week combined. This is also a clue: if both size variants are out, the supplier may have stopped shipping. Pair with Catalogue Drift to surface other supplier-stalled SKUs.
- Adobe Commerce’s MSI multi-source inventory matters here.
LMP-COPPER-12is genuinely zero across both Source Stock US and Source Stock UK; the card is right to flag. If only the US source were out and UK source had stock, we’d flag it for US-targeted ads only. - The lost-conversion estimate uses the SKU’s typical 7-day order rate × its average
grand_totalcontribution. It’s an order-of-magnitude estimate, not exact. For the Moroccan Rug: 8 orders/week × £675 AOV = ~£5,400 of weekly revenue at risk if the SKU stays out. - B2B portal SKUs aren’t flagged here because B2B doesn’t run consumer paid-ads. The cross-channel feed for B2B is a separate concern, and the supplier-stall pattern usually shows up first on consumer ads.
Sibling cards merchants should reference together
This card surfaces a moment-of-action; pair with these for context and follow-up:| Card | Why pair it with Active Ads on OOS SKUs |
|---|---|
| Catalogue Drift | Flags SKUs where the Adobe Commerce catalogue and the ad-platform feed diverge (price, image, status). Frequent companion: an OOS SKU still in the feed is one type of drift. |
| Top Refunded SKUs | If a SKU is OOS because of mass returns (defective batch), pausing the ad isn’t enough, you also need to halt new orders. Cross-check refund spike against OOS list. |
| Order State Distribution | If a SKU’s pending_payment orders haven’t decremented stock yet, the card may underflag. Check pending_payment order volume by SKU. |
| Total Revenue | The denominator-of-context. 50k/month merchant; trivial on a $5m/month merchant. |
| Revenue at Risk from Incident | The general revenue-at-risk roll-up; this card’s lost-conversion estimate feeds into it. |
google_ads.google_ads_spend | The total Google Ads spend over the same window. Use to compute waste-as-percentage-of-spend; >3% is concerning, >10% is broken. |
facebook.facebook_ads_spend | Meta-side spend equivalent. |
google_search_console.gsc_oos_impressions | Organic impressions on OOS pages. The free side of the same problem. |
Reconciling against the vendor’s own dashboard
Where to look in Adobe Commerce Admin: The Adobe Commerce Admin views to verify the stock side of the alert:Catalog > Products with the Quantity filter set to ”≤ 0” and Visibility set to “Catalog, Search”. The product list should show every SKU at zero stock that’s also visible to customers, the candidates for this card.For the multi-source inventory view (Adobe Commerce 2.3+):
Stores > Inventory > Sources to confirm the source-stock configuration, then Catalog > Products edit > Sources tab on a flagged SKU shows source-by-source quantity. This is what salable_qty aggregates.
For ad-platform synchronisation:
Marketing > Communications doesn’t cover ad platforms (it’s email/transactional). Check your Google Ads Content API integration (often via a third-party connector module like Magento 2 Google Shopping by Magenest) for feed-sync timestamps.Other Adobe Commerce Admin views that look relevant but aren’t:
- Reports > Products > Most Viewed: traffic, not stock.
- Reports > Products > Bestsellers: sales velocity, not stock.
- Catalog > Categories: category hierarchy, no stock signal.
- Stores > Configuration > Catalog > Inventory: backorder/stock-display rules, not live stock levels.
| Reason | Direction of divergence |
|---|---|
| Time-zone / sync lag. Stock decrements typically index within 1-5 minutes; ad-platform feeds sync hourly to daily. The card uses live MSI data on the Adobe side and the most recent feed-sync on the ad side. A SKU may have just sold its last unit but the Google Shopping feed still says “in stock” for another 30 minutes. | Card flags new OOS faster than ad platform’s own product status |
pending_payment reservations. Adobe MSI reserves stock for orders in pending_payment (i.e. salable_qty is decremented even if no money taken yet). If the gateway eventually fails and the order moves to canceled, MSI returns the stock. During the limbo, the card may flag a SKU as OOS even though the physical inventory exists. This is the right behaviour, ads should still pause. | Vortex IQ flags slightly earlier than physical-stock view |
Backorders allowed. Products with backorders = 1 (Allow Qty Below 0) are NOT flagged here; the card excludes them. The Adobe stock view shows them as zero qty all the same. | Vortex IQ shows fewer flags than raw-zero-qty Adobe filter |
Source stock vs aggregate. MSI multi-source merchants see per-source stock in admin; this card aggregates salable_qty across all stock-sources visible at the storefront. A SKU with US source 0 and UK source 5 may show as “available” here but flag a US-only ad campaign incorrectly, set up per-Store-View variants for region-locked merchants. | Region-locked merchants need per-region cards |
Custom inventory modules. Some Magento 2 installations replace MSI with a third-party inventory module (e.g. for ERP-fed real-time stock). The card uses the standard getInventoryStatus query, custom modules may bypass it. | Custom-inventory merchants may need a manifest tweak |
| Pair | Expected relationship | What divergence tells you |
|---|---|---|
Adobe salable_qty = 0 on a SKU vs the SKU’s status in google_ads.google_ads_spend | Card flags = ad still active and spending | Confirmed waste, pause it. |
Adobe salable_qty = 0 vs Google Merchant Center product status | Google should show “approved” with “in stock” | If Google is still serving but Adobe is OOS, the feed sync is lagging. Force a feed re-push. |
facebook.facebook_ads_spend Catalogue Sales campaign on the SKU vs Adobe stock | Should align within 1-4 hours | Meta refreshes catalogues every 1-4 hours; treat lag as routine, not a fault. |
google_analytics.ga_revenue_by_product | OOS SKUs should have falling traffic and falling conversions | If GA4 traffic is steady but conversions cratered on a SKU, that’s a stock problem. |
Known limitations / merchant FAQs
The card flags ads as wasted but my ad-platform reports show the SKU as in stock, who’s right? The card is right about Adobe Commerce stock. The ad platform’s product status is whatever it last received from your feed sync, which can lag 30 minutes to several hours. The customer who clicks the ad will land on a product page that says “out of stock” (because the storefront uses livesalable_qty) and bounce. The ad is wasted regardless of what the ad platform thinks. Pause and force a feed re-push.
What’s the difference between state and status and does it affect this card?
This card uses product stock status (stock_status, salable_qty), not order state/status. Order lifecycle is irrelevant to whether the SKU has stock. The indirect link is via pending_payment: orders in pending_payment reserve stock in MSI even though no money was taken, which can flag a SKU as OOS during the limbo. That behaviour is correct, ads should still pause because the customer can’t add the reserved units to a new cart anyway.
Why does my multi-source Adobe Commerce setup not show source-by-source ad waste?
The card aggregates salable_qty across all stock-sources visible to the storefront. A SKU in stock at the UK warehouse but out at the US warehouse may waste US-only ad spend even though the headline salable_qty is positive. Set up a per-region card variant that filters store_id and only checks the matching stock-source. Standard MSI configurations with country-restricted source-stocks need this customisation.
Why is the spend figure ex-VAT?
Ad platforms report spend ex-VAT because VAT is invoiced separately to the merchant. Both Google and Meta do this. Comparing to Adobe Commerce grand_total (typically VAT-inclusive on UK/EU stores) introduces a slight bias when computing waste-as-percentage-of-revenue, ad spend is undercounted by the VAT delta. For a like-for-like view, gross up ad spend by your VAT rate before comparing.
The card flags a SKU but I don’t run ads on it, false positive?
Possible causes: (1) the SKU is in your Google Merchant Center catalogue feed even though no campaign is actively bidding on it, Google Shopping can still serve free organic placements that count as “active”; (2) a campaign is set to bid on all products in a feed via Performance Max or a smart-shopping campaign, even ones you didn’t manually add; (3) a third-party feed-management tool (Channable, GoDataFeed) is auto-creating ads at a more granular level than your console shows.
My multi-store Adobe Commerce, can I see per-Store-View ad waste?
Not on this card directly. Set up per-region card variants, each filtered to one Store View’s stock-source and one ad-platform geo target. Particularly important for region-locked merchants (UK warehouse only ships UK).
Why is the lost-conversion estimate fuzzy?
It’s an order-of-magnitude figure based on the SKU’s typical 7-day order rate × its average grand_total contribution. It can’t account for: substitution (customers buying a different SKU), seasonality (the SKU’s sales rate is changing), or paid-vs-organic mix (some of those orders would have happened without the ad). Treat as “is this a 20,000/wk problem”, not as a precise revenue figure.
The Adobe Commerce admin shows the SKU as qty = 5 but the card flags it as OOS, why?
Two possibilities: (1) qty is physical-source stock; salable_qty is what’s available to sell after reservations for pending_payment orders, B2B holds, and pre-sales. The card uses salable_qty. If physical qty is 5 but 5 are reserved for pending orders, salable is 0 and the card is right. (2) stock_status = 0 (Out of Stock) was manually set in the product edit screen, even with qty > 0 the SKU is hidden from sale. Check both fields in admin.
Why doesn’t Google Analytics agree this is wasted spend?
GA4 attributes the revenue of converting clicks; clicks on OOS SKUs simply don’t convert, so they show as zero-revenue paid traffic. GA4 doesn’t have a concept of “wasted spend”; it shows the spend in the channel report and the (zero) revenue separately. The card synthesises the contrast across data sources that don’t talk to each other. Use this card as the action prompt; use GA4 for after-the-fact attribution.
Should I delete the OOS SKU from my catalogue feed?
Usually no. Pause the bidding (or remove the product from the active campaign), but keep the product live in the feed so when stock returns the ad-platform’s quality score and ranking history are preserved. Deleting and re-adding usually costs you 2-4 weeks of ad-platform learning. For a permanently discontinued SKU, full removal is right.