← Back to list

Monitoring Website Content with Playwright and Nagios

it’s very important to simply ensuring your users always see the latest updates.

Firat Gulec · 2025-12-27 17:42 · 0 claps · 7.9 min read
#nagios #monitoring #website #networking #security
Open on Medium ↗

Monitoring Website Content with Playwright and Nagios

it’s very important to simply ensuring your users always see the latest updates.

Photo by nine koepfer on Unsplash

Photo by nine koepfer on Unsplash

Keeping a close eye on your website’s content is crucial, whether for uptime monitoring, regulatory compliance, or simply ensuring your users always see the latest updates. Traditionally, Nagios plugins focused on server availability or response times, but modern tools like Playwright allow us to perform end-to-end content checks automatically. In this article, we’ll explore how to build a custom Nagios plugin using Playwright inside Docker, capable of monitoring both text and element presence on your website.

Why Playwright?

Fast and reliable end-to-end testing for modern web apps | Playwright

Playwright is a modern browser automation library that supports Chromium, Firefox, and WebKit. It allows for robust, end-to-end testing of web applications and provides features like:

  • Cross-browser testing
  • Headless execution for CI/CD pipelines
  • Powerful selectors (getByText, locator, CSS, etc.)
  • JSON reporters for structured test results

By combining Playwright with Nagios, we can move beyond simple HTTP checks and verify actual page content.

Project Structure

Here’s a clean directory layout for our monitoring setup:

  • **product/tests** – Contains the Playwright test files.
  • **product/out** – Stores JSON results and logs for Nagios.
  • **Dockerfile** – Encapsulates the Playwright environment.
  • **run-tests.sh** – Executes Playwright tests inside Docker.
  • **check_website_content.sh** – Nagios plugin script that generates the test, runs Docker, parses results, and outputs Nagios-compatible status.

Setting Up Playwright

Inside the product/tests folder:

mkdir -p product/tests product/out
cd product/tests

playwright.config.ts

import { defineConfig } from '@playwright/test';
export default defineConfig({
  reporter: [
    ['json', { outputFile: '/tests/out/product-result.json' }]
  ],
  projects: [
    {
      name: 'chromium',
      use: { browserName: 'chromium' },
    },
  ],
});
package.json
{
  "devDependencies": {
    "@playwright/test": "1.56.1"
  }
}

product.spec.ts

import { test, expect } from '@playwright/test';
test('Firat Gulec Website Check', async ({ page }) => {
  await page.goto('www.webpagecheck.com');
  let buttonCheck = 'Skipped';
  let textCheck = 'Failed';
  let contentCheck = 'Skipped';
  let cssCheck = 'Skipped';
  try {
    await expect(page.getByText('checktext_script')).toBeVisible();
    textCheck = 'Passed';
  } catch {
    textCheck = 'Failed';
  }
  try {
    const body = await page.textContent('body');
    if (body && body.includes("checktext_script")) {
      contentCheck = 'Passed';
    } else {
      contentCheck = 'Failed';
    }
  } catch {
    contentCheck = 'Failed';
  }
  console.log("RESULT_JSON:" + JSON.stringify({
    buttonCheck,
    textCheck,
    contentCheck,
    cssCheck
  }));
});

Dockerizing Playwright

We use Docker to ensure consistent, isolated test environments, avoiding dependency issues on the host machine.

Dockerfile

# FROM mcr.microsoft.com/playwright:v1.56.1-jammy
# AMD64 Mimaride Playwright imaj
FROM --platform=linux/amd64 mcr.microsoft.com/playwright:v1.56.1-jammy
WORKDIR /tests
# Package.json
COPY product/tests/package.json .
# Install Dependencies
RUN npm install
# Copy test files
COPY product/tests ./tests
# Copy and set permissions for the test runner script
COPY run-tests.sh .
RUN chmod +x run-tests.sh
ENTRYPOINT ["./run-tests.sh"]
##
## To build the Docker image, use:  docker build -t playwright-runner .
## for x86_64 ## docker build --platform=linux/amd64 -t playwright-runner .

You should check host mimari uname -m if your mimari is x86_64 you must use --platform=linux/amd64 command parameters docker build and in dockerfile from

run-tests.sh

#!/bin/bash
set -e
echo "Running Playwright tests..."
cd /tests/tests
# it creates JSON report in /tests/out by using playwright.config.ts
npx playwright test --config=playwright.config.ts
echo "Done. JSON report created in /tests/out"

