{
  "openapi": "3.0.1",
  "info": {
    "title": "Website Change Monitor – Diff & Webhook Alerts",
    "description": "Watch any web page, or one part of it, and get a before/after diff when it changes. Alerts by Slack, Discord or webhook. Ignores clocks and \"2 hours ago\", double-checks each change, renders JavaScript when needed. $1 per 1,000 checks + $5 per 1,000 changes.",
    "version": "0.1",
    "x-build-id": "VvFvucyDrYOZZVzYe"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/oldjard~website-change-monitor/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-oldjard-website-change-monitor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/oldjard~website-change-monitor/runs": {
      "post": {
        "operationId": "runs-sync-oldjard-website-change-monitor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/oldjard~website-change-monitor/run-sync": {
      "post": {
        "operationId": "run-sync-oldjard-website-change-monitor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "urls": {
            "title": "URLs to monitor",
            "type": "array",
            "description": "Pages to watch, one per line. Each run compares every page with what it saw last time. Bare domains like example.com/pricing work too.",
            "items": {
              "type": "string"
            }
          },
          "selector": {
            "title": "Part of the page to watch (optional)",
            "type": "string",
            "description": "A CSS selector (like #price or .product-title) or an XPath (starting with /) for the part of the page to watch. Leave empty to watch all the text on the page. Applies to every URL above; use Pages (advanced) to give each page its own."
          },
          "contentMode": {
            "title": "What to compare",
            "enum": [
              "text",
              "html",
              "attribute"
            ],
            "type": "string",
            "description": "Visible text catches what a person would notice. HTML also catches changes to links, images and markup. Attribute compares one attribute of the selected elements.",
            "default": "text"
          },
          "attribute": {
            "title": "Attribute name",
            "type": "string",
            "description": "Only for What to compare: An attribute. For example href, src, content or data-price."
          },
          "pages": {
            "title": "Pages (advanced)",
            "type": "array",
            "description": "Give each page its own settings. Each item: url (required), and optionally selector, contentMode, attribute, label (shown in alerts) and renderJavaScript. The same URL can appear more than once with different selectors."
          },
          "monitorName": {
            "title": "Monitor name",
            "type": "string",
            "description": "Snapshots are saved under this name (in a key-value store called change-monitor-&lt;name&gt;). Use a different name for each separate monitor or schedule, so they don't share snapshots.",
            "default": "default"
          },
          "renderJavaScript": {
            "title": "Render JavaScript",
            "enum": [
              "auto",
              "off",
              "always"
            ],
            "type": "string",
            "description": "Auto loads each page over plain HTTP first and opens it in headless Chrome only when the page is blocked, the selector isn't found, or the page is nearly empty without JavaScript. Once a page needs the browser it keeps using it, so snapshots stay comparable. Browser checks cost a little extra.",
            "default": "auto"
          },
          "screenshots": {
            "title": "Save screenshots",
            "type": "boolean",
            "description": "Take a screenshot of the watched part (or the first screen of the page) and link before/after screenshots in each change. Uses the browser for every page.",
            "default": false
          },
          "requestTimeoutSecs": {
            "title": "Page timeout (seconds)",
            "minimum": 5,
            "maximum": 120,
            "type": "integer",
            "description": "How long to wait for a page.",
            "default": 30
          },
          "maxConcurrency": {
            "title": "Pages at a time",
            "minimum": 1,
            "maximum": 25,
            "type": "integer",
            "description": "How many pages to check in parallel. Pages on the same site are always checked one at a time.",
            "default": 5
          },
          "ignoreNoise": {
            "title": "Ignore text that changes on every visit",
            "type": "array",
            "description": "These are masked before comparing, so a page whose only change is its clock or \"posted 5 minutes ago\" doesn't trigger an alert. The rest of each line is still compared.",
            "items": {
              "type": "string",
              "enum": [
                "times",
                "relative-times",
                "dates",
                "numbers"
              ],
              "enumTitles": [
                "Clock times (14:05, 2:05 PM)",
                "Relative times (5 minutes ago, yesterday)",
                "Dates (2026-10-05, Oct 5, 2026)",
                "All numbers (counters; hides price changes too)"
              ]
            },
            "default": [
              "times",
              "relative-times"
            ]
          },
          "ignorePatterns": {
            "title": "Ignore text matching (regex)",
            "type": "array",
            "description": "Regular expressions for text to ignore, matched case-insensitively. Example: Visitors: \\d+ or Ad #\\d+.",
            "items": {
              "type": "string"
            }
          },
          "ignoreSelectors": {
            "title": "Ignore page parts (CSS)",
            "type": "array",
            "description": "CSS selectors for parts of the page to remove before comparing, like cookie banners, ads or a \"related posts\" box. Example: .cookie-banner, #ads, footer.",
            "items": {
              "type": "string"
            }
          },
          "minChangeChars": {
            "title": "Minimum change size (characters)",
            "minimum": 0,
            "type": "integer",
            "description": "Ignore changes smaller than this many characters added plus removed. Small changes still count toward the next alert, because the baseline isn't updated until a change is reported.",
            "default": 0
          },
          "confirmChanges": {
            "title": "Double-check changes before alerting",
            "type": "boolean",
            "description": "When a change is seen, look again 3 seconds later. If the page is back to the saved version (A/B tests, rotating banners), no alert is sent.",
            "default": true
          },
          "webhookUrl": {
            "title": "Webhook URL",
            "type": "string",
            "description": "Where to send each change. Slack and Discord incoming-webhook URLs get a readable message; any other URL (Zapier, Make, n8n, your server) gets a JSON POST with the full diff."
          },
          "notifyEmail": {
            "title": "Email (beta)",
            "type": "string",
            "description": "Beta, not yet tested end to end: send one email per run listing every change (comma-separate several addresses). Sent with Apify's own send-mail actor, which some developer-only Apify plans can't run. For reliable email alerts, use a webhook to Zapier or Make."
          },
          "notifyOnErrors": {
            "title": "Also notify when a page can't be checked",
            "type": "boolean",
            "description": "Send a notification when a page is blocked, times out or returns an error. A watched part of a page that disappears is always reported, once.",
            "default": false
          },
          "saveUnchanged": {
            "title": "Save unchanged pages to the dataset",
            "type": "boolean",
            "description": "By default the dataset only gets changes, new baselines and pages that couldn't be checked. Turn this on to get a row for every page.",
            "default": false
          },
          "failRunOnErrors": {
            "title": "Fail the run if any page can't be checked",
            "type": "boolean",
            "description": "Mark the run as failed when a page is blocked or errors, so Apify's own failed-run alerts reach you. Off by default: changes on the other pages are still detected and reported either way.",
            "default": false
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}