Joined Jun 2005
L8: Grand Teacher
Popular

Grocery store coupon clipping automation (Mperks, Kroger, publix etc..) using JavaScript (similar to the Amex offers Javascript)
April 10, 2025 at
10:15 AM
in
Grocery
(5)
Meijer
Deal Details
Last Edited by Cobalt_Blue_FF August 7, 2025 at 01:18 PM
Similar to the Amex offers JavaScript that you can bookmark and run to clip all offers, I crafted one that works for Meijer Mperks. Note that Mperks has a limit of 160 coupons clipped per their TOC, so I added a clip limit of 160 to the code . It was not real clear if that is how many you can clip per x amount of time or the total number of clipped coupons.
Either way, I found it threw an error after clipping a bunch of them. But it did work!
Also, here is a direct link to your handpicked offers, it is not always obvious when these are available.
https://www.meijer.com/shopping/c...ffers.html
Mods please delete if this is not allowed to be posted. Thanks!
Just create a new bookmark, and add this code as the webpage. Then click it while on the Amex offers or Mperks coupon pages
Enjoy!
I am adding all new stores to the wiki
Update: See Wiki for most up to date list
Either way, I found it threw an error after clipping a bunch of them. But it did work!
Also, here is a direct link to your handpicked offers, it is not always obvious when these are available.
https://www.meijer.com/shopping/c...ffers.html
Mods please delete if this is not allowed to be posted. Thanks!
Just create a new bookmark, and add this code as the webpage. Then click it while on the Amex offers or Mperks coupon pages
Enjoy!
I am adding all new stores to the wiki
Update: See Wiki for most up to date list
Community Wiki
Last Edited by Cobalt_Blue_FF
September 4, 2025
at
01:57 PM
JavaScript Clipping Bookmarklets for Grocery & Rewards Sites
- Mperks Clipper
Clicks up to 160 coupons with a short delay between each.- To change how many coupons it tries to clip, edit: clipLimit=160
- To adjust the click delay speed, edit: Math.random()*300+100
Code:javascript:(function(){var clipBtns=[...document.querySelectorAll('button.coupon-tile__button--clip[aria-label*="Clip"]')];console.log('Found '+clipBtns.length+' clip buttons');if(clipBtns.length===0){alert('No clip buttons found!');return;}var clipLimit=160;var index=0;function clipNext(){if(index>=clipBtns.length||clipLimit<=0){alert('Clipping complete! Processed '+index+' coupons.');return;}var btn=clipBtns[index];if(btn&&btn.offsetParent!==null){btn.click();console.log('Clipped coupon '+(index+1)+'/'+clipBtns.length);clipLimit--;}index++;setTimeout(clipNext,Math.random()*300+100);}clipNext();})();
- Mperks Unclipper
Unclips already clipped coupons. Useful for removing unwanted clipped coupons to filter out deals you don't want and stay under the 160 coupon limit.- To change how many coupons it tries to unclip, edit: unclipLimit=160
- To adjust the timing, edit: Math.random()*200+100 (next coupon delay) or 300 (detail view wait)
Code:javascript:(function(){var unclipBtns=[...document.querySelectorAll('button.coupon-tile__button--unclip[aria-label*="Shop"]')];console.log('Found '+unclipBtns.length+' clipped coupons to unclip');if(unclipBtns.length===0){alert('No clipped coupons found!');return;}var unclipLimit=160;var index=0;function unclipNext(){if(index>=unclipBtns.length||unclipLimit<=0){alert('Unclipping complete! Processed '+index+' coupons.');return;}var btn=unclipBtns[index];if(btn&&btn.offsetParent!==null){btn.click();console.log('Opening coupon detail '+(index+1)+'/'+unclipBtns.length);setTimeout(function(){var unclipDetailBtn=document.querySelector('button.coupon-detail-view__unclip-btn');if(unclipDetailBtn){unclipDetailBtn.click();console.log('Unclipped coupon '+(index+1)+'/'+unclipBtns.length);}else{console.log('Unclip detail button not found for coupon '+(index+1));}unclipLimit--;index++;setTimeout(unclipNext,Math.random()*200+100);},300);}else{index++;unclipNext();}}unclipNext();})();
- Amex Offers Clipper
Adds all "Add to Card" offers with a short random delay between each.- To adjust delay speed, change the delay function inside the code (currently Math.random()*500+200)
Code:javascript:(function(){var R=Math.random;function realClick(el){try{if(window.PointerEvent){el.dispatchEvent(new PointerEvent('pointerdown',{bubbles:true}));el.dispatchEvent(new PointerEvent('pointerup',{bubbles:true}))}if('ontouchstart'in window){var t=document.createEvent('Event');t.initEvent('touchstart',true,true);el.dispatchEvent(t);var t2=document.createEvent('Event');t2.initEvent('touchend',true,true);el.dispatchEvent(t2)}['mousedown','mouseup','click'].forEach(function(type){el.dispatchEvent(new MouseEvent(type,{bubbles:true,cancelable:true,view:window}))})}catch(e){try{el.click()}catch(_){}}}function visible(e){return e&&e.offsetParent!==null}function collect(){var q=Array.from(document.querySelectorAll('[data-testid="merchantOfferAddButton"]'));if(q.length)return q;var all=Array.from(document.querySelectorAll('button,a,span[role="button"],div[role="button"]'));return all.filter(function(b){var t=(b.textContent||'').trim();return /^(Add to Card|Add Offer|Enroll)$/i.test(t)})}var btns=collect().filter(function(b){return visible(b)&&b.getAttribute('aria-disabled')!=='true'&&!b.disabled});if(!btns.length){alert('Amex Clipper: no add/enroll buttons found');return}var i=0,limit=btns.length,delay=function(){return R()*500+200};console.log('Amex Clipper: found '+btns.length+' buttons');(function next(){if(i>=limit){alert('Amex Clipper: finished '+i+' offers');return}var b=btns[i++];try{b.scrollIntoView({block:'center'})}catch(_){}var target=b.closest('[data-testid="merchantOfferAddButton"],button,[role="button"]')||b;realClick(target);console.log('Amex Clipper: added '+i+'/'+limit);setTimeout(next,delay())})()})();
- Kroger
Clicks all "Clip" buttons instantly.- No adjustable values.
Code:javascript:[...document.querySelectorAll('button[aria-label*="Clip"]')].forEach(btn => btn.click());
- Kroger (Without Boost Coupons)
Same as above, but skips Boost-exclusive coupons.- No adjustable values.
Code:javascript:[...document.querySelectorAll('button[aria-label*="Clip"]')].filter(btn => !btn.textContent.includes("Boost")).forEach(btn => btn.click());
- Publix
Clicks all coupon buttons instantly.- No adjustable values.
Code:javascript:(function(){document.querySelectorAll('.p-coupon-button__label').forEach(button => button.click());})();
- Winn-Dixie
Clicks coupons with a small random delay between each.- To adjust delay speed, change: Math.random()*300
Code:javascript:btns=[...document.querySelectorAll('span[id^="cpnSpan_"]')];c=()=>{b=btns.shift();if(!b)return;b.click();setTimeout(c,Math.random()*300)};c();
- H-E-B
Clips only buttons labeled "Clip" with delay between clicks.- To adjust delay speed, change: Math.random()*300
Code:javascript:btns=[...document.querySelectorAll('span.ButtonLabel_buttonLabel__z680Q')].filter(btn=>btn.textContent.trim()==='Clip');c=()=>{b=btns.shift();if(!b)return;b.click();setTimeout(c,Math.random()*300)};c();
- Kroger Cash Back
Clips Kroger Cash Back offers with a delay between each.- To adjust delay speed, change: Math.random()*300
Code:javascript:btns=[...document.querySelectorAll('button[data-testid^="CouponActionButton-"]')];c=()=>{b=btns.shift();if(!b)return;b.click();setTimeout(c,Math.random()*300)};c();
- Ibotta
Clips a limited number of offers with random delays to prevent account lockouts.- View your Ibotta items here: https://ibotta.com/retailers/
- To change how many offers are clipped, edit: limit=5
- To change the random delay range, edit:
• 1250 = randomness (range of delay in ms)
• 250 = minimum delay in ms
Code:javascript:(()=>{let btns=[...document.querySelectorAll('span.p-btn__icon.p-btn__icon-middle.p-btn__icon--plus')],limit=5;const c=()=>{if(limit<=0||btns.length===0)return;let b=btns.shift();b.click();limit--;setTimeout(c,Math.random()*1250+250)};c();})()
- Ralphs
Clips all coupon buttons with delay to prevent rate limiting. (Uses Kroger infrastructure)- Start at: https://www.ralphs.com/savings/cl/coupons/
- To adjust delay speed, change: Math.random() * 500 + 200
- Includes alert if no coupons found
Code:javascript:btns=[...document.querySelectorAll('button, a, [role="button"]')].filter(b => {const text = b.textContent?.trim() || ''; const ariaLabel = b.getAttribute('aria-label') || ''; return text === 'Clip' || text === 'Add Coupon' || ariaLabel.includes('Clip') || ariaLabel.includes('Add Coupon');});c=()=>{ b = btns.shift(); if (!b) return; b.click(); setTimeout(c, Math.random() * 500 + 200) };if(btns.length > 0) c(); else alert('No coupon buttons found');
- Citi Offers
Clicks the plus icon to add all available offers. It uses a random delay between clicks to mimic human interaction.- To adjust delay speed, change: Math.random()*500+200
Code:javascript:btns=[...document.querySelectorAll('svg path[d^="M12 4.2a"]')].map(p=>p.closest('button, [role="button"]')).filter(b=>b&&b.offsetParent!==null);if(!btns.length){alert('No Citi offer buttons found.');}else{let count=btns.length;c=()=>{b=btns.shift();if(!b){alert('Finished adding '+count+' Citi offers.');return;}b.click();setTimeout(c,Math.random()*500+200)};c();}
- Chase Offers Auto-Adder Bookmarklet
This bookmarklet automatically adds all available Chase credit card offers to your account.
How to use:
1. Create a new bookmark in your browser
2. Name it "Chase Auto Offers" or something similar
3. Instead of a URL, copy and paste the ENTIRE code from the Pastebin link below into the URL/location field
4. Go to the Chase website and log in
5. Navigate to your offers page
6. Click the bookmarklet to run it
Pastebin Link (Recommended Method):
https://pastebin.com/raw/5j5CTFUg
Alternative Method - Code (Not Recommended):
Code:javascript:void(async function(){try{const c={ALL_OFFERS_URL:"https://secure.chase.com/web/auth/dashboard#/dashboard/merchantOffers/offerCategoriesPage?offerCategoryName=ALL",readinessTimeout:18e3,readinessPoll:400,detailObserveTotal:9e3,detailObservePoll:400,inlineTimeout:5200,poll:420,betweenOffers:450,detailBackDelay:1300,postReturnSettle:900,maxPerTileAttempts:3,maxPasses:8,pauseAfterReturn:800},p=new Set(["M24.07 4.34c-11.046 0-20 8.954-20 20s8.954 20 20 20 20-8.954 20-20c-.011-11.041-8.959-19.989-20-20m0 37c-9.389 0-17-7.611-17-17s7.611-17 17-17 17 7.611 17 17c-.013 9.383-7.617 16.987-17 17","M33.62 24.04a1.5 1.5 0 0 1-1.5 1.5h-6.53l-.02 6.52a1.5 1.5 0 0 1-3-.01l.02-6.51h-6.47a1.5 1.5 0 1 1 0-3h6.48l.02-6.51a1.5 1.5 0 0 1 1.5-1.49h.01a1.5 1.5 0 0 1 1.49 1.5l-.02 6.5h6.52a1.5 1.5 0 0 1 1.5 1.5"]),a=new Map;let n=1;function s(e,t=4e3){let o=document.getElementById("chase-offer-notifier");o||(o=document.createElement("div"),o.id="chase-offer-notifier",Object.assign(o.style,{position:"fixed",top:"20px",right:"20px",backgroundColor:"#0070ba",color:"white",padding:"15px 25px",borderRadius:"8px",boxShadow:"0 4px 12px rgba(0,0,0,0.2)",zIndex:"99999",fontSize:"16px",fontFamily:"sans-serif",opacity:"0",transition:"opacity 0.5s ease-in-out, top 0.5s ease-in-out"}),document.body.appendChild(o)),o.textContent=e,setTimeout(()=>{o.style.top="20px",o.style.opacity="1"},50),t>0&&setTimeout(()=>{o.style.top="0px",o.style.opacity="0"},t)}const d=()=>Array.from(document.querySelectorAll('div[data-testid="commerce-tile"]')),f=()=>/offerCategoriesPage.*offerCategoryName=ALL/i.test(location.href),h=()=>/offer-activated|offer-detail/i.test(location.href),u=()=>/offer-activated/i.test(location.href);function i(e){return e.dataset.offerAutoId||(e.dataset.offerAutoId="o_"+n++),e.dataset.offerAutoId}function l(e){return Array.from(e.querySelectorAll("path")).some(e=>p.has(e.getAttribute("d")))}function g(e){return Array.from(e.querySelectorAll('button,[role="button"]')).some(e=>{const t=(e.innerText||"")+" "+(e.getAttribute("aria-label")||"");return/add offer|activate|add to card/i.test(t.toLowerCase())})}function m(e){if(!e)return"";let t=e.match(/^\s*\d+\s+of\s+\d+\s+(.+?)\s+(?:\d+%|\$\d+)/);if(t)return t[1].trim();if(t=e.match(/^\s*\d+\s+of\s+\d+\s+(.+?)\s+Add offer/i))return t[1].trim();if(t=e.match(/^\s*\d+\s+of\s+\d+\s+(.+?)\s+(?:\d+%|\$\d+)\s+cash back/i))return t[1].trim();return e.split(/Add offer|Added|Success Added/i)[0].replace(/^\s*\d+\s+of\s+\d+\s+/,"").trim()||""}function b(e){const t=e.getAttribute("aria-label")||"",o=m(t),r=/(Added|Success Added)\s*$/i.test(t.trim()),a=/add offer/i.test(t)||l(e)||g(e);return{merchant:o,added:r,addableSignal:a}}async function w(){f()||(location.href=c.ALL_OFFERS_URL,await new Promise(e=>setTimeout(e,1100))),f()||(location.assign(c.ALL_OFFERS_URL),await new Promise(e=>setTimeout(e,1500)))}async function T(e=1){const t=Date.now();for(;Date.now()-t=e)return!0;await new Promise(e=>setTimeout(e,c.readinessPoll))}return!1}async function A(e){if(!e)return;e.scrollIntoView({block:"center"}),await new Promise(e=>setTimeout(e,200));try{e.focus({preventScroll:!0})}catch(e){}for(const t of["mouseover","mousedown","mouseup","click"])e.dispatchEvent(new MouseEvent(t,{bubbles:!0,cancelable:!0,view:window}))}function O(){return!!h()||(!!document.querySelector('#back-button, .navigation-bar__back-button, button[aria-label*="Back" i], button[aria-label*="Close" i]')||Array.from(document.querySelectorAll('button,[role="button"]')).some(e=>{const t=(e.innerText||"")+" "+(e.getAttribute("aria-label")||"");return/add offer|activate|add to card/i.test(t.toLowerCase())&&!e.closest('div[data-testid="commerce-tile"]')}))}function y(){return Array.from(document.querySelectorAll('button,[role="button"]')).find(e=>{const t=(e.innerText||"")+" "+(e.getAttribute("aria-label")||"");return/add offer|activate|add to card/i.test(t.toLowerCase())&&!/added/i.test(t.toLowerCase())&&!e.disabled})}function S(){return!!u()||(!!Array.from(document.querySelectorAll('[aria-live], [role="status"]')).some(e=>/added/i.test(e.textContent||"")&&!/add offer/i.test(e.textContent||""))||Array.from(document.querySelectorAll('button,[role="button"]')).some(e=>{const t=(e.innerText||"")+" "+(e.getAttribute("aria-label")||"");return/added/i.test(t)&&!/add offer/i.test(t)}))}async function v(){const e=Date.now();for(;Date.now()-esetTimeout(e,c.detailObservePoll))}return S()}async function k(){if(S())return{status:"already"};for(let e=1;e<=3;e++){const e=y();if(e){if(await A(e),await v())return{status:"added"}}else if(S())return{status:"added"};await new Promise(e=>setTimeout(e,500))}return S()?{status:"added"}:{status:"unconfirmed"}}async function E(){const e=document.querySelector('#back-button, .navigation-bar__back-button, button[aria-label*="Back" i], button[aria-label*="Close" i]');e?(await A(e),await new Promise(e=>setTimeout(e,700)),O()&&history.back()):history.back(),await new Promise(e=>setTimeout(e,c.pauseAfterReturn)),await T(1),await new Promise(e=>setTimeout(e,c.postReturnSettle))}function C(e){return a.get(i(e))||0}function R(e){const t=i(e);a.set(t,C(e)+1)}function L(e){return e.querySelector('button,[role="button"],a,div[onclick],span[onclick],div[tabindex]')||e}async function P(e){const t=Date.now();for(;Date.now()-t<3e3;){if(d().some(t=>{const o=b(t);return o.merchant===e&&o.added}))return!0;await new Promise(e=>setTimeout(e,250))}return!1}async function j(e,t){e.dispatchEvent(new MouseEvent("mouseenter",{bubbles:!0})),await new Promise(e=>setTimeout(e,90));const o=b(e);if(o.added)return{status:"already"};if(!o.addableSignal&&!t)return{status:"skip"};if(C(e)>=c.maxPerTileAttempts)return{status:"exhausted"};R(e),await A(L(e));const r=Date.now();for(;Date.now()-rsetTimeout(e,c.poll)),O())break;if(!e.isConnected)return{status:"ambiguous"};if(b(e).added)return{status:"added"}}if(O()){await new Promise(e=>setTimeout(e,c.detailBackDelay));const t=await k();return"added"===t.status||"already"===t.status?(await E(),await P(o.merchant),{status:"added"}):(await E(),{status:"unconfirmed"})}return{status:"ambiguous"}}async function M(){let e=0,t=!1;for(let o=1;o<=c.maxPasses;o++){let r=!1,a=new Set,n=!0;for(;n;){if(!d().length&&await T(1),!(h=d().find(e=>!a.has(i(e))))){n=!1;break}a.add(i(h)),b(h).added||(u=await j(h,t),"added"===u.status&&(e++,r=!0),await new Promise(e=>setTimeout(e,c.betweenOffers)))}var h,u;const l=d().filter(e=>!b(e).added).length;if(0===l)return void s(`Complete! Added ${e} offers.`,5e3);if(!r){if(t)return void s(`Stalled. Added ${e}. Remaining: ${l}.`,6e3);t=!0}}s(`Finished. Added ${e}. Remaining: ${d().filter(e=>!b(e).added).length}.`,6e3)}if(!/secure\.chase\.com/i.test(location.hostname))return void s("Error: Must be on a Chase.com page.",5e3);s("Starting Chase Offers Auto-Adder...",3e3),await w(),await T(1)?(d().forEach(i),await M()):s("Error: Could not find any offers on the page.",5e3)}catch(e){console.error("Chase Offers Script Failed:",e),s(`Script Error: ${e.message}. See console.`,8e3)}})();
Special characters in the code above will be converted by the forum software, making the bookmarklet NOT work if copied directly from here. You have two options:
1. Recommended: Use the Pastebin link above to get the full, working code
2. Alternative: Edit this wiki post, click "Edit" and then copy the code from inside the code tags in the editor (NOT from the rendered view)
Details:
This bookmarklet navigates to your Chase offers page and automatically adds all available offers to your account. It includes intelligent retries and progress notifications. - More Coming Soon
Add additional store names below to request new bookmarklets.
46 Comments
Your comment cannot be blank.
Sign up for a Slickdeals account to remove this ad.
Either way, I found it threw an error after clipping a bunch of them. But it did work!
Also, here is a direct link to your handpicked offers, it is not always obvious when these are available.
https://www.meijer.com/shopping/c...ffers.html
Mods please delete if this is not allowed to be posted. Thanks!
Just create a new bookmark, and add this code as the webpage. Then click it while on the Amex offers or Mperks coupon pages
Enjoy!
I am adding all new stores to the wiki
Mperks Clipper:
I'm also looking for the Publix one (https://www.publix.com/savings/di...nav=header) mentioned in the comments and if still taking requests one for Winn-Dixie (https://www.winndixie.c
perplexity.ai fails miserably at trying to make one of these for renfroes market. I'm also curious if we can modify the url so all coupons show on 1 page instead of multiple.
It generated: javascript: (function() {
document.querySelectorAll('a.coupon-item-button:contains("Add")').forEach(function(a) {
a.click();
});
})();
which doesn't seem to do anything.
Sign up for a Slickdeals account to remove this ad.
Everytime before I go to Bj's, I just run this and all the coupons are clipped. It's like magic!
A lot of coupons are 1x per day, so the next time you want to use it, you have to clip it again.
https://greasyfork.org/en/scripts...on-clicker [greasyfork.org]
I'm also looking for the Publix one (https://www.publix.com/savings/di...nav=header) mentioned in the comments and if still taking requests one for Winn-Dixie (https://www.winndixie.c
perplexity.ai fails miserably at trying to make one of these for renfroes market. I'm also curious if we can modify the url so all coupons show on 1 page instead of multiple.
It generated: javascript: (function() {
document.querySelectorAll('a.coupon-item-button:contains("Add")').forEach(function(a) {
a.click();
});
})();
which doesn't seem to do anything.
Our community has rated this post as helpful. If you agree, why not thank Fuwapa
Sign up for a Slickdeals account to remove this ad.
On the Meijer page displaying the coupons, scroll down to the bottom and click "Load More". Scroll down to the bottom and hit "Load More" again. Do it a few times, and keep expanding the page. Then, clicking the bookmarked Java scripts should clip many more coupons at a time.