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.
I noticed it only clips what is showing on the screen, I simply refreshed the screen and clicked the shortcut code button again. I believe I did that 3 times before I was maxed out
Thanks! I have updated the Wiki. Please let me know if it looks better now.
You will get a red warning message on the screen once you hit the limit, and no new coupons can be clicked until it is reset (~1 minute or so). Enjoy!
Sign up for a Slickdeals account to remove this ad.
https://github.com/onlyLogicalSens
Sign up for a Slickdeals account to remove this ad.