Skip to content

Instantly share code, notes, and snippets.

@jef
Last active July 29, 2022 15:28
Show Gist options
  • Star 41 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save jef/96fd50c6fe3eedc1bdf52585eac2b3c4 to your computer and use it in GitHub Desktop.
Save jef/96fd50c6fe3eedc1bdf52585eac2b3c4 to your computer and use it in GitHub Desktop.
const puppeteer = require("puppeteer");
const opn = require("opn");
const nodemailer = require("nodemailer");
const timeout = 5000;
const waitForTimeout = 1000;
const cartLink =
"https://store.nvidia.com/store/nvidia/en_US/buy/productID.5438481700/clearCart.yes/nextPage.QuickBuyCartPage";
const emailUsername = process.env.EMAIL_USERNAME;
const emailPassword = process.env.EMAIL_PASSWORD;
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: emailUsername,
pass: emailPassword,
},
});
const mailOptions = {
from: emailUsername,
to: emailUsername,
subject: "NVIDIA - BUY NOW",
text: cartLink,
};
async function buy() {
const links = [
"https://www.nvidia.com/en-us/geforce/buy/",
"https://www.nvidia.com/en-us/shop/geforce/?page=1&limit=9&locale=en-us&search=3080",
"https://www.bestbuy.com/site/nvidia-geforce-rtx-3080-10gb-gddr6x-pci-express-4-0-graphics-card-titanium-and-black/6429440.p?skuId=6429440",
];
for (const link of links) {
await goto(link);
}
setTimeout(buy, timeout);
}
async function goto(link) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setUserAgent(
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
);
page.setViewport({
width: 1920,
height: 1080,
});
await page.goto(link);
await page.waitFor(waitForTimeout);
const dom = await page.evaluate(() => {
return {
body: document.body.innerText,
};
});
console.log(dom);
if (dom.body.toLowerCase().includes("out of stock") || dom.body.toLowerCase().includes("sold out")) {
console.log("still out of stock, will try again.");
} else {
console.log("*** IN STOCK, BUY NOW ***");
await page.screenshot({ path: `nvidia-${Date.now()}.png` });
opn(cartLink);
if (emailUsername && emailPassword) {
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
console.log(error);
} else {
console.log("email sent: " + info.response);
}
});
}
}
await browser.close();
}
try {
buy();
} catch (error) {
buy();
}
@verchan
Copy link

verchan commented Sep 18, 2020