Building the Nagios Plugin

The check_website_content.sh script dynamically generates a Playwright test based on input parameters (URL, text, buttons, CSS selectors), runs the test in Docker, and parses the JSON result into Nagios-compatible status codes.

Key features:

  1. Dynamic test generation — Supports button clicks, text visibility, CSS content checks, and full-body content searches.
  2. Dockerized execution — Runs Playwright tests in a container, ensuring environment consistency.
  3. Nagios integration — Outputs OK or CRITICAL with detailed information.

check_website_content.sh

#!/bin/bash
# Default values
HELP=false
URL=""
TEXT_SEARCH=""
BUTTON_TEXT=""
CSS_SELECTOR=""
CSS_TEXT=""
CONTENT_TEXT=""
usage() {
    echo "Usage:"
    echo "  $0 -w <URL> -t <TEXT_SEARCH> [-b <BUTTON_TEXT>] [-c <CONTENT_TEXT> -cc content] [-s <CSS_TEXT> -ss <CSS_SELECTOR>]"
    echo ""
    echo "Options:"
    echo "  -w      URL of the page to test"
    echo "  -t      Text to search using Playwright getByText()"
    echo "  -b      Optional button text to click first"
    echo ""
    echo "Content-based search (body text):"
    echo "  -c      Text to find inside full page body text"
    echo "  -cc     Enable content search mode (must be used with -cc then -c together)"
    echo ""
    echo "CSS selector search:"
    echo "  -s      Text to search inside items returned by CSS selector"
    echo "  -ss     CSS selector (must be used with -s)"
    echo ""
    echo "Examples:"
    echo "  ./script.sh -w <https://site> -t \\"Start hier\\" -cc -c \\"Transavia\\""
    echo "  ./script.sh -w <https://site> -t \\"Start\\" -ss \\".faq-title\\" -s \\"Transavia\\""
    exit 1
}
# Parse parameters
while [[ $# -gt 0 ]]; do
    case "$1" in
        -w) URL="$2"; shift 2 ;;
        -t) TEXT_SEARCH="$2"; shift 2 ;;
        -b) BUTTON_TEXT="$2"; shift 2 ;;
        -s) CSS_TEXT="$2"; shift 2 ;;
        -ss) CSS_SELECTOR="$2"; shift 2 ;;
        -c) CONTENT_TEXT="$2"; shift 2 ;;
        -cc) CONTENT_MODE="enabled"; shift 1 ;;
        -help|--help) usage ;;
        *) usage ;;
    esac
done
# Mandatory checks
if [ -z "$URL" ] || [ -z "$TEXT_SEARCH" ]; then
    usage
fi
# Validate CSS search pairing
if { [ ! -z "$CSS_TEXT" ] && [ -z "$CSS_SELECTOR" ]; } || \\
   { [ -z "$CSS_TEXT" ] && [ ! -z "$CSS_SELECTOR" ]; }; then
    echo "ERROR: -s and -ss must be used together."
    exit 1
fi
# Validate content search pairing
if { [ ! -z "$CONTENT_TEXT" ] && [ "$CONTENT_MODE" != "enabled" ]; } || \\
   { [ -z "$CONTENT_TEXT" ] && [ "$CONTENT_MODE" = "enabled" ]; }; then
    echo "ERROR: -c and -cc must be used together."
    exit 1
