Building a Website Monitoring Dashboard with ToolCenter API
Keeping tabs on your websites shouldn't require expensive SaaS tools. With ToolCenter's suite of APIs, you can build a fully custom monitoring dashboard that tracks uptime, SSL health, DNS records, and page speed — all from a single integration.
In this guide, we'll build a monitoring dashboard step by step, combining multiple ToolCenter endpoints into one cohesive system.
Why Build Your Own Monitoring?
Commercial monitoring tools like Pingdom, UptimeRobot, or Datadog are great — but they come with limitations:
- Pricing tiers restrict the number of monitors or check frequency
- Limited customization of alerts and dashboards
- Vendor lock-in makes migration painful
- Overkill for small teams managing 5-20 sites
With ToolCenter, you pay per API call and own every piece of the stack.
The Architecture
Our dashboard will use four ToolCenter APIs:
- Status Check — HTTP response codes and uptime
- SSL Checker — Certificate expiry and validity
- DNS Lookup — Record verification
- Page Speed — Performance metrics
Each API call returns structured JSON, making it trivial to store results and render dashboards.
Step 1: Set Up the Status Check
The Status Check API is the backbone of any monitoring system. It tells you whether your site is responding and how fast.
const ToolCenter = require('toolcenter');
const client = new ToolCenter('your_api_key');
async function checkStatus(url) {
const result = await client.status.check({ url });
return {
url,
statusCode: result.status_code,
responseTime: result.response_time_ms,
isUp: result.status_code >= 200 && result.status_code < 400,
checkedAt: new Date().toISOString()
};
}
// Monitor multiple sites
const sites = [
'https://example.com',
'https://api.example.com',
'https://docs.example.com'
];
const results = await Promise.all(sites.map(checkStatus));
console.log(results);
The response includes the HTTP status code and response time in milliseconds — everything you need for uptime tracking.
Python Alternative
from toolcenter import ToolCenter
from datetime import datetime
client = ToolCenter("your_api_key")
def check_status(url):
result = client.status.check(url=url)
return {
"url": url,
"status_code": result["status_code"],
"response_time": result["response_time_ms"],
"is_up": 200 <= result["status_code"] < 400,
"checked_at": datetime.utcnow().isoformat()
}
sites = ["https://example.com", "https://api.example.com"]
results = [check_status(site) for site in sites]
Step 2: Monitor SSL Certificates
Expired SSL certificates break trust and kill SEO rankings. The SSL Checker API gives you full certificate details:
async function checkSSL(domain) {
const ssl = await client.ssl.check({ url: domain });
const expiryDate = new Date(ssl.valid_to);
const daysUntilExpiry = Math.floor(
(expiryDate - new Date()) / (1000 * 60 * 60 * 24)
);
return {
domain,
issuer: ssl.issuer,
validFrom: ssl.valid_from,
validTo: ssl.valid_to,
daysUntilExpiry,
isExpiringSoon: daysUntilExpiry < 30,
isValid: ssl.is_valid
};
}
const sslStatus = await checkSSL('https://example.com');
if (sslStatus.isExpiringSoon) {
console.warn(`SSL for ${sslStatus.domain} expires in ${sslStatus.daysUntilExpiry} days!`);
}
Pro tip: Set your alert threshold to 30 days. Most certificate authorities like Let's Encrypt renew at 30 days, so if you're inside that window and it hasn't renewed, something is wrong.
Step 3: Verify DNS Records
DNS misconfigurations are silent killers. A changed nameserver or missing MX record can go unnoticed for days. The DNS Lookup API helps you verify records match your expected configuration:
async function checkDNS(domain, expectedRecords) {
const dns = await client.dns.lookup({ domain, type: 'A' });
const currentIPs = dns.records.map(r => r.value);
const mismatches = expectedRecords.filter(ip => !currentIPs.includes(ip));
return {
domain,
records: currentIPs,
expected: expectedRecords,
hasIssues: mismatches.length > 0,
mismatches
};
}
const dnsCheck = await checkDNS('example.com', ['93.184.216.34']);
if (dnsCheck.hasIssues) {
console.error(`DNS mismatch for ${dnsCheck.domain}!`);
console.error(`Missing: ${dnsCheck.mismatches.join(', ')}`);
}
You can extend this to check MX, CNAME, TXT (SPF/DKIM), and NS records for complete DNS monitoring.
Step 4: Track Page Speed
Slow pages lose visitors. The Page Speed API gives you performance metrics you can track over time:
async function checkSpeed(url) {
const speed = await client.pageSpeed.analyze({ url });
return {
url,
loadTime: speed.load_time_ms,
ttfb: speed.ttfb_ms,
pageSize: speed.page_size_bytes,
requests: speed.total_requests,
score: speed.performance_score,
isSlowLoading: speed.load_time_ms > 3000
};
}
const speedResult = await checkSpeed('https://example.com');
if (speedResult.isSlowLoading) {
console.warn(`${speedResult.url} is loading slowly: ${speedResult.loadTime}ms`);
}
Track these metrics daily to catch performance regressions before users do.
Step 5: Putting It All Together
Here's a complete monitoring script that combines all four checks:
const ToolCenter = require('toolcenter');
const fs = require('fs');
const client = new ToolCenter(process.env.TOOLCENTER_API_KEY);
const SITES = [
{
url: 'https://example.com',
expectedDNS: ['93.184.216.34'],
label: 'Main Site'
},
{
url: 'https://api.example.com',
expectedDNS: ['93.184.216.34'],
label: 'API'
}
];
async function runFullCheck(site) {
const [status, ssl, dns, speed] = await Promise.all([
client.status.check({ url: site.url }),
client.ssl.check({ url: site.url }),
client.dns.lookup({ domain: new URL(site.url).hostname, type: 'A' }),
client.pageSpeed.analyze({ url: site.url })
]);
const sslExpiry = Math.floor(
(new Date(ssl.valid_to) - new Date()) / 86400000
);
return {
label: site.label,
url: site.url,
timestamp: new Date().toISOString(),
uptime: {
isUp: status.status_code >= 200 && status.status_code < 400,
statusCode: status.status_code,
responseTime: status.response_time_ms
},
ssl: {
isValid: ssl.is_valid,
daysUntilExpiry: sslExpiry,
needsAttention: sslExpiry < 30
},
dns: {
records: dns.records.map(r => r.value),
matchesExpected: site.expectedDNS.every(
ip => dns.records.some(r => r.value === ip)
)
},
performance: {
loadTime: speed.load_time_ms,
score: speed.performance_score,
isHealthy: speed.load_time_ms < 3000
}
};
}
async function monitor() {
const results = await Promise.all(SITES.map(runFullCheck));
results.forEach(r => {
console.log(`${r.label} (${r.url})`);
console.log(` Status: ${r.uptime.isUp ? 'UP' : 'DOWN'} ${r.uptime.statusCode} (${r.uptime.responseTime}ms)`);
console.log(` SSL: ${r.ssl.daysUntilExpiry} days remaining`);
console.log(` DNS: ${r.dns.records.join(', ')}`);
console.log(` Speed: ${r.performance.loadTime}ms (score: ${r.performance.score})`);
});
// Store history
const historyFile = './monitoring-history.json';
let history = fs.existsSync(historyFile)
? JSON.parse(fs.readFileSync(historyFile, 'utf8'))
: [];
history.push(...results);
fs.writeFileSync(historyFile, JSON.stringify(history, null, 2));
// Alert on issues
const alerts = results.filter(r =>
!r.uptime.isUp || r.ssl.needsAttention || !r.dns.matchesExpected || !r.performance.isHealthy
);
if (alerts.length > 0) {
alerts.forEach(a => {
if (!a.uptime.isUp) console.log(`ALERT: ${a.label} is DOWN`);
if (a.ssl.needsAttention) console.log(`ALERT: ${a.label} SSL expires in ${a.ssl.daysUntilExpiry} days`);
if (!a.dns.matchesExpected) console.log(`ALERT: ${a.label} DNS mismatch`);
if (!a.performance.isHealthy) console.log(`ALERT: ${a.label} slow: ${a.performance.loadTime}ms`);
});
}
}
monitor().catch(console.error);
Scheduling with Cron
Save the script as monitor.js and schedule it:
# Run every 5 minutes
*/5 * * * * cd /path/to/project && node monitor.js >> /var/log/site-monitor.log 2>&1
For a more sophisticated setup, use PM2:
pm2 start monitor.js --cron-restart="*/5 * * * *" --no-autorestart
Adding Slack Alerts
Connect monitoring to real notification channels:
async function sendSlackAlert(message) {
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ text: message })
});
}
if (alerts.length > 0) {
const message = alerts.map(a => {
const issues = [];
if (!a.uptime.isUp) issues.push(`DOWN (${a.uptime.statusCode})`);
if (a.ssl.needsAttention) issues.push(`SSL expires in ${a.ssl.daysUntilExpiry}d`);
if (!a.dns.matchesExpected) issues.push('DNS mismatch');
if (!a.performance.isHealthy) issues.push(`Slow (${a.performance.loadTime}ms)`);
return `${a.label}: ${issues.join(', ')}`;
}).join('\n');
await sendSlackAlert(`Monitoring Alert\n${message}`);
}
Cost Estimation
Each full site check uses 4 API calls:
- 5-minute intervals: 288 checks/day x 4 calls = 1,152 calls/site/day
- 15-minute intervals: 96 checks/day x 4 calls = 384 calls/site/day
- Hourly intervals: 24 checks/day x 4 calls = 96 calls/site/day
For most small teams monitoring 5-10 sites, hourly checks are the sweet spot between visibility and cost.
What's Next
This foundation gives you full visibility into your web infrastructure. From here you could:
- Build a web UI with charts using Chart.js or Recharts
- Add incident tracking with automatic status page updates
- Monitor API endpoints with custom request bodies
- Track historical trends to predict issues before they happen
- Set up escalation policies (email, Slack, SMS)
The ToolCenter API gives you the building blocks. What you build with them is up to you.
Ready to start monitoring? Get your free API key and try the Status Check API — it takes less than a minute to make your first call.