yeah i am trying to figure out the DE location but there is nothing :(
https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/products/de_de/EUR/5438481700
https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/get-inventory/de_de/5438481700?format=json&expand=availablequantity
Also here:
https://api.nvidia.partners/edge/product/search?page=1&limit=9&locale=de-de
It looks like Germany never had any to start with :/

I believe different regions have different product IDs. en_gb (UK) is different than ours in US, just an FYI

That's good to know, but if that's true it's pretty wired
image

I used the below link as buy link and its recognized
https://store.nvidia.com/store/nvidia/de_DE/buy/productID.5438481700/clearCart.yes/nextPage.QuickBuyCartPage

Has anyone figured out the product ID for the 3080 in the german store yet?
Since https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/get-inventory/de_de/5438481700?format=json&expand=availablequantity returns a 404 but works with other IDs like https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/get-inventory/de_de/5335703700?format=json&expand=availablequantity for a RTX 20 Series card there are definitively different IDs in place but I cannot seem to find the right endpoint to search for them :(

@alekthex
Copy link

@EricSciullo Exactly what I meant, because the opn() call right now opens up cartLink if it finds a buy button right? So if I want it to scan a bunch of links and open the one that has the buy button I would just change it to opn(link) is that correct?

@MGraefe
Copy link

MGraefe commented Sep 18, 2020

yeah i am trying to figure out the DE location but there is nothing :(
https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/products/de_de/EUR/5438481700
https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/get-inventory/de_de/5438481700?format=json&expand=availablequantity
Also here:
https://api.nvidia.partners/edge/product/search?page=1&limit=9&locale=de-de
It looks like Germany never had any to start with :/

I believe different regions have different product IDs. en_gb (UK) is different than ours in US, just an FYI

That's good to know, but if that's true it's pretty wired
image
I used the below link as buy link and its recognized
https://store.nvidia.com/store/nvidia/de_DE/buy/productID.5438481700/clearCart.yes/nextPage.QuickBuyCartPage

Has anyone figured out the product ID for the 3080 in the german store yet?
Since https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/get-inventory/de_de/5438481700?format=json&expand=availablequantity returns a 404 but works with other IDs like https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/get-inventory/de_de/5335703700?format=json&expand=availablequantity for a RTX 20 Series card there are definitively different IDs in place but I cannot seem to find the right endpoint to search for them :(

There are definetly different IDs, the "German" RTX 2080 Super ID (5335703700) returns a 404 in the en_us API. Might be the case that Germany never had an ID because we didn't get any FEs but Nvidia didn't want to admit it.

@verchan
Copy link

verchan commented Sep 18, 2020

I talked to a tech support guy on the phone yesterday and he said they estimated 2-3 days for the german stock to last...
But they had no idea what happened and did not get any infos from marketing if the stock really was gone in 1 second or the store had a problem.

@JohannesMP
Copy link

While including the best buy url in links to check is useful, opening/mailing cartLink if the best buy link shows stock seems somewhat pointless.

@jef
Copy link
Author

jef commented Sep 18, 2020

Moved over to a repository. Feel free to go from there.

https://github.com/jef/nvidia-snatcher

Discord is linked in README. File any issues or features you have in the ticket system.

Thanks all :)

@jef
Copy link
Author

jef commented Sep 18, 2020

opening/mailing cartLink if the best buy link shows stock seems somewhat pointless.

@JohannesMP, agreed. Working on getting a IDs to add directly to cart.

@anthonysparrow
Copy link

I made a couple changes to mine.

  1. I adjusted the Nvidia URL to include filters such that the 3080 was the only product on screen.
    https://www.nvidia.com/en-us/shop/geforce/gpu/?page=1&limit=9&locale=en-us&category=GPU&gpu=RTX%203080&manufacturer=NVIDIA&manufacturer_filter=NVIDIA~1,ASUS~1,EVGA~3,GIGABYTE~2,MSI~1,PNY~0,ZOTAC~0

  2. I adjusted the page load wait to be more fluid instead of a static 1s. It waits for the featured box class to load.
    await page.waitForSelector('.featured-container-xl');

  3. I adjusted the text that is being inspected to only be that of the featured box in order to be more precice
    body: document.querySelector('.featured-container-xl').innerText

It seems your false positives are coming from the best buy site as their "out of stock" button seems to change a little in verbiage.

@Valpertui
Copy link

If anyone find the digitalRiverID for the French nvidia store, please share :)

@jvice152
Copy link

@binury
Copy link

binury commented Sep 18, 2020

try {
  buy();
} catch (error) {
  buy();
}

😆

@dimi-kr
Copy link

dimi-kr commented Sep 18, 2020

If anyone find the digitalRiverID for the French nvidia store, please share :)

5438795200

@coolfarmer
Copy link

coolfarmer commented Sep 21, 2020

Anyone have the digitalRiverID for the french canadian store (or maybe just Canada) ? Damn god I'm looking to a lot of api call but I can't find it :/

@Coldi7
Copy link

Coldi7 commented Sep 21, 2020

Does anyone happen to have API Key that would work with GB store? It seems that my region FI/DN is in GB catalogue. I assume to find separate SKU for couple or regions in GB store.

@andrewmackrodt
Copy link

andrewmackrodt commented Sep 22, 2020

Does anyone happen to have API Key that would work with GB store? It seems that my region FI/DN is in GB catalogue. I assume to find separate SKU for couple or regions in GB store.

Add &locale=en_gb to the digital river query string for GB listings, there are no 3090 cards right now and 3080 are out of stock.

@smithers54
Copy link

I would just like to say thank you to you and everyone else that helped make this script. I was able to combat the bots and get a card through newegg!!

@tashrifsanil
Copy link

I tried looking for the digitialRiverId of the 3090 by filtering out the json output from this "https://api.nvidia.partners/edge/product/search?page=1&limit=9&locale=en-ca&category=GPU&manufacturer=NVIDIA&gpu=RTX%203090". But it wasn't updated and the card is now sold out :( If anyone finds the digitalriverid that'd be legendary. The hunt continues

@andrewmackrodt
Copy link

@tashrifsanil you can get it from the landing page e.g. inspect the source of https://www.nvidia.com/en-gb/geforce/graphics-cards/30-series/rtx-3090/ - change "en-gb" to whatever is correct for your locale. Query selector is: div[data-digital-river-id].

@tashrifsanil
Copy link

@andrewmackrodt Yeah I think I found it, I'm pretty sure it's "5438792700"

@tashrifsanil
Copy link

@andrewmackrodt My badd I was wrong, I got that ^^ id by looking at requests made in network tab. Your method returned a proper id "5438481600" (for the us site). Thanks!!

@tashrifsanil
Copy link

Does anyone have a better way to check for stock? I was sending a get request to https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481600 which would return a json response which would tell you inventory status, but now it doesn't work so well (error 503 - gateway times out).

Nvidia's own website makes the same website and now it fails there too, but eventually after a while the out of stock button pops up on their site. Do you guys think their website is setup so that if the request fails the out of stock button shows up? Or is their a better way to check for stock?

import requests

url = "https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481600"

payload = {}
headers = {
  'authority': 'api-prod.nvidia.com',
  'accept': 'application/json, text/javascript, */*; q=0.01',
  'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36',
  'dnt': '1',
  'origin': 'https://www.nvidia.com',
  'sec-fetch-site': 'same-site',
  'sec-fetch-mode': 'cors',
  'sec-fetch-dest': 'empty',
  'referer': 'https://www.nvidia.com/en-us/geforce/graphics-cards/30-series/rtx-3090/',
  'accept-language': 'en-CA,en-GB;q=0.9,en-US;q=0.8,en;q=0.7'
}

response = requests.request("GET", url, headers=headers, data = payload)

print(response.text.encode('utf8'))

@tashrifsanil
Copy link

Okay so the above worked ^^ but the card was scalped again before I could check out :(

@jgramling17
Copy link

Does anyone have a better way to check for stock? I was sending a get request to https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481600 which would return a json response which would tell you inventory status, but now it doesn't work so well (error 503 - gateway times out).

Nvidia's own website makes the same website and now it fails there too, but eventually after a while the out of stock button pops up on their site. Do you guys think their website is setup so that if the request fails the out of stock button shows up? Or is their a better way to check for stock?

import requests

url = "https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481600"

payload = {}
headers = {
  'authority': 'api-prod.nvidia.com',
  'accept': 'application/json, text/javascript, */*; q=0.01',
  'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36',
  'dnt': '1',
  'origin': 'https://www.nvidia.com',
  'sec-fetch-site': 'same-site',
  'sec-fetch-mode': 'cors',
  'sec-fetch-dest': 'empty',
  'referer': 'https://www.nvidia.com/en-us/geforce/graphics-cards/30-series/rtx-3090/',
  'accept-language': 'en-CA,en-GB;q=0.9,en-US;q=0.8,en;q=0.7'
}

response = requests.request("GET", url, headers=headers, data = payload)

print(response.text.encode('utf8'))

Do you have a sample of what the json response structure looks like?

@tashrifsanil
Copy link

@jgramling17 I'll put up the json response when it's not timing out anymore. Till then if it helps, converting the json response using json.loads() and using this is how I'm check for when it's in stock
json_resp["products"]["product"][0]["inventoryStatus"]["status"] != 'PRODUCT_INVENTORY_OUT_OF_STOCK'

@jcharnley
Copy link

jcharnley commented Oct 2, 2020

where do we get the api key from for the store?

the only endpoint I can hit is https://api.nvidia.partners/edge/product/search?page=1&limit=9&locale=en-gb&category=GPU&manufacturer=NVIDIA&gpu=RTX%203080, which doesnt show stock levels.

anyone got a digital rivers endpoint that is working please? am sick of refeshing for days and days and missing out. want to write my own script

@jgramling17
Copy link

@jgramling17 I'll put up the json response when it's not timing out anymore. Till then if it helps, converting the json response using json.loads() and using this is how I'm check for when it's in stock
json_resp["products"]["product"][0]["inventoryStatus"]["status"] != 'PRODUCT_INVENTORY_OUT_OF_STOCK'

Awesome, that should be good for now, thanks so much! I'm getting repeated 504s from their api endpoint as well. Hopefully it'll go up before they go on sale again. I noticed that the 3080 availability page is no longer hitting that endpoint, wonder if it only checks around the time of new inventory.

where do we get the api key from for the store?

the only endpoint I can hit is https://api.nvidia.partners/edge/product/search?page=1&limit=9&locale=en-gb&category=GPU&manufacturer=NVIDIA&gpu=RTX%203080, which doesnt show stock levels.

anyone got a digital rivers endpoint that is working please? am sick of refeshing for days and days and missing out. want to write my own script

I assume they've locked it down and are concealing their digital river key on server side. The link above doesn't work anymore since they probably removed that key. If you look at digital-river's api reference it seems like you need to be using their service to obtain an api key, and even then I assume you would need the correct permissions to access nvidia's products. Purely speculation though.

@tashrifsanil
Copy link

@jgramling17 No worries, Lemme know if you manage to cop one! The 3090 got scalped again when it came back in stock last Thursday sighh

@Michael-Keen-MS
Copy link

yeah i am trying to figure out the DE location but there is nothing :(
https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/products/de_de/EUR/5438481700
https://in-and-ru-store-api.uk-e1.cloudhub.io/DR/get-inventory/de_de/5438481700?format=json&expand=availablequantity
Also here:
https://api.nvidia.partners/edge/product/search?page=1&limit=9&locale=de-de
It looks like Germany never had any to start with :/

I believe different regions have different product IDs. en_gb (UK) is different than ours in US, just an FYI

Does this help?

{
"en-us": {
"rtx-3090": "5438481600",
"rtx-3080": "5438481700",
"rtx-3070": null,
"titan-rtx": "5254456900",
"rtx-2080-super": "5335703700",
"rtx-2070-super": "5394901600",
"rtx-2060-super": "5394902900",
"expensive-shirt": "5444021500"
},
"fr-fr": {
"rtx-3090": "5438761500",
"rtx-3080": "5438795200",
"rtx-3070": null,
"titan-rtx": "5256301100",
"rtx-2080-super": "5336531100",
"rtx-2070-super": "5394901900",
"rtx-2060-super": "5394903200",
"expensive-shirt": "5444021500"
},
"de-de": {
"rtx-3090": "5438761400",
"rtx-3080": "5438792300",
"rtx-3070": null,
"titan-rtx": "5256301000",
"rtx-2080-super": "5335703700",
"rtx-2070-super": "5394901600",
"rtx-2060-super": "5394902900",
"expensive-shirt": "5444021500"
},
"en-gb": {
"rtx-3090": "5438792700",
"rtx-3080": "5438792800",
"rtx-3070": null,
"titan-rtx": "5256301200",
"rtx-2080-super": "5336531200",
"rtx-2070-super": "5394902000",
"rtx-2060-super": "5394903300",
"expensive-shirt": "5444021500"
},
"es-es": {
"rtx-3090": "5438794700",
"rtx-3080": "5438794800",
"rtx-3070": null,
"titan-rtx": "5256301400",
"rtx-2080-super": "5336531400",
"rtx-2070-super": "5394901700",
"rtx-2060-super": "5394903000",
"expensive-shirt": "5444021500"
},
"it-it": {
"rtx-3090": "5438796100",
"rtx-3080": "5438796200",
"rtx-3070": null,
"titan-rtx": "5256302000",
"rtx-2080-super": "5336532000",
"rtx-2070-super": "5394902100",
"rtx-2060-super": "5394903400",
"expensive-shirt": "5444021500"
},
"pl-pl": {
"rtx-3090": "5438797600",
"rtx-3080": "5438797700",
"rtx-3070": null,
"titan-rtx": "5256301600",
"rtx-2080-super": "5336531600",
"rtx-2070-super": "5394902300",
"rtx-2060-super": "5394903700",
"expensive-shirt": "5444021500"
},
"nb-no": {
"rtx-3090": "5438797100",
"rtx-3080": "5438797200",
"rtx-3070": null,
"titan-rtx": "5256301700",
"rtx-2080-super": "5336531700",
"rtx-2070-super": "5394902600",
"rtx-2060-super": "5394903600",
"expensive-shirt": "5444021500"
},
"sv-se": {
"rtx-3090": "5438761600",
"rtx-3080": "5438798100",
"rtx-3070": null,
"titan-rtx": "5256301300",
"rtx-2080-super": "5336531300",
"rtx-2070-super": "5394902500",
"rtx-2060-super": "5394903900",
"expensive-shirt": "5444021500"
},
"da-dk": {
"rtx-3090": "5438793200",
"rtx-3080": "5438793300",
"rtx-3070": null,
"titan-rtx": "5256301800",
"rtx-2080-super": "5336531800",
"rtx-2070-super": "5394901800",
"rtx-2060-super": "5394903100",
"expensive-shirt": "5444021500"
},
"fr-be": {
"rtx-3090": "5438795600",
"rtx-3080": "5438795700",
"rtx-3070": null,
"titan-rtx": "5256301500",
"rtx-2080-super": "5336531500",
"rtx-2070-super": "5336534300",
"rtx-2060-super": "5394902700",
"expensive-shirt": "5444021500"
},
"de-at": {
"rtx-3090": "5444941400",
"rtx-3080": "5440853700",
"rtx-3070": null,
"titan-rtx": "5256301000",
"rtx-2080-super": "5335703700",
"rtx-2070-super": "5394901600",
"rtx-2060-super": "5394902900",
"expensive-shirt": "5444021500"
},
"cs-cz": {
"rtx-3090": "5438793600",
"rtx-3080": "5438793800",
"rtx-3070": null,
"titan-rtx": "5256301900",
"rtx-2080-super": "5336531900",
"rtx-2070-super": "5394901500",
"rtx-2060-super": "5394902800",
"expensive-shirt": "5444021500"
},
"fi-fi": {
"rtx-3090": "5438793200",
"rtx-3080": "5438793300",
"rtx-3070": null,
"titan-rtx": "5256301800",
"rtx-2080-super": "5336531800",
"rtx-2070-super": "5394901800",
"rtx-2060-super": "5394903100",
"expensive-shirt": "5444021500"
},
"nl-nl": {
"rtx-3090": "5438796600",
"rtx-3080": "5438796700",
"rtx-3070": null,
"titan-rtx": "5256302100",
"rtx-2080-super": "5336532100",
"rtx-2070-super": "5394902200",
"rtx-2060-super": "5394903500",
"expensive-shirt": "5444021500"
}
}

@Michael-Keen-MS
Copy link

Does anyone have a better way to check for stock? I was sending a get request to https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481600 which would return a json response which would tell you inventory status, but now it doesn't work so well (error 503 - gateway times out).

Nvidia's own website makes the same website and now it fails there too, but eventually after a while the out of stock button pops up on their site. Do you guys think their website is setup so that if the request fails the out of stock button shows up? Or is their a better way to check for stock?

import requests

url = "https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481600"

payload = {}
headers = {
  'authority': 'api-prod.nvidia.com',
  'accept': 'application/json, text/javascript, */*; q=0.01',
  'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36',
  'dnt': '1',
  'origin': 'https://www.nvidia.com',
  'sec-fetch-site': 'same-site',
  'sec-fetch-mode': 'cors',
  'sec-fetch-dest': 'empty',
  'referer': 'https://www.nvidia.com/en-us/geforce/graphics-cards/30-series/rtx-3090/',
  'accept-language': 'en-CA,en-GB;q=0.9,en-US;q=0.8,en;q=0.7'
}

response = requests.request("GET", url, headers=headers, data = payload)

print(response.text.encode('utf8'))

This should help:

from IPython.core.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))

import requests
import json

payload = {}
headers = {
  'authority': 'api-prod.nvidia.com',
  'accept': 'application/json, text/javascript, */*; q=0.01',
  'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36',
  'dnt': '1',
  'origin': 'https://www.nvidia.com',
  'sec-fetch-site': 'same-site',
  'sec-fetch-mode': 'cors',
  'sec-fetch-dest': 'empty',
  'referer': 'https://www.nvidia.com/en-us/geforce/graphics-cards/30-series/rtx-3090/',
  'accept-language': 'en-CA,en-GB;q=0.9,en-US;q=0.8,en;q=0.7'
}

url = "https://api-prod.nvidia.com/direct-sales-shop/DR/products/en_us/USD/5438481700"

response = requests.request("GET", url, headers=headers, data = payload)

/* print(response.json()) -- you can use this to look at the full dict */

jsonResponse = response.json()

for url in jsonResponse["products"]["product"]:
    print(" PRODUCT NAME:   ", url["displayName"], '\n', "IN STOCK?:      ", url["inventoryStatus"]["productIsInStock"].upper(), '\n', "PRODUCT STATUS: ", url["inventoryStatus"]["status"], '\n', "PRICE:          ", url["pricing"]["formattedListPrice"])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment