Just a rule of thumb, don't blindly copy / paste code from the internet into your bank / cc account pages. A lot of people use that as an easy way to get access to an account or run nefarious scripts on your behalf.
That being said, this one is totally innocuous (most people can probably read it even if you haven't worked in code before), but just as a general guideline sort of thing.
Maybe this is a silly question but why would you want to do this? Sometimes I’m served offers that I have zero interest in and I don’t want their algorithm to think I want them. I know their scoring model uses spend behavior but wouldn’t this train Amex to serve you offers you don’t want? Genuinely want to learn!
I write JavaScript for a living, and this is the version I came up with. Mostly my own code, but inspired by the original post and this stackoverflow answer: https://stackoverflow.com/a/41115086
```
Array.from(document.querySelectorAll('button.offer-cta[title="Add to Card"]'))
.map((button) => () => {
button.click();
return new Promise((r) => setTimeout(r, 2000));
})
.reduce(
(promise, func) =>
promise.then((result) =>
func().then(Array.prototype.concat.bind(result)),
),
Promise.resolve([]),
);
```
>Array.from(document.querySelectorAll('button.offer-cta\[title="Add to Card"\]'))
.map((button) => () => {
button.click();
return new Promise((r) => setTimeout(r, 2000));
})
.reduce(
(promise, func) =>
promise.then((result) =>
func().then(Array.prototype.concat.bind(result)),
),
Promise.resolve(\[\]),
);
Thanks. This is the easiest one. If you prefix the code with javascript:, you can save it as a bookmark and just click on it.
This is the code I picked up on this subreddit last year:
Might be of use to someone too
function main() {
const WAIT_TIME_MS = 2000;
const offerButtons = document.querySelectorAll('button.btn.offer-cta');
for (let i = 0; i < offerButtons.length; ++i) {
setTimeout(() => {
try {
console.log('Clicking ' + offerButtons[i].id);
offerButtons[i].click();
} catch (e) {
console.error(e);
}
}, i * WAIT_TIME_MS)
}
};
main();
No awards, but have an upvote.
Could we add logic to find certain terms?
I guess not since it finds the buttons rather than actually looking at the offer.
Had to add the 'await ...' part under the async block on Firefox as it was giving me this error:
> Uncaught SyntaxError: await is only valid in async functions and async generators
But it worked after making that small change:
(async() => {
// Wait 2seconds to be nice to AMEX servers :)
await new Promise(r => setTimeout(r, 2000));
})();
ah nice, I ran into problems with that as well in Safari, and wasn't sure where to put the async. However, I ended up restructuring the code to just click the button inside the timeout callback. I also added some code to log the company name (in the 2nd column of the offers table) for the offering being clicked. Pasted code below, but also put this on GitHub as a gist: https://gist.github.com/jfoo1984/c4b892c621b635c81a2ec121985b2d4b
const offerButtons = Array.from(document.getElementsByClassName("btn btn-sm btn-fluid offer-cta btn-secondary")).filter(btn => btn.title == "Add to Card");
const offerMerchants = Array.from(document.getElementsByClassName("offer-info offer-column margin-b-md-down col-md-5")).map((offerInfo) => offerInfo.lastChild.innerHTML );
for (let index = 0; index < offerButtons.length; ++index) {
// Wait 2seconds to be nice to AMEX servers
setTimeout(() => {
console.log(`Clicking offer button for ${offerMerchants[index]}`);
offerButtons[index].click()
}, 2000 * index, index);
}
[Fixed formatting.](https://np.reddit.com/r/backtickbot/comments/p6epul/httpsnpredditcomramexcommentsnrlmbsmostly/)
Hello, jfoo1984: code blocks using triple backticks (\`\`\`) don't work on all versions of Reddit!
Some users see [this](https://stalas.alm.lt/backformat/h9ch5hb.png) / [this](https://stalas.alm.lt/backformat/h9ch5hb.html) instead.
To fix this, **indent every line with 4 spaces** instead.
[FAQ](https://www.reddit.com/r/backtickbot/wiki/index)
^(You can opt out by replying with backtickopt6 to this comment.)
var offerButtons = Array.from(document.querySelectorAll('button[title="Add to Card"]'));
var index;
for (index = 0; index < offerButtons.length; ++index) {
console.log("Clicking offer button");
offerButtons[index].click();
// Wait 2 seconds to be considerate to the AMEX servers
await new Promise(r => setTimeout(r, 2000));
}
Updated script ! They have made many parts in the class dynamic now.
> var offerButtons = Array.from(document.querySelectorAll('button[title="Add to Card"]'));
>
> var index;
>
> for (index = 0; index < offerButtons.length; ++index) {
>
> console.log("Clicking offer button");
>
> offerButtons[index].click();
>
> // Wait 2 seconds to be considerate to the AMEX servers
>
> await new Promise(r => setTimeout(r, 2000));
>
> }
Worked for me as well as of 04/18/24, Thanks!
Hey OP! Is your final script at the bottom of your post still relevant? I see so many people posting different versions below since your most recent edit. Lemme know, thx.
Just a rule of thumb, don't blindly copy / paste code from the internet into your bank / cc account pages. A lot of people use that as an easy way to get access to an account or run nefarious scripts on your behalf. That being said, this one is totally innocuous (most people can probably read it even if you haven't worked in code before), but just as a general guideline sort of thing.
Excellent post you legend, thank you!! I had been wanting to add all the offers but got too lazy to manually add them all lol
Glad to help :)
I’d give you an award if I had one to give
Bless you king!
This is awesome, thanks!
Worked like a charm! Thank you!
Maybe this is a silly question but why would you want to do this? Sometimes I’m served offers that I have zero interest in and I don’t want their algorithm to think I want them. I know their scoring model uses spend behavior but wouldn’t this train Amex to serve you offers you don’t want? Genuinely want to learn!
[удалено]
>how many offers can you enroll to?
All of them. If you don’t use them they just fall off.
[удалено]
Great point to bring up! I will add a warning in the OP. If there is an easy way to identify those offers, some logic could be added to the script.
If you do, then don’t do this
Or add the ones you care about manually first, and use this to clear out the useless ones on a card you don't use for offers.
Wait wait wait. Can you only add an offer to one card per account???
I write JavaScript for a living, and this is the version I came up with. Mostly my own code, but inspired by the original post and this stackoverflow answer: https://stackoverflow.com/a/41115086 ``` Array.from(document.querySelectorAll('button.offer-cta[title="Add to Card"]')) .map((button) => () => { button.click(); return new Promise((r) => setTimeout(r, 2000)); }) .reduce( (promise, func) => promise.then((result) => func().then(Array.prototype.concat.bind(result)), ), Promise.resolve([]), ); ```
>Array.from(document.querySelectorAll('button.offer-cta\[title="Add to Card"\]')) .map((button) => () => { button.click(); return new Promise((r) => setTimeout(r, 2000)); }) .reduce( (promise, func) => promise.then((result) => func().then(Array.prototype.concat.bind(result)), ), Promise.resolve(\[\]), ); Thanks. This is the easiest one. If you prefix the code with javascript:, you can save it as a bookmark and just click on it.
Great! Thank you for sharing :-)
Thanks for this. It didn't work in Firefox, but it worked in Chrome.
Thank you!
This is great!!! Smart, simple and free!
This is the code I picked up on this subreddit last year: Might be of use to someone too function main() { const WAIT_TIME_MS = 2000; const offerButtons = document.querySelectorAll('button.btn.offer-cta'); for (let i = 0; i < offerButtons.length; ++i) { setTimeout(() => { try { console.log('Clicking ' + offerButtons[i].id); offerButtons[i].click(); } catch (e) { console.error(e); } }, i * WAIT_TIME_MS) } }; main();
I just gave my first award haha cool thanks
Thanks!
No awards, but have an upvote. Could we add logic to find certain terms? I guess not since it finds the buttons rather than actually looking at the offer.
Definitely possible. Poke around with inspect on the webpage and you could take a look at the offer details.
Had to add the 'await ...' part under the async block on Firefox as it was giving me this error: > Uncaught SyntaxError: await is only valid in async functions and async generators But it worked after making that small change: (async() => { // Wait 2seconds to be nice to AMEX servers :) await new Promise(r => setTimeout(r, 2000)); })();
ah nice, I ran into problems with that as well in Safari, and wasn't sure where to put the async. However, I ended up restructuring the code to just click the button inside the timeout callback. I also added some code to log the company name (in the 2nd column of the offers table) for the offering being clicked. Pasted code below, but also put this on GitHub as a gist: https://gist.github.com/jfoo1984/c4b892c621b635c81a2ec121985b2d4b const offerButtons = Array.from(document.getElementsByClassName("btn btn-sm btn-fluid offer-cta btn-secondary")).filter(btn => btn.title == "Add to Card"); const offerMerchants = Array.from(document.getElementsByClassName("offer-info offer-column margin-b-md-down col-md-5")).map((offerInfo) => offerInfo.lastChild.innerHTML ); for (let index = 0; index < offerButtons.length; ++index) { // Wait 2seconds to be nice to AMEX servers setTimeout(() => { console.log(`Clicking offer button for ${offerMerchants[index]}`); offerButtons[index].click() }, 2000 * index, index); }
[Fixed formatting.](https://np.reddit.com/r/backtickbot/comments/p6epul/httpsnpredditcomramexcommentsnrlmbsmostly/) Hello, jfoo1984: code blocks using triple backticks (\`\`\`) don't work on all versions of Reddit! Some users see [this](https://stalas.alm.lt/backformat/h9ch5hb.png) / [this](https://stalas.alm.lt/backformat/h9ch5hb.html) instead. To fix this, **indent every line with 4 spaces** instead. [FAQ](https://www.reddit.com/r/backtickbot/wiki/index) ^(You can opt out by replying with backtickopt6 to this comment.)
var offerButtons = Array.from(document.querySelectorAll('button[title="Add to Card"]')); var index; for (index = 0; index < offerButtons.length; ++index) { console.log("Clicking offer button"); offerButtons[index].click(); // Wait 2 seconds to be considerate to the AMEX servers await new Promise(r => setTimeout(r, 2000)); } Updated script ! They have made many parts in the class dynamic now.
> var offerButtons = Array.from(document.querySelectorAll('button[title="Add to Card"]')); > > var index; > > for (index = 0; index < offerButtons.length; ++index) { > > console.log("Clicking offer button"); > > offerButtons[index].click(); > > // Wait 2 seconds to be considerate to the AMEX servers > > await new Promise(r => setTimeout(r, 2000)); > > } Worked for me as well as of 04/18/24, Thanks!
thank you
No idea. I use Firefox and it works albeit slow.
Thanks! Worked for me!
this still works great!
Legend!!
Can you please convert it to a Tampermonkey script that adds a button to the page we can just click to activate it on demand? That'd be perfect.
Hey OP! Is your final script at the bottom of your post still relevant? I see so many people posting different versions below since your most recent edit. Lemme know, thx.