How I built a dashboard for the iPad with JavaScript
By Flavio Copes
How I built a signups counter dashboard for the iPad with JavaScript, using a small Node.js and Express server to serve an auto-refreshing full-screen page.
In this post I’m going to show you how I built a signups counter for the JavaScript Course course, so I can see how many people signed up to the course (signups are open from Nov 15 to Nov 22!)
This counter is a totally superfluous thing, the ones that I do when I’m procrastinating and want to avoid the important work.
I’ve been thinking of different ways to do this, like creating an iOS widget with JavaScript, using Scriptable.
But then I thought, well let’s just make a web page. A web page that I can keep open on the iPad, and I’ll put the iPad next to the desk or somewhere I can look at it from time to time.
I can set the iPad to never put the display to sleep, and I can set the page to automatically refresh every 2 minutes.
The advantage of making a simple web page is that I can access it anywhere. From the iPad, the iPhone, the Mac.
I made a Node.js program that fetches the data I need.
The first step is to write a function that gets the data:
const getData = async () => {
let count = 0
//retrieve the count, for example with fetch()
return count
}
I made it an async function as I use a fetch request, and it’s most likely you’re going to need it too. An async function always returns a promise, so there’s no need to wrap the code in new Promise(). You await what you need inside it and return the value.
If you’re curious, I store all signups into an Airtable record, so inside getData() I put all the code needed to retrieve the count from Airtable.
Then I made a very simple Express server that serves an HTML page that shows the count big, centered in the page.
I use ES modules, so I import Express with import. Add "type": "module" to your package.json, or name the file server.mjs. With CommonJS, const express = require('express') works too.
import express from 'express'
const app = express()
app.get('/', async (req, res) => {
const count = await getData()
const html = `
<html>
<head>
<!-- refresh every 2 minutes -->
<meta http-equiv="refresh" content="120">
<!-- allow full screen on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<link href="https://fonts.googleapis.com/css2?family=Arvo:wght@400;500;600;700&display=swap" rel="stylesheet" media="all">
<style>
html,
body {
font-family: Arvo,Helvetica,Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Noto Color Emoji,Segoe UI Symbol,Android Emoji,EmojiSymbols,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Noto Sans,sans-serif;
margin: 0;
font-size: 200px
}
h1 {
display: grid;
place-items: center;
height: 100vh;
}
@media (prefers-color-scheme: dark) {
body {
filter: invert(100%);
background-color: #000;
}
}
</style>
</head>
<body>
<h1>${count}</h1>
</body>
</html>
`
res.end(html)
})
const listener = app.listen(3000)
This code is for Express 5, the version npm install express gives you as of September 2026. Express 5 catches errors thrown inside an async route handler, like a failed request to Airtable, and sends them to its error handler, which replies with a 500 error. With Express 4 you had to catch the error yourself and call next(err).
The two <meta> tags do the dashboard work. The first reloads the page every 120 seconds, so the count stays fresh. With the second, the page opens full screen, without the Safari toolbar, once you add it to the Home Screen from the Share menu.
Here’s the result:


And here’s the same page on the iPhone:
You can run the program locally on your computer and you can access it from devices on the same wi-fi network, as long as the computer is running, or if you prefer you can use a localhost tunnel service, but you can also put this somewhere on the Internet.
I put the app on a server I use for my Node scripts, so I can access it from anywhere, even if I’m on a 4G network.
If I want, I can also AirPlay that on the Apple TV, so I can see the number of signups on the big television screen.
Want me to talk about your product? You can sponsor this site.
Related posts about js: