Build a Serverless Gaming Console Stock Checker with Playwright, Azure Functions and Twilio
- Published on
- Reading time
- Authors
- Name
- Simon Waight
- Mastodon
- @simonwaight
Unless you've been living on the Outer Hebrides you can't help but have noticed how in short supply the XBox Series X has been since its launch. If, like me, you have a house of mad gamers, the ongoing demands for one of these devices remains high and the constant challenge is being able to identify when you might be able to buy one from a retailer.
There are already a few websites floating around that will tell you if stock comes in at an online retailer, but I don't have the time to sit around waiting for a web page to update to know when stock comes in. It's also something I'm likely to miss.
Keeping this in mind I set out to build a simple automated stock checker that will push an alert to me when stock shows up so that I can action it immediately regardless of where I am. Now this wouldn't be a great post if you couldn't follow along, so here's how I built it.
Checking for Stock
First, let's start by asking how would you do this manually? You'd open a web browser tab on each retailer's website and periodically refresh the page.
Yeah, not great, and not very scalable.
In an ideal world (for developers at least) every retailer would have an API you could use to check stock levels of goods. In the real world... good luck with that!
In years gone by I might have been able to write some code to request a URL from the retailer, download the HTML and parse the contents for key items. These days this approach doesn't work due to how much web content is dynamically created by JavaScript executing in a web browser, which, unfortunately, excludes the old school approach of simply downloading static HTML and using a regular expression on it.
Thankfully, this is a common challenge in the world of automated website testing, so we can borrow some tech from that space and use it to solve our challenge. The two leading frameworks that can help us with modern web content are Playwright from Microsoft or Pupeteer from Google.
Finding Web Page Triggers
The next piece of our puzzle is to visit the retailer websites we are interested to track and to identify which page (URL) and which elements on the page will help identify stock availability. In order to do this all you need is a modern web browser with developer tools available - either Edge or Chrome will do.
Let's use the Microsoft Australia retail website as our sample site. I'm going to open the XBox Series X URL in my web browser and look at the page.
I can see when I hover over the "Configure now" button that the cursor changes and I am unable to submit the form. This gives suggests that if the console was in stock this behaviour wouldn't occur, so that's my starting point.
The next thing I'm going to do is pop open the developer tools in my browser and inspect this element. When I find the element I can look at the properties in the resulting markup and identify which I want to use to determine the state of stock availability. I don't need to worry about how this element is created, simply that it exists in the resulting document.
I can see the HTML element has an ID property of 'buttons_ConfigureDeviceButton' which I can use to uniquely identify the element on the page, and that it has a second property called 'aria-disabled' which is an accessibility property being used in this case to disable the button element on the page.
At this point I have what I need to use the page as a trigger for whether the item is in stock. You would need to repeat this across each retailer you want to track. Depending on how they've built their website you might have to spend a bit of time figuring out what the right combination of properties is in order to trigger an alert that a console is in stock.
Here's a JavaScript snippet showing you how I've turned the HTML elements into code to check for stock availability. You can find the full source code file on GitHub.
CheckMSAU: async function(context) {
var hasConsole = false;
const url = 'https://www.microsoft.com/en-au/d/xbox-series-x/8wj714n3rbtl?activetab=pivot%3aoverviewtab';
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(url);
try
{
// find the element and retrieve the attribute that tells the browser if it can be clicked
const elementValue = await page.getAttribute("#buttons_ConfigureDeviceButton", "aria-disabled");
if(elementValue != "true")
{
hasConsole = true;
context.log("MSAU: XBox Series X in stock! :)");
}
else
{
context.log("MSAU: XBox X still out of stock. :(");
}
}
catch (e)
{
if(e instanceof TimeoutError)
{
context.log("Took too long to find the element!");
}
}
await browser.close();
return new LookupResponse(consoleAvailable = hasConsole, pageLink = url);
}
Automating the checks
I am going to automate my checks by using Azure Functions, using a Timer trigger to execute code at regular intervals (I have it set to 30 minutes). My use case really suits Consumption plan Functions as well, so I can minimise my Azure costs by staying under the free execution limit for Functions and only paying a tiny amount for the Storage Acccount.
If you want to go ahead and check out the final solution you find it on GitHub.
The Azure Function actually has two individual Functions defined:
- StockChecker: Timer triggered Function that uses Playwright (and "headless" Chrome) to retrieve and parse the web pages and identifies if any stock is available based on the state of the page. It then sends an alert using a call to Twilio using their SDK to simplify the call.
- ActivitySwitcher: HTTP Trigger Function that is the webhook endpoint integrated with Twilio. This allows us to control the stock checker via SMS. When our configured phone number at Twilio receives an incoming text message it sends on the message text to our Function which parses the text and flips a control bit in an Azure Storage Table.
Deploying to Azure is controlled via a GitHub Action that was created using the Deployment Center capability of Azure Functions and App Service. This is great because I don't need to handle magic credentials anywhere - they are automatically populated as a secret in GitHub for me!
Important note: make sure to select Linux for your Azure Function hosting plan. It appears that on Windows you can run into issues with Playwright configuration.
Deciding on alerting approach
I tried a few approaches to this - Azure Notification Hubs, Azure Event Grid Webhooks and Twilio's Messaging API. Ultimately I ended up going with Twilio due to its simplicity, even though it introduces a cost to my solution (if you use a Twilio trial you might avoid that cost for a while).
Longer term I'd probably look at the messaging capabilities Azure Communication Services, but in Australia at this time it can only do text-based chat which didn't meet my needs.
Merry Christmas?
Well, I'm hoping with this setup in place I can finally sit back and simply wait for my code to tell me when I can buy a XBox Series X and make it a Merry Christmas for the mad gamers I am surrounded by! Ooooh... maybe I'm in luck already?!
Happy Days 😎
You can check out the source code at: https://github.com/sjwaight/GameConsoleStockChecker