fi
# Paths
#
TEST_DIR="/usr/local/nagios/libexec/check_website_content/product"
OUT_DIR="$TEST_DIR/out"
SPEC_FILE="$TEST_DIR/tests/product.spec.ts"
LOG_FILE="$OUT_DIR/playwright_log.txt"
mkdir -p "$OUT_DIR"
mkdir -p "$TEST_DIR/tests"
rm -f "$SPEC_FILE" "$LOG_FILE"
###############################
# Generate Playwright Test    #
###############################
cat > "$SPEC_FILE" <<EOF
import { test, expect } from '@playwright/test';
test('Firat Gulec Website Check', async ({ page }) => {
  await page.goto('$URL');
  let buttonCheck = 'Skipped';
  let textCheck = 'Failed';
  let contentCheck = 'Skipped';
  let cssCheck = 'Skipped';
EOF
# Button click
if [ ! -z "$BUTTON_TEXT" ]; then
cat >> "$SPEC_FILE" <<EOF
  try {
    await page.getByRole('button', { name: /$BUTTON_TEXT/i }).click();
    buttonCheck = 'Passed';
  } catch {
    buttonCheck = 'Failed';
  }
EOF
fi
# Standard getByText()
cat >> "$SPEC_FILE" <<EOF
  try {
    await expect(page.getByText('$TEXT_SEARCH')).toBeVisible();
    textCheck = 'Passed';
  } catch {
    textCheck = 'Failed';
  }
EOF
# Content-based search
if [ "$CONTENT_MODE" = "enabled" ]; then
cat >> "$SPEC_FILE" <<EOF
  try {
    const body = await page.textContent('body');
    if (body && body.includes("$CONTENT_TEXT")) {
      contentCheck = 'Passed';
    } else {
      contentCheck = 'Failed';
    }
  } catch {
    contentCheck = 'Failed';
  }
EOF
fi
# CSS Selector Search
if [ ! -z "$CSS_SELECTOR" ]; then
cat >> "$SPEC_FILE" <<EOF
  try {
    const list = await page.locator('$CSS_SELECTOR').allTextContents();
    if (list.some(x => x.includes("$CSS_TEXT"))) {
      cssCheck = 'Passed';
    } else {
      cssCheck = 'Failed';
    }
  } catch {
    cssCheck = 'Failed';
  }
EOF
fi
cat >> "$SPEC_FILE" <<EOF
  console.log("RESULT_JSON:" + JSON.stringify({
    buttonCheck,
    textCheck,
    contentCheck,
    cssCheck
  }));
});
EOF
# echo "INFO: Spec file created at $SPEC_FILE"
###############################
# Run Docker Runner           #
###############################
docker run --rm \\
    -v "$TEST_DIR/tests:/tests/tests" \\
    -v "$OUT_DIR:/tests/out" \\
    playwright-runner > "$LOG_FILE" 2>&1
RAW_JSON=$(grep "RESULT_JSON:" "$LOG_FILE" | sed 's/RESULT_JSON://')
if [ -z "$RAW_JSON" ]; then
    echo "CRITICAL: No JSON output received!"
    exit 2
fi
# Extract all statuses
BUTTON_STATUS=$(echo "$RAW_JSON" | jq -r '.buttonCheck')
TEXT_STATUS=$(echo "$RAW_JSON" | jq -r '.textCheck')
CONTENT_STATUS=$(echo "$RAW_JSON" | jq -r '.contentCheck')
CSS_STATUS=$(echo "$RAW_JSON" | jq -r '.cssCheck')
# Count totals
TOTAL=0
PASSED=0
FAILED=0
for item in "$BUTTON_STATUS" "$TEXT_STATUS" "$CONTENT_STATUS" "$CSS_STATUS"; do
    if [ "$item" = "Skipped" ]; then
        continue
    fi
    ((TOTAL++))
    if [ "$item" = "Passed" ]; then
        ((PASSED++))
    else
        ((FAILED++))
    fi
done
MSG="Website check: $PASSED/$TOTAL passed, $FAILED failed | Text: $TEXT_STATUS | Button: $BUTTON_STATUS | Content: $CONTENT_STATUS | CSS: $CSS_STATUS"
if [ "$FAILED" -gt 0 ]; then
    echo "CRITICAL: $MSG"
    exit 2
else
    echo "OK: $MSG"
    exit 0
fi

Running the Plugin

Example usage:

./check_website_content.sh -w "<https://www.firatgulec.com>" -t "Firat Gulec" -cc -c "Hot Air Balloon Map"
OK: Website check: 2/2 passed, 0 failed | Text: Passed | Button: Skipped | Content: Passed | CSS: Skipped
  • Checks that the page contains “Firat Gulec”.
  • Optionally clicks a button if provided.
  • Verifies that body content includes “Hot Air Balloon Map”.
  • Outputs status for Nagios.

Adding the Plugin to Nagios Using NConf

After creating the Playwright-based content monitoring plugin, the next step is to integrate it into Nagios so it can run as part of your regular checks. If you’re using NConf, the web-based configuration tool for Nagios, the process becomes much easier and more structured.

Below is a step-by-step guide explaining how to add the new plugin and create a Nagios service using NConf.

1. Place the Plugin in Nagios libexec

First, copy the plugin script into the Nagios libexec directory (or your custom plugin folder):

