Return to Blog List
Implementing a Website Monitoring System with Screenshot API
Monitoring

Implementing a Website Monitoring System with Screenshot API

April 15, 2025
9 min read

Website monitoring is essential for businesses that rely on their online presence. By capturing regular screenshots, you can visually track changes, detect issues, and ensure your site is functioning correctly. This tutorial will guide you through building an automated monitoring system using our Screenshot API.

Why Visual Monitoring Matters

Traditional monitoring focuses on uptime and performance metrics, but visual monitoring adds another dimension:

  • Detect rendering issues that don't trigger errors
  • Identify UI/UX regressions after deployments
  • Spot unauthorized content changes
  • Verify third-party components display correctly
  • Document compliance with regulatory requirements

System Architecture

Our monitoring system will consist of:

  1. A scheduler to trigger screenshots at regular intervals
  2. The Screenshot API to capture website images
  3. Image storage for the screenshots
  4. A comparison engine to detect changes
  5. Notification system for alerts

Implementation Steps

1. Setting Up the Scheduler

We'll use Node.js with a cron job scheduler:

javascript
01const cron = require('node-cron');
02const { captureScreenshot, compareScreenshots } = require('./screenshot-service');
03const { sendAlert } = require('./notification-service');
04
05// Schedule screenshots every hour
06cron.schedule('0 * * * *', async () => {
07 console.log('Running scheduled screenshot capture...');
08
09 const websites = [
10 { name: 'Main Website', url: 'https://example.com' },
11 { name: 'Product Page', url: 'https://example.com/products' },
12 { name: 'Checkout Page', url: 'https://example.com/checkout' }
13 ];
14
15 for (const site of websites) {
16 try {
17 await processWebsite(site);
18 } catch (error) {
19 console.error(`Error processing ${site.name}:`, error);
20 }
21 }
22});
23
24async function processWebsite(site) {
25 // Capture new screenshot
26 const newScreenshot = await captureScreenshot(site.url);
27
28 // Get previous screenshot from storage
29 const previousScreenshot = await getPreviousScreenshot(site.name);
30
31 if (previousScreenshot) {
32 // Compare screenshots
33 const changes = await compareScreenshots(previousScreenshot, newScreenshot);
34
35 if (changes.percentageDifference > 5) {
36 // Alert if significant changes detected
37 await sendAlert({
38 website: site.name,
39 changePercentage: changes.percentageDifference,
40 previousImage: previousScreenshot.url,
41 newImage: newScreenshot.url,
42 changesImage: changes.diffImageUrl
43 });
44 }
45 }
46
47 // Save new screenshot as the latest
48 await saveScreenshot(site.name, newScreenshot);
49}

2. Screenshot Capture Service

javascript
01const fetch = require('node-fetch');
02const AWS = require('aws-sdk');
03const s3 = new AWS.S3();
04const { v4: uuidv4 } = require('uuid');
05
06async function captureScreenshot(url) {
07 // Call Screenshot API
08 const response = await fetch('https://api.screenshotapi.com/capture', {
09 method: 'POST',
10 headers: {
11 'Content-Type': 'application/json',
12 'Authorization': `Bearer ${process.env.SCREENSHOT_API_KEY}`
13 },
14 body: JSON.stringify({
15 url,
16 width: 1280,
17 height: 800,
18 fullPage: true,
19 format: 'png'
20 })
21 });
22
23 const data = await response.json();
24
25 // Download the screenshot
26 const imageResponse = await fetch(data.screenshotUrl);
27 const imageBuffer = await imageResponse.buffer();
28
29 // Generate unique filename
30 const filename = `${uuidv4()}.png`;
31
32 // Upload to S3
33 await s3.putObject({
34 Bucket: process.env.S3_BUCKET,
35 Key: filename,
36 Body: imageBuffer,
37 ContentType: 'image/png'
38 }).promise();
39
40 // Return screenshot info
41 return {
42 url: `https://${process.env.S3_BUCKET}.s3.amazonaws.com/${filename}`,
43 timestamp: new Date().toISOString(),
44 metadata: data.metadata
45 };
46}

3. Image Comparison Service

