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. ```javascript 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 ```python 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: ```javascript 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: ```javascript 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: ```javascript 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: ```javascript 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: ```bash # 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: ```bash pm2 start monitor.js --cron-restart="*/5 * * * *" --no-autorestart ``` ## Adding Slack Alerts Connect monitoring to real notification channels: ```javascript 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](https://toolcenter.dev) and try the Status Check API — it takes less than a minute to make your first call.*