泥潭日报 uscardforum · 每日精选

日行一善,捐不用的instacart credit 给food bank

内容摘要

利用Instacart信用卡积分向食品救济站捐赠无需货币支出。

1. 关键信息

  • Regulatory fee:NYC 6美元,避开NYC(#1、#35、#60)。
  • 捐赠通过Instacart Community Carts完成,直接配送至组织(#1)。
  • 食品购买免税,可对小费与配送费进行最小化操作(#16)。
  • 部分酒店/航司卡(如IHG、UA)曾有$10 credit,需会员激活并切换支付方式(#60、#63)。

2. 羊毛/优惠信息

  • Mastercard:每月$10;Chase:每月$10–20(#1)。
  • Target REDcard:满$50免配送,配合信用卡积分可近似白送(#27、#30)。
  • Weee!:$10 credit(需激活);Blue Apron、TGTG可作备用薅羊毛渠道(#71、#75)。
  • Amex/CSR/CSP/CIP/Hyatt/C4/UR/MR/TYP/AS/VS/AA/UA/DL:未提及具体兑换比例,保留缩写(#60、#63)。

3. 最新动态

  • 用户自发整理可用信用卡与商超组合进行捐赠(#76)。
  • Instacart自动添加脚本发布,支持批量查找与一键加购(#78)。

4. 争议或不同意见

  • 是否涉及“阶级”标签与道德绑架(#46、#67–#69)。
  • 对shopper私自扣减商品、会员过期、品控不稳定的批评(#22、#32、#80)。
  • 部分用户认为手续费与小费削弱实际优惠价值(#20、#81)。

5. 行动建议

  • 优先选择无Regulatory fee的偏远地区组织(#35)。
  • 避开NYC与西雅图,善用Target等免配送门槛商户(#35、#37)。
  • 及时刷新credit并分批捐赠以降低风险(#76、#79)。
原始内容
--- 第 1 楼来自 Pika123 的回复 (2026-03-31 14:22:59 PDT) ---

现在很多信用卡都附赠 Instacart 积分(mastercard每月 10 美元,Chase 卡每月 10-20 美元)。有些人出于各种原因不使用他们的积分,,你可以用这些积分通过社区购物车向食品救济站捐赠物品。

PS: NYC很黑会收回6块钱regulatory fee, 所以避开nyc就行了。

instacart.com

Donate items to a local cause with Community Carts | Instacart

Select a participating organization to support, browse their personalized wish list, and donate items with a few clicks through Instacart - delivered directly to the organization.

--- 第 2 楼来自 SkylerY 的回复 (2026-03-31 14:23:35 PDT) ---

挺好的,只是我的经济状况还不允许我这么善良

--- 第 3 楼来自 Pika123 的回复 (2026-03-31 14:24:06 PDT) ---

那你再去撞几家银行就有钱了。 这完全不用钱(穷的话delivery person也别tip 就可以白嫖了)。

--- 第 4 楼来自 nin11 的回复 (2026-03-31 14:25:11 PDT) ---

还要动手

--- 第 5 楼来自 Pika123 的回复 (2026-03-31 14:25:34 PDT) ---

也可以动脚

--- 第 6 楼来自 Fiiish 的回复 (2026-03-31 14:26:10 PDT) ---

这个donation能抵税吗

--- 第 7 楼来自 Pika123 的回复 (2026-03-31 14:26:31 PDT) ---

可以低你的鲁卡的罪恶

--- 第 8 楼来自 tomandjerry 的回复 (2026-03-31 14:29:14 PDT) ---

各位需要行善的好人,不需要那么麻烦。直接给我打钱就好了。

捐助给山区贫困儿童

--- 第 9 楼来自 Pika123 的回复 (2026-03-31 14:29:47 PDT) ---

你把你的account# 和 routing # 发出来

--- 第 10 楼来自 tomandjerry 的回复 (2026-03-31 14:31:56 PDT) ---

目前只支持 xmr,谢谢。

8BQ3vdpLVjxA4nq9FWPNrMQ6zpja6J4yuAwvu8EeQyAE6gz6GBFdTPJPPEGMTxW9hEMYS1UcQkeLrG9bryxYtAjxSALcKP3

--- 第 11 楼来自 wanghai 的回复 (2026-03-31 14:32:12 PDT) ---

$10 off 附加条件太多

我不想用,捐

--- 第 12 楼来自 AppleVisionPro 的回复 (2026-03-31 14:39:27 PDT) ---

大家这样做是善举

但是这些credits怎么能用不掉呢?

--- 第 13 楼来自 xxxyyy 的回复 (2026-03-31 14:40:38 PDT) ---

我从来不用,浪费精力。每张卡这种小羊毛都要搞得把人累死。

--- 第 14 楼来自 xxxyyy 的回复 (2026-03-31 14:42:15 PDT) ---

感谢楼主,终于找到办法划掉这些麻烦的credit了。

免所有fee,真不错

--- 第 15 楼来自 dayI 的回复 (2026-03-31 14:44:31 PDT) ---

一般是忘记了……

--- 第 16 楼来自 Pika123 的回复 (2026-03-31 14:45:59 PDT) ---

是的,只要买的是食物是免税。 最多给送货员点tip。 避开nyc就行了因为有regulatory fee。不过这样挺好,可以优先给贫困偏远地区

--- 第 17 楼来自 Define_P 的回复 (2026-03-31 14:48:29 PDT) ---

不想捐给本地的

--- 第 18 楼来自 Pika123 的回复 (2026-03-31 14:53:46 PDT) ---

我也推荐捐给偏远地区!

--- 第 19 楼来自 bill2020 的回复 (2026-03-31 14:58:33 PDT) ---

赞同!我从来不用,以后全捐了

--- 第 20 楼来自 xxxyyy 的回复 (2026-03-31 15:16:51 PDT) ---

不知道doordash的10刀有没有办法捐掉,也很鸡肋。

这种福利不到20刀根本就是反薅,又要小额fee,又要小费,还得溢价买东西

--- 第 21 楼来自 qsun89 的回复 (2026-03-31 15:19:13 PDT) ---

用instacart买菜不是蛮方便的 还是有些阶级的人不需要买菜 都是外面吃

--- 第 22 楼来自 xxxyyy 的回复 (2026-03-31 15:36:37 PDT) ---

很多人不做饭
10刀还得付小费 + fee,还得凑半天不能多不能少,还有markup。最后到手是多少钱还真不好说。shopper有的时候还乱拿东西,容易反薅。
送的会员过期了

谈阶级是啥意思?10刀的订单最少也得自己付4.5刀。东西价值8刀。真没什么意义折腾半天。本来逛超市随手就买的事,弄到instacart上省不了两三块钱

--- 第 23 楼来自 Define_P 的回复 (2026-03-31 15:44:10 PDT) ---

配送成本太高了,不如出门加油的时候顺便拉一后备箱的食物回家囤着(还是 wholesale 模式简单)

--- 第 24 楼来自 Ayanami_7 的回复 (2026-03-31 15:44:48 PDT) ---

不需要会员也能捐吗 会不会有额外的fee 我的instacart+马上到期不打算续提前问问

--- 第 25 楼来自 xxxyyy 的回复 (2026-03-31 15:44:58 PDT) ---

只需要小费,因为是慈善。什么fee都没。而且很好操作,他们需要什么都列好了,点一下加号就完事了。我没会员的号试过了

--- 第 26 楼来自 eee 的回复 (2026-03-31 15:45:11 PDT) ---

这真的挺好的

--- 第 27 楼来自 mxi 的回复 (2026-03-31 15:53:36 PDT) ---

像target这些店都是10刀免配送费,配合credit等于白送,随便买点牛奶鸡蛋桶装咖啡不都是顺手的事…当然可能有些人善举带来的情绪价值远高于10刀,win-win也不亏

--- 第 28 楼来自 列.伊.勃列日涅夫 的回复 (2026-03-31 15:58:01 PDT) ---

那我捐了能在年底抵税吗?

--- 第 29 楼来自 Ava.太太太后 的回复 (2026-03-31 16:02:06 PDT) ---

哈哈doordash那个真的鸡肋,instacart这个捐出去感觉良心好多了,反正用不完

--- 第 30 楼来自 xxxyyy 的回复 (2026-03-31 16:03:13 PDT) ---

【引用自 mxi】:
像target这些店都是10刀免配送费
你得有会员。送的会员过期了就是9.99了。

target本身东西也贵

--- 第 31 楼来自 Yangff 的回复 (2026-03-31 16:04:40 PDT) ---

image1308×931 345 KB

什么意思还不让人凑单是吧,资本家怎么这么坏啊

image1336×886 267 KB

哼,想逃?

--- 第 32 楼来自 xxxyyy 的回复 (2026-03-31 16:06:17 PDT) ---

感觉都不是很好吃。我买了俩午餐肉 + 一个豆子汤凑单,正好10刀。

--- 第 33 楼来自 Yangff 的回复 (2026-03-31 16:06:37 PDT) ---

image1127×539 43.2 KB

闹麻了

--- 第 34 楼来自 xxxyyy 的回复 (2026-03-31 16:06:49 PDT) ---

有什么给西雅图捐的必要吗

--- 第 35 楼来自 Pika123 的回复 (2026-03-31 16:07:08 PDT) ---

别送nyc和西雅图等有regulatory fee. 选个偏远地区

--- 第 36 楼来自 Yangff 的回复 (2026-03-31 16:07:34 PDT) ---

还真是,捐农村得了

--- 第 37 楼来自 Pika123 的回复 (2026-03-31 16:07:38 PDT) ---

对,西雅图,纽约等城市真没必要送。 送给偏远地区,更需要的人

--- 第 38 楼来自 Pika123 的回复 (2026-03-31 16:08:12 PDT) ---

果然资本家克星泥潭人

--- 第 39 楼来自 Define_P 的回复 (2026-03-31 16:09:04 PDT) ---

捐给共和党基本盘还是太后现代了

--- 第 40 楼来自 xxxyyy 的回复 (2026-03-31 16:13:55 PDT) ---

那你捐明尼苏达农村,没区别。而且吃food bank的人很难说是共和党基本盘吧

--- 第 41 楼来自 Yangff 的回复 (2026-03-31 16:14:29 PDT) ---

不过讲道理,农村能领到foodbank嘛,感觉这种东西一般城市里比较多吧

--- 第 42 楼来自 xxxyyy 的回复 (2026-03-31 16:14:49 PDT) ---

【引用自 Yangff】:
农村能领到foodbank嘛
农村也有homeless,我搜了一下村里超级多。很多是教堂的

--- 第 43 楼来自 Define_P 的回复 (2026-03-31 16:24:33 PDT) ---

乡村地区这种职能就是由教会承担的

--- 第 44 楼来自 Pika123 的回复 (2026-03-31 16:25:16 PDT) ---

对的,偏远地区基本上靠教堂。 谁都有需要帮扶一把时候

--- 第 45 楼来自 qsun89 的回复 (2026-03-31 16:27:52 PDT) ---

你说的第一点不就回答了我关于阶级的问题?怎么还有自答自问的

--- 第 46 楼来自 xxxyyy 的回复 (2026-03-31 16:29:22 PDT) ---

做不做饭 = 阶级?

我吃食堂不行吗

--- 第 47 楼来自 qsun89 的回复 (2026-03-31 16:29:54 PDT) ---

算了不聊阶级了 聊聊你丰富的幽默感吧

--- 第 48 楼来自 xxxyyy 的回复 (2026-03-31 16:33:40 PDT) ---

刚才试试下了一单,20刀的东西,shopper就拿了10刀就checkout走了。我自己付了五六刀出去,血亏。

这玩意自己用抽象的很

--- 第 49 楼来自 ybing99 的回复 (2026-03-31 16:35:19 PDT) ---

思路打开了

自己用不出去时候,捐了蛮好的。

--- 第 50 楼来自 ybing99 的回复 (2026-03-31 16:38:51 PDT) ---

说实话我觉得偏题了

捐与不捐不过是选择,捐的人没有必要站在高处道德绑架,不捐的人在本帖也没必要嘲讽

--- 第 51 楼来自 lyy 的回复 (2026-03-31 16:49:09 PDT) ---

【引用自 Fiiish】:
这个donation能抵税吗
是时候学习一下新的大美丽法案里面的donation的项目了。一般的捐款已经不能抵税了,除非你捐够一定数额(泥潭用户一般捐不到,不然就不来泥潭了)

--- 第 52 楼来自 qsun89 的回复 (2026-03-31 16:52:21 PDT) ---

说实话我只想问句 instcart买菜不是蛮方便的,想问为什么不自己用卷了,我自己chase的10刀doordash固定每周买块肉,因为懒得出门。不知道我的话可以被理解为嘲讽或道德绑架

--- 第 53 楼来自 mengyu202 的回复 (2026-03-31 16:54:54 PDT) ---

food bank会不会怕来路不明然后丢了

--- 第 54 楼来自 xxxyyy 的回复 (2026-03-31 16:56:02 PDT) ---

这个就是foodbank自己参与的,他们给了一个shopping list,你只能买上面的东西。

--- 第 55 楼来自 不知道是谁 的回复 (2026-03-31 17:00:13 PDT) ---

然后被foodbank员工贪了。感觉慈善机构水都很深

--- 第 56 楼来自 Pika123 的回复 (2026-03-31 17:05:48 PDT) ---

你可以选其他的, 选项挺多的

--- 第 57 楼来自 xxxyyy 的回复 (2026-03-31 17:07:08 PDT) ---

你送食物不送钱,没那么好贪。

我听我朋友去foodbank当志愿者的经历,没看出来水深在哪,至少分发食物这方面没感觉有什么问题。资金运作就不知道了

--- 第 58 楼来自 Pika123 的回复 (2026-03-31 17:09:53 PDT) ---

嗯,我food bank volunteer 时候也都是装好一袋一袋食物 然后拿去分给人。 这是直接送食物,不好贪

--- 第 59 楼来自 kevincs 的回复 (2026-03-31 17:12:30 PDT) ---

没有WA, Seattlle, BRK 让了

--- 第 60 楼来自 See 的回复 (2026-03-31 17:14:21 PDT) ---

我也去做过,把食物装箱,但公司组织者说foodbank要先收几千刀入场费才给我们来的。

另外,怎么没看到ihg和ua卡的$10credit呢?必须买胡萝卜会员才能激活吗?而且点多了还不能删除数量,只能往上加不能减,太流氓了吧?

破案了

IMG_61311206×357 48.4 KB

IMG_61321206×445 59.1 KB

--- 第 61 楼来自 P1919 的回复 (2026-03-31 17:16:55 PDT) ---

【引用自 列.伊.勃列日涅夫】:
那我捐了能在年底抵税吗?
估计是你捐了instacart就可以在年底的时候用这笔钱抵税了,因为是用他们名义捐的

--- 第 62 楼来自 ybing99 的回复 (2026-03-31 17:19:05 PDT) ---

【引用自 qsun89】:
只想问句 instcart买菜不是蛮方便的,想问为什么不自己用卷了
很合理,不过更适合在Instacart credit帖子下讨论;再退一步,可以只讲本意(即前半部分),不提及买菜以及阶级。

话说买不买菜,最多讲到消费观念,和阶级有锤子关系

--- 第 63 楼来自 xxxyyy 的回复 (2026-03-31 17:23:30 PDT) ---

【引用自 See】:
怎么没看到ihg和ua卡的$10credit呢?必须买胡萝卜会员才能激活吗?
要会员才有好像。然后支付的时候要切换到这张卡

--- 第 64 楼来自 xxxyyy 的回复 (2026-03-31 17:24:34 PDT) ---

这个不行吧,很明显有问题。

他们能做账的部分应该只有他们免掉的fee和他们承担的运费。

消费者送的那部分他们不能拿来抵税

--- 第 65 楼来自 qsun89 的回复 (2026-03-31 17:25:22 PDT) ---

好的 我以后不允许我觉得只堂食的人比我有钱很多, 我以后肯定按照你的要求发表言论, 肯定发在指定板块地方,肯定不开玩笑说比体感有钱很多的人是在另一个阶级。你是电是光是神话,论坛是你的 你真牛逼。

--- 第 66 楼来自 Koalakoala 的回复 (2026-03-31 17:27:04 PDT) ---

instacart把我账号ban了我还能捐吗?

--- 第 67 楼来自 xxxyyy 的回复 (2026-03-31 17:27:45 PDT) ---

【引用自 qsun89】:
我以后不允许我觉得只堂食的人比我有钱很多
主要是你的逻辑根本说不通。

不自己做饭不代表有钱,美国做饭成本一点也不低。我一顿饭自己做成本轻松10刀+。
【引用自 xxxyyy】:
我吃食堂不行吗
公司食堂不要钱,学校食堂几刀。照你这么说所有学生,所有公司管饭的人都比你有钱。都不是你的阶级的,因为他们不做饭…

再退一万步,美国一堆几刀就能吃饱的垃圾食物,你总不能说在麦当劳解决晚餐的人比你有钱嘛,比你阶级高。

--- 第 68 楼来自 xxxyyy 的回复 (2026-03-31 17:32:22 PDT) ---

开小号呗

--- 第 69 楼来自 qsun89 的回复 (2026-03-31 17:34:59 PDT) ---

这有点不客观了吧… 美国现在物价肯定堂食物比做饭贵很多啊。难道概率上说 堂食的更穷?你一定要枚举例子说服我觉得能每天外面吃的人比我穷吗?我自己体感做饭省钱也不合逻辑吗。

--- 第 70 楼来自 qsun89 的回复 (2026-03-31 17:35:17 PDT) ---

算了不吵了 你回答我的问题了最后 谢谢

--- 第 71 楼来自 davidx 的回复 (2026-03-31 20:45:34 PDT) ---

我同意你说的,我经常在家做饭,但每个月买菜钱一点也不少花,因为一个人吃不可避免会出现食物吃不完浪费,需要花时间做,只能做一个菜(不然吃不完),需要吃不新鲜的事物(有时候做多了只能冻起来)等等问题

我自己算过一笔账,全部在外面吃并不比我自己在家做多花什么钱,甚至还节省了买菜做饭的时间,唯一在家做的理由是这边中餐馆做的菜普遍是川菜江湖菜天天吃很难受

因为在家做,所以会留意怎么可以省钱,从来没觉得用Instacart省钱… 我个人一般会薅Weee小号,Blue Apron白嫖,TGTG

--- 第 72 楼来自 zpahai 的回复 (2026-03-31 23:56:41 PDT) ---

image1314×707 56.9 KB

--- 第 73 楼来自 skywing 的回复 (2026-04-01 00:58:45 PDT) ---

每次建一个新号trial,mastercard,Costco薅一圈就半年会员了

--- 第 74 楼来自 xxxyyy 的回复 (2026-04-01 01:08:43 PDT) ---

【引用自 davidx】:
唯一在家做的理由是这边中餐馆做的菜普遍是川菜江湖菜天天吃很难受
对,我自己做的唯一原因也是餐厅里吃不到一些菜,只能自己做。

当然偶尔做做牛排什么的,还是比餐厅便宜多了

--- 第 75 楼来自 cocdeshijie 的回复 (2026-04-01 01:19:52 PDT) ---

自用ic薅 50-35 80-40 100-50 125-50

$10 credit 就都捐了吧

--- 第 76 楼来自 Pika123 的回复 (2026-04-01 11:48:52 PDT) ---

今天credit 又刷新了。 日行一善, 无量陀佛天尊,阿门

--- 第 77 楼来自 Pika123 的回复 (2026-04-01 18:18:54 PDT) ---

好人啊!

--- 第 78 楼来自 zpahai 的回复 (2026-04-01 19:30:46 PDT) ---

这不是大伙最爱的coin change变体吗,来复习一下DP // ==UserScript== // @name Instacart Auto-Add Closest to Target // @namespace http://tampermonkey.net/ // @version 6.0 // @description Auto-selects items (with quantities, bundle promos & sale prices) closest to a target amount on Instacart food bank lists. Always meets or exceeds the minimum. Includes cart cleaning. // @match https://www.instacart.com/store/list/* // @grant none // ==/UserScript== (function () { 'use strict'; const DEFAULT_TARGET = 10.00; const ADD_DELAY_MS = 800; const MAX_QTY_PER_ITEM = 10; const OVERSHOOT_CENTS = 200; function parsePrice(text) { const m = text.match(/\$(\d+\.?\d*)/); return m ? parseFloat(m[1]) : null; } function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); } // ── Phase 1: Scan all product cards ── function getAllItems() { const cards = document.querySelectorAll('[role="group"][aria-label="product card"]'); const items = []; cards.forEach((card) => { const srOnly = card.querySelector('.screen-reader-only'); const addBtn = card.querySelector('button[aria-label^="Add"]'); if (!srOnly || !addBtn) return; const srText = srOnly.textContent; const allPrices = [...srText.matchAll(/\$(\d+\.?\d*)/g)].map(m => parseFloat(m[1])).filter(p => p > 0); let discountedPrice = null; const priceEls = card.querySelectorAll( '[data-testid="item-price"], [class*="sale"], [class*="discount"], [class*="current-price"]' ); priceEls.forEach(el => { const p = parsePrice(el.textContent); if (p !== null && p > 0) discountedPrice = p; }); const originalPrice = allPrices.length > 0 ? Math.max(...allPrices) : null; let effectivePrice = discountedPrice || (allPrices.length > 1 ? Math.min(...allPrices) : null) || originalPrice; if (effectivePrice === null || effectivePrice <= 0) return; const nameEl = addBtn.getAttribute('aria-label') || ''; const name = nameEl.replace(/^Add 1 ct /, ''); let promo = null; const divs = card.querySelectorAll('div, span'); divs.forEach((d) => { const t = d.textContent.trim(); if (d.children.length > 0) return; const mOff = t.match(/^Buy (\d+) or more, get \$(\d+\.?\d*) off each$/); if (mOff) { promo = { type: 'bulk_off', minQty: parseInt(mOff[1]), discount: parseFloat(mOff[2]), raw: t }; } const mFor = t.match(/^Buy (\d+) for \$(\d+\.?\d*)$/); if (mFor) { promo = { type: 'bundle_for', qty: parseInt(mFor[1]), bundlePrice: parseFloat(mFor[2]), raw: t }; } }); items.push({ price: effectivePrice, originalPrice: originalPrice || effectivePrice, name, addBtn, card, promo, }); }); return items; } // ── Phase 2: Build solver entries (singles + virtual bundles) ── function buildSolverEntries(items, maxQty) { const entries = []; const promoGroups = {}; items.forEach((item) => { entries.push({ type: 'single', price: item.price, name: item.name, items: [{ item, qty: 1 }], maxQty: maxQty, }); if (item.promo) { const key = item.promo.raw; if (!promoGroups[key]) promoGroups[key] = { promo: item.promo, members: [] }; promoGroups[key].members.push(item); } }); for (const key of Object.keys(promoGroups)) { const { promo, members } = promoGroups[key]; if (promo.type === 'bulk_off') { const sorted = [...members].sort((a, b) => a.price - b.price); const minQty = promo.minQty; const discount = promo.discount; const seen = new Set(); for (const member of sorted) { const basePrice = member.price; const bundleUnitPrice = basePrice - discount; const bundlePrice = bundleUnitPrice * minQty; const bundleKey = `single_${member.name}`; if (bundlePrice > 0 && bundleUnitPrice > 0 && !seen.has(bundleKey)) { seen.add(bundleKey); entries.push({ type: 'bundle', price: Math.round(bundlePrice * 100) / 100, name: `🏷️ ${minQty}× ${member.name.substring(0, 35)}… ($${discount} off each)`, items: [{ item: member, qty: minQty }], maxQty: Math.floor(maxQty / minQty), promoInfo: promo, }); } } if (sorted.length >= minQty) { const mixItems = sorted.slice(0, minQty); const mixPrice = mixItems.reduce((s, it) => s + (it.price - discount), 0); if (mixPrice > 0) { entries.push({ type: 'bundle', price: Math.round(mixPrice * 100) / 100, name: `🏷️ Mix: ${mixItems.map((it) => it.name.substring(0, 20)).join(' + ')}… ($${discount} off each)`, items: mixItems.map((it) => ({ item: it, qty: 1 })), maxQty: 1, promoInfo: promo, }); } } if (sorted.length > minQty) { for (let start = 1; start <= sorted.length - minQty; start++) { const mixItems = sorted.slice(start, start + minQty); if (mixItems.length === minQty) { const mixPrice = mixItems.reduce((s, it) => s + (it.price - discount), 0); if (mixPrice > 0) { entries.push({ type: 'bundle', price: Math.round(mixPrice * 100) / 100, name: `🏷️ Mix: ${mixItems.map((it) => it.name.substring(0, 20)).join(' + ')}…`, items: mixItems.map((it) => ({ item: it, qty: 1 })), maxQty: 1, promoInfo: promo, }); } } } } } else if (promo.type === 'bundle_for') { const { qty, bundlePrice } = promo; for (const member of members) { entries.push({ type: 'bundle', price: bundlePrice, name: `🏷️ ${qty}× ${member.name.substring(0, 40)}… (${qty} for $${bundlePrice.toFixed(2)})`, items: [{ item: member, qty }], maxQty: Math.floor(maxQty / qty), promoInfo: promo, }); } } } return entries; } // ── Phase 3: Unbounded knapsack DP (must meet or exceed target) ── function findBestSubset(entries, target) { const targetCents = Math.round(target * 100); const cap = targetCents + OVERSHOOT_CENTS; const prices = entries.map((e) => Math.round(e.price * 100)); const dp = new Array(cap + 1).fill(null); dp[0] = { selections: [], totalQty: 0 }; for (let s = 1; s <= cap; s++) { for (let i = 0; i < entries.length; i++) { const p = prices[i]; if (p <= 0 || p > s) continue; const prev = dp[s - p]; if (prev === null) continue; const existing = prev.selections.find((e) => e.entryIdx === i); const currentQty = existing ? existing.qty : 0; if (currentQty >= entries[i].maxQty) continue; let newSel; if (existing) { newSel = prev.selections.map((e) => e.entryIdx === i ? { entryIdx: i, qty: e.qty + 1 } : { ...e } ); } else { newSel = [...prev.selections, { entryIdx: i, qty: 1 }]; } const newTotalQty = prev.totalQty + 1; if (dp[s] === null || newTotalQty < dp[s].totalQty) { dp[s] = { selections: newSel, totalQty: newTotalQty }; } } } let bestSum = null; for (let s = targetCents; s <= cap; s++) { if (dp[s] !== null) { bestSum = s; break; } } if (bestSum === null) { return { selections: [], solverSelections: [], total: 0, belowTarget: true }; } const result = []; for (const sel of dp[bestSum].selections) { const entry = entries[sel.entryIdx]; for (let q = 0; q < sel.qty; q++) { for (const comp of entry.items) { const existing = result.find((r) => r.item === comp.item); if (existing) { existing.qty += comp.qty; } else { result.push({ item: comp.item, qty: comp.qty, fromBundle: entry.type === 'bundle' }); } } } } return { selections: result, solverSelections: dp[bestSum].selections.map((s) => ({ entry: entries[s.entryIdx], qty: s.qty, })), total: bestSum / 100, belowTarget: false, }; } // ── Clean Cart: Remove all items from the donation cart ── async function cleanCart(statusEl) { const CLICK_DELAY = 600; const EXPAND_DELAY = 400; // Gather all product cards that are currently in the cart function getCartCards() { const cards = document.querySelectorAll('[role="group"][aria-label="product card"]'); const cartCards = []; cards.forEach((card) => { // A card is in the cart if it has a "Quantity: X ct" button or // expanded decrement/remove controls const qtyBtn = card.querySelector('button[aria-label*="Quantity"]'); const decBtn = card.querySelector( 'button[aria-label^="Decrement"], button[aria-label^="Remove"]' ); if (qtyBtn || decBtn) { let qty = 1; if (qtyBtn) { const m = qtyBtn.textContent.match(/(\d+)/); if (m) qty = parseInt(m[1]); } cartCards.push({ card, qtyBtn, decBtn, qty }); } }); return cartCards; } let cartCards = getCartCards(); const totalItems = cartCards.reduce((sum, c) => sum + c.qty, 0); if (totalItems === 0) { if (statusEl) statusEl.textContent = '✅ Cart is already empty!'; return; } if (statusEl) statusEl.textContent = `🗑️ Cleaning cart: ${totalItems} items to remove...`; let removed = 0; for (let pass = 0; pass < 50; pass++) { // Re-scan each pass in case DOM changes cartCards = getCartCards(); if (cartCards.length === 0) break; const entry = cartCards[0]; // Scroll the card into view entry.card.scrollIntoView({ behavior: 'smooth', block: 'center' }); await sleep(300); // Step 1: If controls are compact, click the quantity button to expand if (entry.qtyBtn && !entry.decBtn) { entry.qtyBtn.click(); await sleep(EXPAND_DELAY); } // Step 2: Re-query the decrement/remove button (it may have just appeared) let decBtn = entry.card.querySelector( 'button[aria-label^="Decrement"], button[aria-label^="Remove"]' ); if (!decBtn) { // Fallback: try clicking the quantity button again const qtyBtn2 = entry.card.querySelector('button[aria-label*="Quantity"]'); if (qtyBtn2) { qtyBtn2.click(); await sleep(EXPAND_DELAY); decBtn = entry.card.querySelector( 'button[aria-label^="Decrement"], button[aria-label^="Remove"]' ); } } if (!decBtn) { // Can't find the button — skip this card to avoid infinite loop if (statusEl) statusEl.textContent = `⚠️ Could not find remove button for a cart item, skipping...`; await sleep(500); continue; } // Step 3: Click the decrement/remove button decBtn.click(); removed++; await sleep(CLICK_DELAY); if (statusEl) { statusEl.textContent = `🗑️ Removing items... (${removed}/${totalItems})`; } } // Final check const remaining = getCartCards(); if (remaining.length === 0) { if (statusEl) statusEl.textContent = `✅ Cart cleaned! Removed ${removed} items.`; } else { const leftover = remaining.reduce((sum, c) => sum + c.qty, 0); if (statusEl) statusEl.textContent = `⚠️ Removed ${removed} items, but ${leftover} remain. Try again.`; } } // ── Phase 5: UI ── function createUI() { const panel = document.createElement('div'); panel.id = 'ic-auto-add-panel'; panel.innerHTML = ` <style> #ic-auto-add-panel { position: fixed; top: 70px; right: 20px; z-index: 99999; background: #fff; border: 2px solid #2b8a3e; border-radius: 12px; padding: 16px 20px; width: 380px; box-shadow: 0 4px 24px rgba(0,0,0,0.18); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; } #ic-auto-add-panel h3 { margin: 0 0 10px; color: #2b8a3e; font-size: 16px; } #ic-auto-add-panel label { font-size: 13px; color: #555; } #ic-auto-add-panel input[type=number] { width: 70px; padding: 4px 8px; border: 1px solid #ccc; border-radius: 6px; font-size: 14px; margin-left: 4px; } #ic-auto-add-panel .btn { display: inline-block; margin-top: 10px; padding: 8px 16px; border: none; border-radius: 8px; font-size: 14px; cursor: pointer; font-weight: 600; transition: background 0.2s; } #ic-auto-add-panel .btn-find { background: #2b8a3e; color: #fff; } #ic-auto-add-panel .btn-find:hover { background: #237032; } #ic-auto-add-panel .btn-add { background: #e67700; color: #fff; margin-left: 6px; } #ic-auto-add-panel .btn-add:hover { background: #c56200; } #ic-auto-add-panel .btn-clean { background: #dc3545; color: #fff; margin-left: 6px; } #ic-auto-add-panel .btn-clean:hover { background: #b02a37; } #ic-auto-add-panel .btn-close { position: absolute; top: 8px; right: 12px; background: none; border: none; font-size: 18px; cursor: pointer; color: #999; } #ic-auto-add-panel .results { margin-top: 10px; max-height: 300px; overflow-y: auto; font-size: 13px; line-height: 1.6; } #ic-auto-add-panel .results .section-hdr { font-weight: 700; color: #555; margin-top: 8px; font-size: 12px; text-transform: uppercase; letter-spacing: 0.5px; } #ic-auto-add-panel .results .item { padding: 3px 0; border-bottom: 1px solid #eee; } #ic-auto-add-panel .results .item.bundle { background: #f0faf0; padding: 4px 6px; border-radius: 4px; margin: 2px 0; } #ic-auto-add-panel .results .qty-badge { background: #2b8a3e; color: #fff; border-radius: 4px; padding: 1px 6px; font-size: 11px; font-weight: 700; margin-right: 4px; } #ic-auto-add-panel .results .promo-badge { background: #e67700; color: #fff; border-radius: 4px; padding: 1px 6px; font-size: 10px; font-weight: 700; margin-left: 4px; } #ic-auto-add-panel .results .sale-badge { background: #d63384; color: #fff; border-radius: 4px; padding: 1px 6px; font-size: 10px; font-weight: 700; margin-left: 4px; } #ic-auto-add-panel .results .total { font-weight: 700; color: #2b8a3e; margin-top: 8px; font-size: 14px; } #ic-auto-add-panel .status { margin-top: 8px; font-size: 12px; color: #888; } </style> <button class="btn-close" id="ic-close-btn">&times;</button> <h3>🛒 Auto-Add to Target</h3> <div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;"> <label>Target: $<input type="number" id="ic-target" value="${DEFAULT_TARGET}" min="1" step="0.50"></label> <label>Max qty: <input type="number" id="ic-max-qty" value="${MAX_QTY_PER_ITEM}" min="1" max="20" step="1"></label> </div> <br> <button class="btn btn-find" id="ic-find-btn">Find Best Combo</button> <button class="btn btn-add" id="ic-add-btn" style="display:none">Add All to Cart</button> <button class="btn btn-clean" id="ic-clean-btn">🗑 Clean Cart</button> <div class="results" id="ic-results"></div> <div class="status" id="ic-status"></div> `; document.body.appendChild(panel); let bestResult = null; document.getElementById('ic-close-btn').addEventListener('click', () => { panel.style.display = panel.style.display === 'none' ? 'block' : 'none'; }); // ── Clean Cart button handler ── document.getElementById('ic-clean-btn').addEventListener('click', async () => { const statusEl = document.getElementById('ic-status'); const cleanBtn = document.getElementById('ic-clean-btn'); const resultsEl = document.getElementById('ic-results'); const addBtn = document.getElementById('ic-add-btn'); cleanBtn.disabled = true; cleanBtn.textContent = '🗑 Cleaning...'; cleanBtn.style.background = '#6c757d'; addBtn.style.display = 'none'; resultsEl.innerHTML = ''; // Remove highlights from previous selections document.querySelectorAll('.ic-highlight, .ic-highlight-bundle').forEach((el) => { el.classList.remove('ic-highlight'); el.classList.remove('ic-highlight-bundle'); }); bestResult = null; await cleanCart(statusEl); cleanBtn.disabled = false; cleanBtn.textContent = '🗑 Clean Cart'; cleanBtn.style.background = '#dc3545'; }); // ── Find Best Combo button handler ── document.getElementById('ic-find-btn').addEventListener('click', () => { const target = parseFloat(document.getElementById('ic-target').value) || DEFAULT_TARGET; const maxQty = parseInt(document.getElementById('ic-max-qty').value) || MAX_QTY_PER_ITEM; const allItems = getAllItems(); const statusEl = document.getElementById('ic-status'); const resultsEl = document.getElementById('ic-results'); const addBtn = document.getElementById('ic-add-btn'); const saleCount = allItems.filter(it => it.price < it.originalPrice).length; statusEl.textContent = `Scanning ${allItems.length} items (${saleCount} on sale) and promotions...`; resultsEl.innerHTML = ''; addBtn.style.display = 'none'; document.querySelectorAll('.ic-highlight, .ic-highlight-bundle').forEach((el) => { el.classList.remove('ic-highlight'); el.classList.remove('ic-highlight-bundle'); }); setTimeout(() => { const entries = buildSolverEntries(allItems, maxQty); const promoCount = entries.filter((e) => e.type === 'bundle').length; statusEl.textContent = `Found ${allItems.length} items + ${promoCount} bundle options. Solving...`; setTimeout(() => { bestResult = findBestSubset(entries, target); if (bestResult.selections.length === 0) { if (bestResult.belowTarget) { resultsEl.innerHTML = `<em>⚠ Could not find any combination that meets the $${target.toFixed(2)} minimum within the overshoot range. Try increasing max qty or lowering the target.</em>`; } else { resultsEl.innerHTML = '<em>No combination found.</em>'; } statusEl.textContent = ''; return; } const totalQty = bestResult.selections.reduce((a, s) => a + s.qty, 0); let html = ''; const bundles = bestResult.solverSelections.filter((s) => s.entry.type === 'bundle'); const singles = bestResult.solverSelections.filter((s) => s.entry.type === 'single'); if (bundles.length > 0) { html += '<div class="section-hdr">Promo Bundles</div>'; for (const s of bundles) { const sub = (s.entry.price * s.qty).toFixed(2); const qtyLabel = s.qty > 1 ? `<span class="qty-badge">×${s.qty}</span>` : ''; html += `<div class="item bundle">${qtyLabel}$${s.entry.price.toFixed(2)}${s.qty > 1 ? ' = $' + sub : ''} — ${s.entry.name}<span class="promo-badge">PROMO</span></div>`; } } if (singles.length > 0) { html += '<div class="section-hdr">Regular Items</div>'; for (const s of singles) { const sub = (s.entry.price * s.qty).toFixed(2); const qtyLabel = s.qty > 1 ? `<span class="qty-badge">×${s.qty}</span>` : ''; const name = s.entry.name.substring(0, 45) + (s.entry.name.length > 45 ? '…' : ''); const item = s.entry.items[0].item; const saleBadge = item.price < item.originalPrice ? `<span class="sale-badge">SALE $${item.originalPrice.toFixed(2)} → $${item.price.toFixed(2)}</span>` : ''; html += `<div class="item">${qtyLabel}$${s.entry.price.toFixed(2)}${s.qty > 1 ? ' = $' + sub : ''} — ${name}${saleBadge}</div>`; } } html += '<div class="section-hdr" style="margin-top:10px;">Cart Actions</div>'; for (const sel of bestResult.selections) { const name = sel.item.name.substring(0, 40) + (sel.item.name.length > 40 ? '…' : ''); html += `<div class="item"><span class="qty-badge">×${sel.qty}</span>${name}</div>`; } html += `<div class="total">Total: $${bestResult.total.toFixed(2)} (${totalQty} items added to cart)</div>`; const diff = bestResult.total - target; if (Math.abs(diff) < 0.01) { html += `<div style="color:#2b8a3e;font-size:12px;">✓ Exact match!</div>`; } else { html += `<div style="color:#2b8a3e;font-size:12px;">✓ $${diff.toFixed(2)} over minimum (closest possible)</div>`; } resultsEl.innerHTML = html; addBtn.style.display = 'inline-block'; addBtn.disabled = false; addBtn.textContent = 'Add All to Cart'; addBtn.style.background = '#e67700'; statusEl.textContent = 'Review the selection, then click "Add All to Cart".'; const style = document.getElementById('ic-highlight-style') || document.createElement('style'); style.id = 'ic-highlight-style'; style.textContent = ` .ic-highlight { outline: 3px solid #2b8a3e !important; outline-offset: 2px; border-radius: 8px; } .ic-highlight-bundle { outline: 3px solid #e67700 !important; outline-offset: 2px; border-radius: 8px; } `; document.head.appendChild(style); bestResult.selections.forEach((s) => { s.item.card.classList.add(s.fromBundle ? 'ic-highlight-bundle' : 'ic-highlight'); }); }, 50); }, 50); }); // ── Add All to Cart button handler ── document.getElementById('ic-add-btn').addEventListener('click', async () => { if (!bestResult || bestResult.selections.length === 0) return; const statusEl = document.getElementById('ic-status'); const addBtnEl = document.getElementById('ic-add-btn'); addBtnEl.disabled = true; addBtnEl.textContent = 'Adding...'; const totalClicks = bestResult.selections.reduce((a, s) => a + s.qty, 0); let clickNum = 0; for (const sel of bestResult.selections) { sel.item.card.scrollIntoView({ behavior: 'smooth', block: 'center' }); await sleep(400); for (let q = 0; q < sel.qty; q++) { clickNum++; statusEl.textContent = `Adding ${clickNum}/${totalClicks}: ${sel.item.name.substring(0, 35)}… (${q + 1}/${sel.qty})`; if (q === 0) { sel.item.addBtn.click(); } else { await sleep(300); const incBtn = sel.item.card.querySelector('button[aria-label*="Increment"]') || sel.item.card.querySelector('button[aria-label*="increment"]') || sel.item.card.querySelector('button[aria-label*="Add 1"]'); if (incBtn) { incBtn.click(); } else { sel.item.addBtn.click(); } } await sleep(ADD_DELAY_MS); } } statusEl.textContent = `✅ Done! Added ${totalClicks} items ($${bestResult.total.toFixed(2)}) to cart.`; addBtnEl.textContent = 'Added!'; addBtnEl.style.background = '#2b8a3e'; }); } // ── Init ── function init() { if (document.querySelectorAll('[role="group"][aria-label="product card"]').length > 0) { createUI(); } else { setTimeout(init, 1000); } } if (document.readyState === 'complete') init(); else window.addEventListener('load', init); })();

--- 第 79 楼来自 Pika123 的回复 (2026-04-01 20:21:28 PDT) ---

辛苦了!

--- 第 80 楼来自 Potato 的回复 (2026-04-02 05:54:30 PDT) ---

我之前在学校旁边超市pickup当午餐,一个寿司9.9,为了凑到10,买了一根香蕉,选的replacement来问我,结果去pickup发现寿司cancelled,等了10分钟取了一根香蕉。呵呵哒。

--- 第 81 楼来自 Potato 的回复 (2026-04-02 06:00:09 PDT) ---

且不说有些地区现在有regulatory fee,就算没有fee的时候,要么要凑单,有些人不给小费愧疚每单要给个几块钱的小费,加上平台的fee跟可能的溢价,四舍五入下来真的没省钱,至于说方便或者省事,$10太少了,其他照样是要买的,如果几十刀都在instacart买,买的越多fee越多溢价越高,再加上品控问题,shopper时不时给你这个找不到那个弄错了,确实不省心。还有就是跟周边的超市有关,比如我的买菜习惯是生鲜whole foods+微波零食trader joes+中国菜wee,这里面本来就没有instacart什么事了。如果是30刀credit那二话不说就是用,折腾来折腾去为了几块钱嫌麻烦。

--- 第 82 楼来自 xxxyyy 的回复 (2026-04-02 06:05:17 PDT) ---

还好你是pickup,不然自己付fee + tips怎么也得四五刀,最后只能拿到香蕉

--- 第 83 楼来自 Pika123 的回复 (2026-04-02 09:30:01 PDT) ---

Instacart不时刻留意的确如此。 10块钱香蕉好吃吗?