javascript
01const { PNG } = require('pngjs');
02const pixelmatch = require('pixelmatch');
03const fetch = require('node-fetch');
04
05async function compareScreenshots(previous, current) {
06 // Download both images
07 const [prevImg, currImg] = await Promise.all([
08 downloadImage(previous.url),
09 downloadImage(current.url)
10 ]);
11
12 // Parse PNG images
13 const prevPng = PNG.sync.read(prevImg);
14 const currPng = PNG.sync.read(currImg);
15
16 // Create output image
17 const { width, height } = prevPng;
18 const diffPng = new PNG({ width, height });
19
20 // Compare pixels
21 const numDiffPixels = pixelmatch(
22 prevPng.data,
23 currPng.data,
24 diffPng.data,
25 width,
26 height,
27 { threshold: 0.1 }
28 );
29
30 // Calculate difference percentage
31 const totalPixels = width * height;
32 const percentageDifference = (numDiffPixels / totalPixels) * 100;
33
34 // Generate diff image
35 const diffBuffer = PNG.sync.write(diffPng);
36 const diffImageUrl = await uploadDiffImage(diffBuffer);
37
38 return {
39 percentageDifference,
40 diffPixels: numDiffPixels,
41 totalPixels,
42 diffImageUrl
43 };
44}
45
46async function downloadImage(url) {
47 const response = await fetch(url);
48 return await response.buffer();
49}
50
51async function uploadDiffImage(buffer) {
52 // Similar to the screenshot upload in captureScreenshot function
53 // ...
54}

4. Notification Service

javascript
01const nodemailer = require('nodemailer');
02const slack = require('@slack/webhook');
03
04const slackWebhook = new slack.IncomingWebhook(process.env.SLACK_WEBHOOK_URL);
05const transporter = nodemailer.createTransport({
06 // Email configuration
07 // ...
08});
09
10async function sendAlert(alertData) {
11 // Send Slack notification
12 await slackWebhook.send({
13 text: `🚨 Visual changes detected on ${alertData.website}`,
14 blocks: [
15 {
16 type: 'section',
17 text: {
18 type: 'mrkdwn',
19 text: `*Visual changes detected on ${alertData.website}*\n${alertData.changePercentage.toFixed(2)}% of the page has changed.`
20 }
21 },
22 {
23 type: 'image',
24 title: {
25 type: 'plain_text',
26 text: 'Visual differences'
27 },
28 image_url: alertData.changesImage,
29 alt_text: 'Visual differences highlighted'
30 },
31 {
32 type: 'actions',
33 elements: [
34 {
35 type: 'button',
36 text: {
37 type: 'plain_text',
38 text: 'View Previous'
39 },
40 url: alertData.previousImage
41 },
42 {
43 type: 'button',
44 text: {
45 type: 'plain_text',
46 text: 'View Current'
47 },
48 url: alertData.newImage
49 }
50 ]
51 }
52 ]
53 });
54
55 // Send email alert
56 await transporter.sendMail({
57 from: process.env.EMAIL_FROM,
58 to: process.env.ALERT_EMAIL,
59 subject: `Website Change Alert: ${alertData.website}`,
60 html: `
61 <h1>Visual changes detected on ${alertData.website}</h1>
62 <p>${alertData.changePercentage.toFixed(2)}% of the page has changed.</p>
63 <h2>Visual Difference:</h2>
64 <img src="${alertData.changesImage}" alt="Visual differences" style="max-width: 100%;" />
65 <div>
66 <a href="${alertData.previousImage}">View Previous Version</a> |
67 <a href="${alertData.newImage}">View Current Version</a>
68 </div>
69 `
70 });
71}

Deployment Options

This monitoring system can be deployed in several ways:

  1. AWS Lambda: For serverless operation with scheduled triggers
  2. Docker Container: For easy deployment to any container platform
  3. Traditional VPS: For complete control over the environment

Advanced Features

Once your basic monitoring system is working, consider these enhancements:

  • Visual Regression Testing: Integrate with CI/CD pipelines to catch UI issues before deployment
  • Historical Archiving: Keep a timeline of website changes for compliance or analysis
  • Element-Specific Monitoring: Focus on critical UI components rather than the entire page
  • Multi-Browser Testing: Capture screenshots across different browsers to ensure cross-browser compatibility

By implementing this monitoring system, you'll gain valuable insights into your website's visual stability and be alerted to unexpected changes before they impact your users.

AutomationDevOps

Ready to Get Started?

Get your API key now and start capturing screenshots in minutes.