Dead-stock SKUs with active paid-ad spend behind them. Pause-immediately list.
At a glance
Alert table: SKUs that meet BOTH criteria, dead-stock in Sage Intacct (zero sales velocity for 90+ days, ageing inventory) AND active ad spend on the same SKU in Google Ads, Amazon Ads, or Meta Ads. The merchant is paying to drive traffic to product pages whose products will eventually be written off. Each row is the Item + ad spend in the period + sales in the period (typically zero) + ageing inventory dollars + the owning Class dimension (Wholesale vs Retail D2C, since Retail D2C is typically the channel running ads). Pause-immediately list. The kill-shot pitch: “you are paying $4,200 / month to advertise products you have not sold in 6 months and will eventually scrap”. Cross-channel only because no single platform sees both sides.
| What it counts | Item WHERE intacct.item.sales_last_90d = 0 AND intacct.item.qty_on_hand > 0 AND ad_platform.spend_30d > $500 (configurable thresholds). Each row = Item + 30D spend + 90D sales (typically zero) + on-hand value + days-since-last-sale + owning Class dimension. |
| Tax treatment | n/a, this is a sales-velocity-vs-spend comparison. Ad spend is gross of any platform fees (Google’s reported spend includes the auction cost only). |
| Shipping | n/a. |
| Discounts | Sales velocity uses post-discount revenue at the Item level, sourced from Intacct’s GL Detail filtered to the Item dimension on revenue accounts. |
| Refunds | Refunded sales are excluded from the “did this Item sell?” check. A Credit Memo against an old sale does not constitute “this Item sold”. |
| Cancelled / voided orders | Excluded. |
| Currency | Per-Item Item value in transaction currency; ad spend converted to consolidation currency at transaction-date FX. |
| Channels / sources | Sage Intacct sales velocity (across all channels routed through Intacct: Wholesale Class, Retail D2C Class, Marketplace Class) vs ad spend across Google Ads, Amazon Ads, Meta Ads (configurable). The ad-platform-to-Item join is via product_id / landing_page_url mapped to the Intacct Item. |
| Owning Intacct dimension | Class (Retail D2C is the typical ad-spend Class), Item (the SKU itself), Location (multi-warehouse aged stock), Department (Department-level merchandising ownership). |
| Sales velocity threshold | 90D zero sales is the default “dead-stock” definition. Configurable to 60D or 180D depending on industry seasonality. |
| Spend threshold | Default 100); higher for large ($2,000). |
| Time window | 30D for ad spend; 90D for sales velocity. |
| Alert trigger | any SKU spending >$500 AND zero sales. |
| Roles | owner, marketing, finance |
Calculation
Calculated automatically from your Sage 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 US D2C apparel brand on Sage Intacct (single-entity, growing into Multi-Entity Console next quarter), Shopify Plus on the front-end with a small BigCommerce B2B Edition side channel for retailer partners. Google Ads + Amazon Ads + Meta Ads connected via Vortex IQ. Annual revenue ~$42M. The Class dimension separates Wholesale from Retail D2C; Retail D2C runs the paid ad budget. Reporting period 02 Apr 26 to 01 May 26. Headline: 14 dead-stock Items receiving 128,400. All 14 Items tagged to the Retail D2C Class. Top 6 dead-stock-with-ad-spend cases:| Item | Description | Class | Ad spend 30D | Sales 90D | Days since last sale | On-hand value | Last sale date | Action |
|---|---|---|---|---|---|---|---|---|
| APPAR-DRES-NVY-S | Navy dress, size S | Retail D2C | $1,140 | $0 | 142 | $18,400 | 14 Dec 25 | Pause Google + Meta |
| APPAR-COAT-WIN-XL | Winter coat XL | Retail D2C | $820 | $0 | 168 | $42,800 | 18 Nov 25 | Pause + clearance |
| APPAR-BAG-VEL-PNK | Velvet bag pink | Retail D2C | $620 | $0 | 134 | $8,200 | 22 Dec 25 | Pause Google |
| APPAR-SCRF-WOL-CHK | Wool check scarf | Retail D2C | $580 | $0 | 122 | $4,200 | 03 Jan 26 | Pause |
| APPAR-SHIR-PRP-M | Purple shirt, size M | Retail D2C | $540 | $0 | 156 | $6,200 | 27 Nov 25 | Pause Meta |
| APPAR-JACK-LTH-RED | Red leather jacket | Retail D2C | $520 | $0 | 178 | $14,800 | 08 Nov 25 | Pause + clearance |
- The 14 Items are seasonal cleanouts that nobody paused. The winter coat in size XL (sold its last unit on 18 Nov 25) is no longer winter-relevant. Google Shopping campaigns are still serving the product because the campaign’s product feed includes it; Meta is still serving lookalike audiences against the original launch creative. Both platforms charge for impressions and clicks regardless of whether the product converts. The Sage Intacct Class dimension on every row confirms these are all Retail D2C Items, which is the only Class running paid ads (the Wholesale Class is sold through B2B reps and trade-show events, not Google Shopping); the Class tag rules out the false positive of a Wholesale-only SKU appearing on this card by mistake.
- Cumulative annualised waste: 58,080 / year of advertising spend on products that won’t sell at full price. Plus the ageing-inventory carry cost (capital tied up + warehousing) on 23,000 to $30,000 of hidden cost.
- Action playbook:
- Pause the Google Shopping product-level bids on all 14 Items. Estimated ad-spend savings: $4,840 / month immediately.
- Pause Amazon Ads on the same 14 Items. Each platform’s ad spend is independent; pausing on Google does not pause on Amazon.
- Move the 14 Items to a clearance section on the website, tagged to a clearance Class in Sage Intacct. Reduce price 30 to 50%. Cross-reference Inventory Aging to see how aged each is; Items aged >180 days warrant 50%+ discount.
- Long-term: implement an automation rule. “If an Intacct Item has zero sales in 90 days AND active ad spend, auto-pause ads on that Item and trigger merchandising review.” The rule reads from Sage Intacct’s Item dimension (sales velocity by Item is one query against GL Detail filtered to the Item) and writes to the ad platforms.
- Why this is the kill shot:
- The cross-channel join is what makes this card possible. Sage Intacct knows sales velocity dimensionally (it owns the GL Detail with Item-tagged revenue lines). The ad platforms know spend (they own their billing). Neither knows the other side. The merchant’s marketing team optimises ROAS at the campaign level (where the headline is healthy because it is averaged across active Items); the dead-stock Items do not get individual attention.
- For most merchants, this card surfaces 5 to 25% of their ad spend as wasted-on-deadstock. At a 10K to $50K/month of recoverable budget. Annualised, that is the cost of the entire Vortex IQ subscription plus a meaningful margin contribution back to the bottom line.
- CEO conversation:
- The pitch: “You are paying $4,840 per month to advertise products you will eventually mark down to clearance. Want to see the list, decomposed by Class, with the days-since-last-sale on each?”
- The merchant CEO: “Are you serious? Why has nobody caught this?”
- The answer: because the join across Sage Intacct (Item-tagged sales velocity from GL Detail) and the ad platforms (spend + clicks per product feed entry) does not exist as a native report on either side. Sage Intacct’s strength on this card is the dimensional read of sales velocity; the ad-platform side is the same as for any other cross-channel waste card. Vortex IQ is the join layer.
- 3 to 8% of monthly ad spend is on dead-stock Items (median).
- Recovered annual spend: 150K for typical merchants in the 100M revenue range.
- The same logic applies to Amazon Ads (often higher: 5 to 15% wasted).
- The fix is process: monthly review of this card + automated pause rules on dead-stock detection.
- Sage Intacct merchants tend to have cleaner Item-dimension data than NetSuite merchants (because Intacct’s dimensional model enforces tagging at line level), which means the Item-to-ad-platform join is more reliable. Expect higher accuracy on this card on Intacct than on equivalent ERPs.
Sibling cards merchants should reference together
| Card | Why pair it with Dead Stock with Active Ad Spend |
|---|---|
| Dead Stock Value | The dollar dead-stock figure; this card filters to those with ad spend. |
| Inventory Aging | The ageing curve for the dead-stock Items; dictates clearance pricing strategy. |
| Margin Erosion Alerts | Markdown clearance pulls margin down; this card’s action is the cause. |
| OOS with Open Order Demand | The mirror leak: this card is over-stocked + over-promoted; OOS is under-stocked + has demand. |
| Inventory Carrying Cost | The carrying-cost twin: dead stock is double-charged (ad spend AND warehousing capital). |
google_ads.adwords_total_spend | The denominator: total ad spend, this card is the dead-spend subset. |
amazon_ads.amzn_ads_spend | Same for Amazon Ads. |
| Top SKUs by Inventory Value | If a top inventory-value Item appears here, the recovery is large. |
Reconciling against the vendor’s own dashboard
Where to look in Sage Intacct’s own dashboard: Sage Intacct cannot show this. Intacct has no view of ad-platform spend. The view is necessarily cross-platform. Intacct’s dead-stock view: Reports → Inventory → Inventory Aging by Item, filtered to zero-velocity Items. The dimensional cut is the unique value: the same dead-stock list can be re-sliced by Class (Retail D2C only, since that is where ads run), by Department (which Department’s merchandiser is responsible), or by Project (project-tagged components that finished a project and now sit unused). Cross-reference manually against Google Ads / Amazon Ads / Meta Ads UIs to find which dead-stock Items are still ad-active. This is exactly what Vortex IQ automates. The Implementation Partner pattern: most Partners do not run this analysis at all because it requires the cross-platform join. The Partner’s monthly board pack typically shows “dead stock value” in aggregate; the per-Item with-ad-spend decomposition is invisible to them. Vortex IQ is the only tool that surfaces this for Sage Intacct merchants. Why our list may legitimately differ from a manual cross-check:| Reason | Direction | Why |
|---|---|---|
| Item-to-ad-product mapping | Material | Vortex IQ joins Intacct Item to ad-platform product_id / landing_page_url. Mis-mapping (incorrect feed configuration, a SKU with two product feed entries) produces false negatives. |
| Ad spend allocation | Material | Brand-keyword ad spend (which does not directly target a SKU) is excluded; some merchants want to include it. Configurable. |
| Sales-velocity threshold | Either | 90D zero-sales is the default. Different industries need different thresholds (slow-fashion may need 180D, fast-rotating consumer-electronics may need 60D). |
| Multi-currency | Either | Ad spend in different currencies converted to consolidation; FX timing affects the dollar comparison marginally. |
| Class scope | Either | Default includes all Classes. Most merchants want to filter to Retail D2C Class only (since Wholesale Class typically does not run paid product ads). Tune the field map. |
| Implementation Partner Item-active flag | Either | If the Partner has marked an Item as inactive in Intacct but the ad platform is still serving it, the Item shows here even though Intacct considers it discontinued. The fix is to ensure inactive-Item discontinuation propagates to ad-feed pause. |
| Card | Direction | Notes |
|---|---|---|
google_ads.adwords_total_spend | Spend side | The total spend; this card is the dead-stock subset. |
amazon_ads.amzn_ads_spend | Spend side | Same. |
facebook.fb_ads_spend | Spend side | Meta ads. |
| Dead Stock Value | Inventory side | Zero-velocity Item dollars; this card adds the spend filter. |
Known limitations / merchant FAQs
My ad team says they manage spend at campaign level, not Item level. Why does this matter? Because campaign-level health metrics (ROAS, CTR) average across Items. A campaign with 200 Items can show a healthy 4.0x ROAS overall while 14 specific Items in it return 0x because nobody bought. The dead-stock subset bleeds quietly while the campaign headline looks fine. Item-level visibility is the only way to catch this, and Sage Intacct’s Item dimension is the cleanest source for the sales-velocity side of the join. An Item sold zero in 90 days but sold 200 units in the prior 90 days. Is it really dead? Possibly seasonal. Configure a seasonality rule for the merchant (e.g. winter coats expected to sell Oct-Feb, dead-stock detection should expect zero sales Apr-Aug). Vortex IQ supports a seasonality calendar via manifest configuration; without it, all 90D-zero-sales Items flag. My new product launches always show as dead-stock initially. Will they appear here? Yes if 90+ days have passed and they have not sold while having ad spend. New-product flag on the Intacct Item record (via a custom dimension or the Item’screation_date) can suppress the alert for a configurable warmup period (default 60 days).
Can I auto-pause ads from this card?
Yes via Ask Viq. Vortex IQ supports a “pause ads on these Items” action that posts a campaign-level negative-product or product-pause to Google Ads / Amazon Ads / Meta Ads. Requires merchant authorisation and the relevant ad-platform permissions.
Multi-Entity Console: per-entity?
Yes. The dead-stock + ad-spend join runs per-entity. The US entity’s US-targeted Google Ads spend on US-warehouse-held dead stock is independent of the Canadian sub’s same. Most multi-entity Sage Intacct merchants run consumer-facing Class only on the primary entity, so the card is typically empty on secondary entities.
The card shows my brand-keyword spend as “dead-stock advertising” because the brand-search lands on a product page. Wrong?
Yes, brand-search should not count. Configure the brand-keyword exclusion in the Google Ads scope; brand search typically generates a “no-product” landing page or a category page. Filter out keywords classified as Brand.
Why does this card not include Amazon Marketplace Vendor / Wholesale spend?
Because Vendor / Wholesale spend on Amazon does not map cleanly to seller-level inventory; the inventory is owned by Amazon. The card focuses on FBM / FBA seller-side where the merchant owns the inventory and pays the ad spend.
The card shows $1,140/month on an Item but I sell wholesale, not via that ad. Why?
Because the same Item is listed on the merchant’s Shopify Retail D2C channel + advertised on Google Shopping. The Retail D2C ads do not move the Wholesale book but still spend money on a product the warehouse holds dead stock on. Filter the Class dimension to Retail D2C only if you want to suppress these patterns; or leave them to surface the actual waste.
Should I worry if a new Item has $200/month spend but no sales in 30 days?
30 days is too short. Below 60 to 90 days is normal product-launch ramp. The 90-day default exists because it captures genuinely dead products without false-flagging launches.
My Item-to-ad-feed mapping is incomplete. How do I check it?
Cross-reference google_ads.adwords_oos_landing_pages and similar cards. Combined view shows which ads land on URLs that do not match an Intacct Item record (mapping gap) vs which ads land on dead-stock Items (the kill shot). Sage Intacct’s dimensional model means the Item-record-to-ad-feed mapping is a single-table lookup, which is structurally cleaner than NetSuite’s Item record plus its custom-field-driven ad-feed-id.
The 200K ad budget. Is it worth pausing?
Yes. Even at 2.4% of budget, the recovery is pure savings (no offsetting customer loss because the products were not selling). Rolled across a year, 20M to 58K of recovered ad budget is approximately 0.15 to 0.3 percentage points of operating margin, which is the kind of finding the Controller takes directly to the CFO.
I have 200+ Items that flag every month. How do I prioritise?
Sort by ad spend descending; pause the top 20. Repeat monthly. The Pareto rule applies: the top 20 of 200 typically account for 60 to 75% of the wasted spend. Use the Sage Intacct Class dimension to focus on Retail D2C first, then Marketplace, then any other Class running paid ads.
Sage Intacct Contracts module: do Contract-bundled Items behave differently?
Yes. A subscription-bundled Item (an annual replenishment plan, a SaaS-bundled hardware Item) recognises revenue over the contract life. The 90D sales-velocity check looks at recognised revenue, so a Contract-bundled Item shows as “selling” only when the Contract releases a slice; if a Contract was billed in February but the next slice is not until June, the Item appears as “no sales in last 90 days” even though the customer is still paying. Tune the field map to detect Contract-bundled Items and use Contract-billing as the velocity signal instead of GL recognition.
REST vs XML API freshness, does it affect this card?
Marginally. Sales velocity is read from Intacct’s GL Detail (XML API for bulk reads), refreshed on the workspace’s cadence (typically 15 to 60 minutes). Ad spend is read from each ad platform’s API in real-time. Lag on the Intacct side is rarely material for a 90D-velocity check; even a 60-minute stale read does not change a “no sales in 90 days” finding.
Sage Intacct vs NetSuite vs Acumatica for this card?
Sage Intacct’s advantage is the dimensional cleanness of the sales-velocity read: Item is a first-class dimension on every revenue line, so the per-Item sales-velocity query is direct. NetSuite has Item records and you can write a SuiteAnalytics query that approximates the same; it requires more steps. Acumatica’s Item dimension exists but the API surface is less consistent. For mid-market merchants who care about per-Item analytics across the GL, Inventory, and Ad-spend join, Sage Intacct’s read is the cleanest.