sudo cp check_website_content.sh /usr/local/nagios/libexec/
sudo chmod +x /usr/local/nagios/libexec/check_website_content.sh

If you followed the earlier structure, your Playwright test folder should be here:

/usr/local/nagios/libexec/check_website_content/product

This directory needs proper permissions: Permissions and volume mounts are critical to make Docker writable for Nagios:

sudo chown -R nagios:nagios /usr/local/nagios/libexec/check_website_content/product
sudo chmod -R 755 /usr/local/nagios/libexec/check_website_content/product
  • for container rights
sudo chmod -R 777 /usr/local/nagios/libexec/check_website_content/product/out
sudo chmod -R 777 /usr/local/nagios/libexec/check_website_content/product/tests

2. Define a Command in NConf

Open NConf Web UI and follow these steps:

➤ Navigate to “Advanced » Commands”

➤ Click “Add”

➤ Fill in the command details:

  • Name: check_website_content
  • Command line:

$USER1$/check_website_content.sh -w $ARG1$ -t $ARG2$ -b $ARG3$ -cc -c $ARG4$ -ss -s $ARG5$

This structure allows flexible arguments for URL, visible text, button clicks, content mode, CSS selector, and CSS text.

root@PCFIRAT:/FG-Script/playwright# ./check_website_content.sh -w "https://firatgulec.com" -t "Ballon" -c "Hot Air Balloon"
ERROR: -c and --cc must be used together.
root@PCFIRAT:/FG-Script/playwright# ./check_website_content.sh -help
Usage:
  ./check_website_content.sh -w <URL> -t <TEXT_SEARCH> [-b <BUTTON_TEXT>] [-c <CONTENT_TEXT> --cc content] [-s <CSS_TEXT> --ss <CSS_SELECTOR>]

Options:
  -w        URL of the page to test
  -t        Text to search using Playwright getByText()
  -b        Optional button text to click first

Content-based search (body text):
  -c        Text to find inside full page body text
  --cc      Enable content search mode (must be used with --cc then -c together)

CSS selector search:
  -s        Text to search inside items returned by CSS selector
  --ss      CSS selector (must be used with -s)

Examples:
  ./script.sh -w https://site -t "TEST" --cc -c "TestTEXT"
  ./script.sh -w https://site -t "TEST" --ss ".faq-title" -s "TestTEXT"

root@PCFIRAT:/FG-Script/playwright#

➤ Press Submit and Save.

3. Create a Service Using the Command

Now that the command exists, we can assign it to a host or host group.

➤ Go to “Basic » Services”

➤ Click “Add Service”

Fill in the following:

  • Service Name: Website Content Check
  • Check Command: check_website_content

After selecting the command, argument fields (ARG1–ARG7) will appear.

Example Arguments

ARG Value Description ARG1 https://www.firatgulec.com Website URL ARG2 Firat Gulec Text to check via getByText() ARG3 Agree Button text (optional) ARG4 Hot Air Balloon Map Text to find in body (optional)

If a parameter is not needed (e.g., no CSS checking), simply put: noneor leave the argument empty (NConf allows empty args depending on your config).

4. Assign to a Host

Under “Assign to hosts”, select:

Specific host Or a host group like: web-servers

Using NConf makes it much easier to manage custom Nagios plugins, especially when they require multiple arguments. Your Playwright-powered plugin becomes a flexible, powerful website monitoring tool that can be deployed across dozens of hosts without manually editing configuration files.

Conclusion

Combining Playwright with Nagios provides a modern, reliable way to monitor actual website content, not just uptime. By containerizing your tests, dynamically generating scripts, and integrating structured JSON output, you can create a scalable, automated monitoring system that catches issues before your users do.

This approach is flexible and can be adapted for almost any website or web application scenario, giving DevOps teams the visibility they need into site content integrity.

Feel free to check out the scripts on GitHub and contribute your improvements or suggestions. Happy testing!


메타데이터
post_id
4842075a1f96
slug
monitoring-website-content-with-playwright-and-nagios-4842075a1f96
url
https://medium.com/@firat-gulec/monitoring-website-content-with-playwright-and-nagios-4842075a1f96
canonical_url
https://medium.com/@firat-gulec/monitoring-website-content-with-playwright-and-nagios-4842075a1f96
author_url
https://medium.com/@firat-gulec
status
ok
fetched_at
2026-07-13 21:07:34