- ChangeDetection.io Web page monitoring and notifications API
  - Where to find my API key?
  - Connection URL
  - Authentication
- Watch Management
  - getList all watches
  - postCreate a new watch
  - getGet single watch
  - putUpdate watch
  - delDelete watch
- Watch History
  - getGet watch history
  - getGet the difference between two snapshots
- Snapshots
  - getGet single snapshot
- Favicon
  - getGet watch favicon
- Group / Tag Management
  - getList all tags
  - postCreate tag
  - getGet single tag
  - putUpdate tag
  - delDelete tag
- Notifications
  - getGet notification URLs
  - postAdd notification URLs
  - putReplace notification URLs
  - delDelete notification URLs
- Search
  - getSearch watches
- Import
  - postImport watch URLs with configuration
- System Information
  - getGet system information
- Plugin API Extensions
  - How Processor Plugins Extend the API
  - getGet full live API spec

API docs by Redocly

# ChangeDetection.io API (0.1.7)

Download OpenAPI specification:

URL: https://github.com/dgtlmoon/changedetection.io License: Apache 2.0

## ChangeDetection.io Web page monitoring and notifications API

REST API for managing Page watches, Group tags, and Notifications.

changedetection.io can be driven by its built in simple API, in the examples below you will also find `curl` command line and `python` examples to help you get started faster.

## Where to find my API key?

The API key can be easily found under the SETTINGS then API tab of changedetection.io dashboard.
Simply click the API key to automatically copy it to your clipboard.

## Connection URL

The API can be found at `/api/v1/`, so for example if you run changedetection.io locally on port 5000, then URL would be `http://localhost:5000/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091/history`.

If you are using the hosted/subscription version of changedetection.io, then the URL is based on your login URL, for example:
`https://<your login url>/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091/history`

## Authentication

Almost all API requests require some authentication, this is provided as an API Key in the header of the HTTP request.

For example: `x-api-key: YOUR_API_KEY`

## Watch Management

Core functionality for managing web page monitors. Create, retrieve, update, and delete individual watches. Each watch represents a single URL being monitored for changes, with configurable settings for check intervals, notification preferences, and content filtering options.

## List all watches

Return concise list of available web page change monitors (watches) and basic info

##### Authorizations:

ApiKeyAuth

##### query Parameters

recheck_all | string Value: "1" Set to 1 to force recheck of all watches
tag | string Tag name to filter results

### Responses

Development server

http://localhost:5000/api/v1/watch

Production server

https://yourdomain.com/api/v1/watch

Custom server

{protocol}://{host}/api/v1/watch

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/watch" \
      -H "x-api-key: YOUR_API_KEY"

### Response samples

- 200

Content type
application/json
`
{

- "095be615-a8ad-4c33-8e9c-c7612fbf6c9f":
  {
  - "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
  - "url": "http://example.com?id={{1+1}} - the raw URL",
  - "link": "http://example.com?id=2 - the rendered URL, always use this for listing.",
  - "title": "Example Website Monitor - manually entered title/description",
  - "page_title": "The HTML <title> from the page",
  - "tags":
    [
    - "550e8400-e29b-41d4-a716-446655440000"
    ],
  - "paused": false,
  - "notification_muted": false,
  - "method": "GET",
  - "fetch_backend": "html_requests",
  - "last_checked": 1640995200,
  - "last_changed": 1640995200
  },
- "7c9e6b8d-f2a1-4e5c-9d3b-8a7f6e4c2d1a":
  {
  - "uuid": "7c9e6b8d-f2a1-4e5c-9d3b-8a7f6e4c2d1a",
  - "url": "http://example.com?id={{1+1}} - the raw URL",
  - "link": "http://example.com?id=2 - the rendered URL, always use this for listing.",
  - "title": "News Site Tracker - manually entered title/description",
  - "page_title": "The HTML <title> from the page",
  - "tags":
    [
    - "330e8400-e29b-41d4-a716-446655440001"
    ],
  - "paused": false,
  - "notification_muted": true,
  - "method": "GET",
  - "fetch_backend": "html_webdriver",
  - "last_checked": 1640998800,
  - "last_changed": 1640995200
  }

}`

## Create a new watch

Create a single web page change monitor (watch). Requires at least `url` to be set.

Every watch can be configured with:

- Processor mode: `processor` field (`restock_diff` or `text_json_diff` - default)
- Notification settings: `notification_urls` (array), `notification_title`, `notification_body`, `notification_format`, `notification_muted`
- Tags/Groups: `tag` (UUID string) or `tags` (array of UUIDs)
- Check settings: `time_between_check`, `paused`, `method`, `fetch_backend`
- Advanced options: `headers`, `body`, `proxy`, `browser_steps`, and more

##### Authorizations:

ApiKeyAuth

##### Request Body schema: application/json
required

url required | string <uri> <= 5000 characters URL to monitor for changes
title | string or null <= 5000 characters Custom title for the web page change monitor (watch), not to be confused with page_title
tag | string <= 5000 characters Tag UUID to associate with this web page change monitor (watch)
tags | Array of strings Array of tag UUIDs
paused | boolean Whether the web page change monitor (watch) is paused
notification_muted | boolean Whether notifications are muted
method | string Enum: "GET" "POST" "DELETE" "PUT" HTTP method to use

fetch_backend

string^(system|html_requests|html_webdriver|extra_b...
Default: "system"

Backend to use for fetching content. Common values:

- `system` (default) - Use the system-wide default fetcher
- `html_requests` - Fast requests-based fetcher
- `html_webdriver` - Browser-based fetcher (Playwright/Puppeteer)
- `extra_browser_*` - Custom browser configurations (if configured)
- Plugin-provided fetchers (if installed)

| object HTTP headers to include in requests
body | string or null <= 5000 characters HTTP request body
proxy | string or null <= 5000 characters Proxy configuration
ignore_status_codes | boolean or null Ignore HTTP status code errors (boolean or null)
webdriver_delay | integer or null Delay in seconds for webdriver
webdriver_js_execute_code | string or null <= 5000 characters JavaScript code to execute
| object Time intervals between checks. All fields must be non-negative. At least one non-zero value required when not using default settings.
time_between_check_use_default | boolean Default: true Whether to use global settings for time between checks - defaults to true if not set
notification_urls | Array of strings <= 100 items [ items <= 1000 characters ] Notification URLs for this web page change monitor (watch). Maximum 100 URLs.
notification_title | string or null <= 5000 characters Custom notification title
notification_body | string or null <= 5000 characters Custom notification body
notification_format | string Enum: "text" "html" "htmlcolor" "markdown" "System default" Format for notifications
track_ldjson_price_data | boolean or null Whether to track JSON-LD price data
| Array of objects <= 100 items Browser automation steps. Maximum 100 steps allowed.
processor | string Default: "text_json_diff" Enum: "restock_diff" "text_json_diff" Optional processor mode to use for change detection. Defaults to `text_json_diff` if not specified.
include_filters | Array of strings <= 100 items [ items <= 5000 characters ] CSS/XPath selectors to extract specific content from the page
subtractive_selectors | Array of strings <= 100 items [ items <= 5000 characters ] CSS/XPath selectors to remove content from the page
ignore_text | Array of strings <= 100 items [ items <= 5000 characters ] Text patterns to ignore in change detection
trigger_text | Array of strings <= 100 items [ items <= 5000 characters ] Text/regex patterns that must be present to trigger a change
text_should_not_be_present | Array of strings <= 100 items [ items <= 5000 characters ] Text that should NOT be present (triggers alert if found)
extract_lines_containing | Array of strings <= 100 items [ items <= 5000 characters ] Keep only lines containing these substrings (plain text, case-insensitive) — simpler alternative to regex
extract_text | Array of strings <= 100 items [ items <= 5000 characters ] Regex patterns to extract specific text after filtering
trim_text_whitespace | boolean Default: false Strip leading/trailing whitespace from text
sort_text_alphabetically | boolean Default: false Sort lines alphabetically before comparison
remove_duplicate_lines | boolean Default: false Remove duplicate lines from content
check_unique_lines | boolean Default: false Compare against all history for unique lines
strip_ignored_lines | boolean or null Remove lines matching ignore patterns
filter_text_added | boolean Default: true Include added text in change detection
filter_text_removed | boolean Default: true Include removed text in change detection
filter_text_replaced | boolean Default: true Include replaced text in change detection
in_stock_only | boolean Default: true Only trigger on in-stock transitions (restock_diff processor)
follow_price_changes | boolean Default: true Monitor and track price changes (restock_diff processor)
price_change_threshold_percent | number or null Minimum price change percentage to trigger notification
notification_screenshot | boolean Default: false Include screenshot in notifications (if supported by notification URL)
filter_failure_notification_send | boolean Default: true Send notification when filters fail to match content
use_page_title_in_list | boolean or null Display page title in watch list (null = use system default)
history_snapshot_max_length | integer or null [ 1 .. 1000 ] Maximum number of history snapshots to keep (null = use system default)
| object Weekly schedule limiting when checks can run
| Array of objects <= 100 items Array of condition rules for change detection logic (empty array when not set)
conditions_match_logic | string Default: "ALL" Enum: "ALL" "ANY" Logic operator - ALL (match all conditions) or ANY (match any condition)
llm_intent | string <= 2000 characters Default: "" Plain-English intent for AI-based change filtering. The AI evaluates every detected change against this and only notifies when it matches.
llm_change_summary | string <= 2000 characters Default: "" Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.
llm_change_summary_mode | string Default: "replace" Enum: "replace" "append" Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.

### Responses

Development server

http://localhost:5000/api/v1/watch

Production server

https://yourdomain.com/api/v1/watch

Custom server

{protocol}://{host}/api/v1/watch

### Request samples

- Payload
- curl
- Python

Content type
application/json
`
{

- "url": "https://example.com",
- "title": "Example Site Monitor",
- "time_between_check":
  {
  - "hours": 1
  }

}`

## Get single watch

Retrieve web page change monitor (watch) information and set muted/paused status. Returns the FULL Watch JSON.

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Web page change monitor (watch) unique ID

##### query Parameters

recheck | string Enum: "1" "true" Recheck this web page change monitor (watch)
paused | string Enum: "paused" "unpaused" Set pause state
muted | string Enum: "muted" "unmuted" Set mute state

### Responses

Development server

http://localhost:5000/api/v1/watch/{uuid}

Production server

https://yourdomain.com/api/v1/watch/{uuid}

Custom server

{protocol}://{host}/api/v1/watch/{uuid}

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f" \
      -H "x-api-key: YOUR_API_KEY"

### Response samples

- 200
- 404

Content type
application/json
`
{

- "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
- "date_created": 0,
- "url": "http://example.com",
- "title": "string",
- "tag": "string",
- "tags":
  [
  - "string"
  ],
- "paused": true,
- "notification_muted": true,
- "method": "GET",
- "fetch_backend": "system",
- "headers":
  {
  - "property1": "string",
  - "property2": "string"
  },
- "body": "string",
- "proxy": "string",
- "ignore_status_codes": true,
- "webdriver_delay": 0,
- "webdriver_js_execute_code": "string",
- "time_between_check":
  {
  - "weeks": 52000,
  - "days": 365000,
  - "hours": 8760000,
  - "minutes": 525600000,
  - "seconds": 31536000000
  },
- "time_between_check_use_default": true,
- "notification_urls":
  [
  - "string"
  ],
- "notification_title": "string",
- "notification_body": "string",
- "notification_format": "text",
- "track_ldjson_price_data": true,
- "browser_steps":
  [
  - {
    - "operation": "string",
    - "selector": "string",
    - "optional_value": "string"
    }
  ],
- "processor": "restock_diff",
- "include_filters":
  [
  - "string"
  ],
- "subtractive_selectors":
  [
  - "string"
  ],
- "ignore_text":
  [
  - "string"
  ],
- "trigger_text":
  [
  - "string"
  ],
- "text_should_not_be_present":
  [
  - "string"
  ],
- "extract_lines_containing":
  [
  - "string"
  ],
- "extract_text":
  [
  - "string"
  ],
- "trim_text_whitespace": false,
- "sort_text_alphabetically": false,
- "remove_duplicate_lines": false,
- "check_unique_lines": false,
- "strip_ignored_lines": true,
- "filter_text_added": true,
- "filter_text_removed": true,
- "filter_text_replaced": true,
- "in_stock_only": true,
- "follow_price_changes": true,
- "price_change_threshold_percent": 0,
- "has_ldjson_price_data": true,
- "notification_screenshot": false,
- "filter_failure_notification_send": true,
- "use_page_title_in_list": true,
- "history_snapshot_max_length": 1,
- "time_schedule_limit":
  {
  - "enabled": false,
  - "monday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "tuesday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "wednesday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "thursday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "friday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "saturday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "sunday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    }
  },
- "conditions":
  [
  - {
    - "field": "string",
    - "operator": "string",
    - "value": "string"
    }
  ],
- "conditions_match_logic": "ALL",
- "llm_intent": "",
- "llm_change_summary": "",
- "llm_change_summary_mode": "replace",
- "llm_prefilter": "string",
- "llm_evaluation_cache": { },
- "llm_last_tokens_used": 0,
- "llm_tokens_used_cumulative": 0,
- "llm_tokens_this_period": 0,
- "llm_tokens_period_key": "string",
- "last_checked": 0,
- "last_changed": 0,
- "last_error": "string",
- "last_viewed": 0,
- "link": "string",
- "page_title": "string",
- "check_count": 0,
- "fetch_time": 0,
- "previous_md5": "string",
- "previous_md5_before_filters": "string",
- "consecutive_filter_failures": 0,
- "last_notification_error": "string",
- "notification_alert_count": 0,
- "content-type": "string",
- "remote_server_reply": "string",
- "browser_steps_last_error_step": 0,
- "viewed": 0,
- "history_n": 0,
- "processor_config_restock_diff":
  {
  - "in_stock_processing": "in_stock_only",
  - "follow_price_changes": true,
  - "price_change_min": 0,
  - "price_change_max": 0,
  - "price_change_threshold_percent": 100
  },
- "processor_config_restock_diff_source": "string"

}`

## Update watch

Update an existing web page change monitor (watch) using JSON. Accepts the same structure as returned in get single watch information.

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Web page change monitor (watch) unique ID

##### Request Body schema: application/json
required

url | string <uri> <= 5000 characters URL to monitor for changes
title | string or null <= 5000 characters Custom title for the web page change monitor (watch), not to be confused with page_title
tag | string <= 5000 characters Tag UUID to associate with this web page change monitor (watch)
tags | Array of strings Array of tag UUIDs
paused | boolean Whether the web page change monitor (watch) is paused
notification_muted | boolean Whether notifications are muted
method | string Enum: "GET" "POST" "DELETE" "PUT" HTTP method to use

fetch_backend

string^(system|html_requests|html_webdriver|extra_b...
Default: "system"

Backend to use for fetching content. Common values:

- `system` (default) - Use the system-wide default fetcher
- `html_requests` - Fast requests-based fetcher
- `html_webdriver` - Browser-based fetcher (Playwright/Puppeteer)
- `extra_browser_*` - Custom browser configurations (if configured)
- Plugin-provided fetchers (if installed)

| object HTTP headers to include in requests
body | string or null <= 5000 characters HTTP request body
proxy | string or null <= 5000 characters Proxy configuration
ignore_status_codes | boolean or null Ignore HTTP status code errors (boolean or null)
webdriver_delay | integer or null Delay in seconds for webdriver
webdriver_js_execute_code | string or null <= 5000 characters JavaScript code to execute
| object Time intervals between checks. All fields must be non-negative. At least one non-zero value required when not using default settings.
time_between_check_use_default | boolean Default: true Whether to use global settings for time between checks - defaults to true if not set
notification_urls | Array of strings <= 100 items [ items <= 1000 characters ] Notification URLs for this web page change monitor (watch). Maximum 100 URLs.
notification_title | string or null <= 5000 characters Custom notification title
notification_body | string or null <= 5000 characters Custom notification body
notification_format | string Enum: "text" "html" "htmlcolor" "markdown" "System default" Format for notifications
track_ldjson_price_data | boolean or null Whether to track JSON-LD price data
| Array of objects <= 100 items Browser automation steps. Maximum 100 steps allowed.
processor | string Default: "text_json_diff" Enum: "restock_diff" "text_json_diff" Optional processor mode to use for change detection. Defaults to `text_json_diff` if not specified.
include_filters | Array of strings <= 100 items [ items <= 5000 characters ] CSS/XPath selectors to extract specific content from the page
subtractive_selectors | Array of strings <= 100 items [ items <= 5000 characters ] CSS/XPath selectors to remove content from the page
ignore_text | Array of strings <= 100 items [ items <= 5000 characters ] Text patterns to ignore in change detection
trigger_text | Array of strings <= 100 items [ items <= 5000 characters ] Text/regex patterns that must be present to trigger a change
text_should_not_be_present | Array of strings <= 100 items [ items <= 5000 characters ] Text that should NOT be present (triggers alert if found)
extract_lines_containing | Array of strings <= 100 items [ items <= 5000 characters ] Keep only lines containing these substrings (plain text, case-insensitive) — simpler alternative to regex
extract_text | Array of strings <= 100 items [ items <= 5000 characters ] Regex patterns to extract specific text after filtering
trim_text_whitespace | boolean Default: false Strip leading/trailing whitespace from text
sort_text_alphabetically | boolean Default: false Sort lines alphabetically before comparison
remove_duplicate_lines | boolean Default: false Remove duplicate lines from content
check_unique_lines | boolean Default: false Compare against all history for unique lines
strip_ignored_lines | boolean or null Remove lines matching ignore patterns
filter_text_added | boolean Default: true Include added text in change detection
filter_text_removed | boolean Default: true Include removed text in change detection
filter_text_replaced | boolean Default: true Include replaced text in change detection
in_stock_only | boolean Default: true Only trigger on in-stock transitions (restock_diff processor)
follow_price_changes | boolean Default: true Monitor and track price changes (restock_diff processor)
price_change_threshold_percent | number or null Minimum price change percentage to trigger notification
notification_screenshot | boolean Default: false Include screenshot in notifications (if supported by notification URL)
filter_failure_notification_send | boolean Default: true Send notification when filters fail to match content
use_page_title_in_list | boolean or null Display page title in watch list (null = use system default)
history_snapshot_max_length | integer or null [ 1 .. 1000 ] Maximum number of history snapshots to keep (null = use system default)
| object Weekly schedule limiting when checks can run
| Array of objects <= 100 items Array of condition rules for change detection logic (empty array when not set)
conditions_match_logic | string Default: "ALL" Enum: "ALL" "ANY" Logic operator - ALL (match all conditions) or ANY (match any condition)
llm_intent | string <= 2000 characters Default: "" Plain-English intent for AI-based change filtering. The AI evaluates every detected change against this and only notifies when it matches.
llm_change_summary | string <= 2000 characters Default: "" Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.
llm_change_summary_mode | string Default: "replace" Enum: "replace" "append" Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.
last_viewed | integer >= 0 Unix timestamp in seconds of the last time the watch was viewed. Setting it to a value higher than `last_changed` in the "Update watch" endpoint marks the watch as viewed.

### Responses

Development server

http://localhost:5000/api/v1/watch/{uuid}

Production server

https://yourdomain.com/api/v1/watch/{uuid}

Custom server

{protocol}://{host}/api/v1/watch/{uuid}

### Request samples

- Payload
- curl
- Python

Content type
application/json
`
{

- "url": "http://example.com",
- "title": "string",
- "tag": "string",
- "tags":
  [
  - "string"
  ],
- "paused": true,
- "notification_muted": true,
- "method": "GET",
- "fetch_backend": "system",
- "headers":
  {
  - "property1": "string",
  - "property2": "string"
  },
- "body": "string",
- "proxy": "string",
- "ignore_status_codes": true,
- "webdriver_delay": 0,
- "webdriver_js_execute_code": "string",
- "time_between_check":
  {
  - "weeks": 52000,
  - "days": 365000,
  - "hours": 8760000,
  - "minutes": 525600000,
  - "seconds": 31536000000
  },
- "time_between_check_use_default": true,
- "notification_urls":
  [
  - "string"
  ],
- "notification_title": "string",
- "notification_body": "string",
- "notification_format": "text",
- "track_ldjson_price_data": true,
- "browser_steps":
  [
  - {
    - "operation": "string",
    - "selector": "string",
    - "optional_value": "string"
    }
  ],
- "processor": "restock_diff",
- "include_filters":
  [
  - "string"
  ],
- "subtractive_selectors":
  [
  - "string"
  ],
- "ignore_text":
  [
  - "string"
  ],
- "trigger_text":
  [
  - "string"
  ],
- "text_should_not_be_present":
  [
  - "string"
  ],
- "extract_lines_containing":
  [
  - "string"
  ],
- "extract_text":
  [
  - "string"
  ],
- "trim_text_whitespace": false,
- "sort_text_alphabetically": false,
- "remove_duplicate_lines": false,
- "check_unique_lines": false,
- "strip_ignored_lines": true,
- "filter_text_added": true,
- "filter_text_removed": true,
- "filter_text_replaced": true,
- "in_stock_only": true,
- "follow_price_changes": true,
- "price_change_threshold_percent": 0,
- "notification_screenshot": false,
- "filter_failure_notification_send": true,
- "use_page_title_in_list": true,
- "history_snapshot_max_length": 1,
- "time_schedule_limit":
  {
  - "enabled": false,
  - "monday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "tuesday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "wednesday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "thursday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "friday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "saturday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "sunday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    }
  },
- "conditions":
  [
  - {
    - "field": "string",
    - "operator": "string",
    - "value": "string"
    }
  ],
- "conditions_match_logic": "ALL",
- "llm_intent": "",
- "llm_change_summary": "",
- "llm_change_summary_mode": "replace",
- "last_viewed": 0

}`

## Delete watch

Delete a web page change monitor (watch) and all related history

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Web page change monitor (watch) unique ID

### Responses

Development server

http://localhost:5000/api/v1/watch/{uuid}

Production server

https://yourdomain.com/api/v1/watch/{uuid}

Custom server

{protocol}://{host}/api/v1/watch/{uuid}

### Request samples

- curl
- Python

    curl -X DELETE "http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f" \
      -H "x-api-key: YOUR_API_KEY"

## Watch History

Get a list of timestamps of all changes detected for a watch.

## Get watch history

Get a list of all historical snapshots available for a web page change monitor (watch), use the key `timestamp` as the query argument for fetching a single watch history snapshot.

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Web page change monitor (watch) unique ID

### Responses

Development server

http://localhost:5000/api/v1/watch/{uuid}/history

Production server

https://yourdomain.com/api/v1/watch/{uuid}/history

Custom server

{protocol}://{host}/api/v1/watch/{uuid}/history

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f/history" \
      -H "x-api-key: YOUR_API_KEY"

### Response samples

- 200

Content type
application/json
`
{

- "1640995200": "/path/to/snapshot1.txt",
- "1640998800": "/path/to/snapshot2.txt"

}`

## Get the difference between two snapshots

Generate a difference (comparison) between two historical snapshots of a web page change monitor (watch).

This endpoint compares content between two points in time and returns the differences in your chosen format. Perfect for reviewing what changed between specific versions or comparing recent changes.

Timestamp Keywords:

- Use `'latest'` for the most recent snapshot (to_timestamp)
- Use `'previous'` for the second-most-recent snapshot (from_timestamp)
- Or use specific Unix timestamps from the watch history

Format Options:

- `text` (default): Plain text with (removed) and (added) prefixes
- `html`: HTML format with (removed) and (added) text
- `htmlcolor`: Rich HTML with colored highlights (green for additions, red for deletions)

Word-Level Diffing:

- Enable word-level granularity with `word_diff=true` for detailed inline comparisons
- Disable with `word_diff=false` for line-level comparisons only (default false/off, line-level mode by default)

Raw Diff Output:

- Use `no_markup=true` to get raw diff content without any formatting applied
- Returns content with placeholders for opening/closing tags of changes
- Allows you to implement your own custom colorisation or formatting
- Skips all HTML color application and service tweaks (added text, html color tags, etc)

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Web page change monitor (watch) unique ID
required | integer or string Example: previous Starting snapshot timestamp, 'previous' for second-most-recent, or specific Unix timestamp
required | integer or string Example: latest Ending snapshot timestamp, 'latest' for most recent, or specific Unix timestamp

##### query Parameters

format

string
Default: "text"
Enum: "text" "html" "htmlcolor" "markdown"

Output format for the diff:

- `text` (default): Plain text with (removed) and (added) prefixes
- `html`: Basic HTML format
- `htmlcolor`: Rich HTML with colored backgrounds (red for deletions, green for additions)
- `markdown`: Markdown format with HTML rendering

word_diff | string Default: "false" Enum: "true" "false" "1" "0" "yes" "no" "on" "off" Enable word-level diffing for more granular comparisons. When enabled, changes are highlighted at the word level rather than line level. Default is false (line-level mode). Accepts: true, false, 1, 0, yes, no, on, off

no_markup

string
Default: "false"
Enum: "true" "false" "1" "0" "yes" "no" "on" "off"

When set to true, returns the raw diff content without any markup formatting. The content will include placeholders for opening/closing tags of the changes, allowing you to implement your own custom colorisation or formatting. This skips all HTML color application and service tweaks. Accepts: true, false, 1, 0, yes, no, on, off

type

string
Default: "diffLines"
Enum: "diffLines" "diffWords"

Diff granularity type:

- `diffLines` (default): Line-level comparison, showing which lines changed
- `diffWords`: Word-level comparison, showing which words changed within lines

This parameter is an alternative to `word_diff` for better alignment with the UI. If both are specified, `type=diffWords` will enable word-level diffing.

changesOnly | string Default: "true" Enum: "true" "false" "1" "0" "yes" "no" "on" "off" When enabled, only show lines/content that changed (no surrounding context). When disabled, include unchanged lines for context around changes. Accepts: true, false, 1, 0, yes, no, on, off
ignoreWhitespace | string Default: "false" Enum: "true" "false" "1" "0" "yes" "no" "on" "off" When enabled, ignore whitespace-only changes (spaces, tabs, newlines). Useful for focusing on content changes and ignoring formatting differences. Accepts: true, false, 1, 0, yes, no, on, off
removed | string Default: "true" Enum: "true" "false" "1" "0" "yes" "no" "on" "off" Include removed/deleted content in the diff output. When disabled, content that was deleted will not appear in the diff. Accepts: true, false, 1, 0, yes, no, on, off
added | string Default: "true" Enum: "true" "false" "1" "0" "yes" "no" "on" "off" Include added/new content in the diff output. When disabled, content that was added will not appear in the diff. Accepts: true, false, 1, 0, yes, no, on, off
replaced | string Default: "true" Enum: "true" "false" "1" "0" "yes" "no" "on" "off" Include replaced/modified content in the diff output. When disabled, content that was modified (changed from one value to another) will not appear in the diff. Accepts: true, false, 1, 0, yes, no, on, off

### Responses

Development server

http://localhost:5000/api/v1/watch/{uuid}/difference/{from_timestamp}/{to_timestamp}

Production server

https://yourdomain.com/api/v1/watch/{uuid}/difference/{from_timestamp}/{to_timestamp}

Custom server

{protocol}://{host}/api/v1/watch/{uuid}/difference/{from_timestamp}/{to_timestamp}

### Request samples

- curl
- Python

    # Compare previous snapshot to latest with colored HTML
    curl -X GET "http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f/difference/previous/latest?format=htmlcolor" \
      -H "x-api-key: YOUR_API_KEY"

    # Compare two specific timestamps in plain text with word-level diff
    curl -X GET "http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f/difference/1640995200/1640998800?format=text&word_diff=true" \
      -H "x-api-key: YOUR_API_KEY"

    # Show only additions (hide removed/replaced content), ignore whitespace
    curl -X GET "http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f/difference/previous/latest?format=htmlcolor&removed=false&replaced=false&ignoreWhitespace=true" \
      -H "x-api-key: YOUR_API_KEY"

## Snapshots

Retrieve individual text snapshot of monitored content according to the `timestamp`. The text snapshot is the HTML to Text at page check time.

Set the query argument `html` to any value to retrieve the last HTML fetched, the system only keeps the last two (2) HTML files fetched.

Use the Watch History API endpoint to get a list of timestamps to pass to this query.

## Get single snapshot

Get single snapshot from web page change monitor (watch). Use 'latest' for the most recent snapshot. Use the Watch History API to get a list of timestamps to pass.

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Web page change monitor (watch) unique ID
required | integer or string Snapshot timestamp or 'latest'

##### query Parameters

html | string Value: "1" Set to 1 to return the last HTML

### Responses

Development server

http://localhost:5000/api/v1/watch/{uuid}/history/{timestamp}

Production server

https://yourdomain.com/api/v1/watch/{uuid}/history/{timestamp}

Custom server

{protocol}://{host}/api/v1/watch/{uuid}/history/{timestamp}

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f/history/latest" \
      -H "x-api-key: YOUR_API_KEY"

## Favicon

Retrieve favicon images associated with monitored web pages. These are used in the dashboard interface to visually identify different watches in your monitoring list.

## Get watch favicon

Get the favicon for a web page change monitor (watch) as displayed in the watch overview list.

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Web page change monitor (watch) unique ID

### Responses

Development server

http://localhost:5000/api/v1/watch/{uuid}/favicon

Production server

https://yourdomain.com/api/v1/watch/{uuid}/favicon

Custom server

{protocol}://{host}/api/v1/watch/{uuid}/favicon

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f/favicon" \
      -H "x-api-key: YOUR_API_KEY" \
      --output favicon.ico

## Group / Tag Management

Organize your watches using tags and groups. Tags (also known as Groups) allow you to categorize monitors, set group-wide notification preferences, and perform bulk operations like mass rechecking or status changes across multiple related watches.

## List all tags

Return list of available tags/groups

##### Authorizations:

ApiKeyAuth

### Responses

Development server

http://localhost:5000/api/v1/tags

Production server

https://yourdomain.com/api/v1/tags

Custom server

{protocol}://{host}/api/v1/tags

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/tags" \
      -H "x-api-key: YOUR_API_KEY"

### Response samples

- 200

Content type
application/json
`
{

- "550e8400-e29b-41d4-a716-446655440000":
  {
  - "uuid": "550e8400-e29b-41d4-a716-446655440000",
  - "title": "Production Sites",
  - "notification_urls":
    [
    - "mailto:admin@example.com"
    ],
  - "notification_muted": false
  },
- "330e8400-e29b-41d4-a716-446655440001":
  {
  - "uuid": "330e8400-e29b-41d4-a716-446655440001",
  - "title": "News Sources",
  - "notification_urls":
    [
    - "discord://webhook_id/webhook_token"
    ],
  - "notification_muted": false
  }

}`

## Create tag

Create a single tag/group

##### Authorizations:

ApiKeyAuth

##### Request Body schema: application/json
required

url | string <uri> <= 5000 characters URL to monitor for changes
title required | string or null <= 5000 characters Custom title for the web page change monitor (watch), not to be confused with page_title
tag | string <= 5000 characters Tag UUID to associate with this web page change monitor (watch)
tags | Array of strings Array of tag UUIDs
paused | boolean Whether the web page change monitor (watch) is paused
notification_muted | boolean Whether notifications are muted
method | string Enum: "GET" "POST" "DELETE" "PUT" HTTP method to use

fetch_backend

string^(system|html_requests|html_webdriver|extra_b...
Default: "system"

Backend to use for fetching content. Common values:

- `system` (default) - Use the system-wide default fetcher
- `html_requests` - Fast requests-based fetcher
- `html_webdriver` - Browser-based fetcher (Playwright/Puppeteer)
- `extra_browser_*` - Custom browser configurations (if configured)
- Plugin-provided fetchers (if installed)

| object HTTP headers to include in requests
body | string or null <= 5000 characters HTTP request body
proxy | string or null <= 5000 characters Proxy configuration
ignore_status_codes | boolean or null Ignore HTTP status code errors (boolean or null)
webdriver_delay | integer or null Delay in seconds for webdriver
webdriver_js_execute_code | string or null <= 5000 characters JavaScript code to execute
| object Time intervals between checks. All fields must be non-negative. At least one non-zero value required when not using default settings.
time_between_check_use_default | boolean Default: true Whether to use global settings for time between checks - defaults to true if not set
notification_urls | Array of strings <= 100 items [ items <= 1000 characters ] Notification URLs for this web page change monitor (watch). Maximum 100 URLs.
notification_title | string or null <= 5000 characters Custom notification title
notification_body | string or null <= 5000 characters Custom notification body
notification_format | string Enum: "text" "html" "htmlcolor" "markdown" "System default" Format for notifications
track_ldjson_price_data | boolean or null Whether to track JSON-LD price data
| Array of objects <= 100 items Browser automation steps. Maximum 100 steps allowed.
processor | string Default: "text_json_diff" Enum: "restock_diff" "text_json_diff" Optional processor mode to use for change detection. Defaults to `text_json_diff` if not specified.
include_filters | Array of strings <= 100 items [ items <= 5000 characters ] CSS/XPath selectors to extract specific content from the page
subtractive_selectors | Array of strings <= 100 items [ items <= 5000 characters ] CSS/XPath selectors to remove content from the page
ignore_text | Array of strings <= 100 items [ items <= 5000 characters ] Text patterns to ignore in change detection
trigger_text | Array of strings <= 100 items [ items <= 5000 characters ] Text/regex patterns that must be present to trigger a change
text_should_not_be_present | Array of strings <= 100 items [ items <= 5000 characters ] Text that should NOT be present (triggers alert if found)
extract_lines_containing | Array of strings <= 100 items [ items <= 5000 characters ] Keep only lines containing these substrings (plain text, case-insensitive) — simpler alternative to regex
extract_text | Array of strings <= 100 items [ items <= 5000 characters ] Regex patterns to extract specific text after filtering
trim_text_whitespace | boolean Default: false Strip leading/trailing whitespace from text
sort_text_alphabetically | boolean Default: false Sort lines alphabetically before comparison
remove_duplicate_lines | boolean Default: false Remove duplicate lines from content
check_unique_lines | boolean Default: false Compare against all history for unique lines
strip_ignored_lines | boolean or null Remove lines matching ignore patterns
filter_text_added | boolean Default: true Include added text in change detection
filter_text_removed | boolean Default: true Include removed text in change detection
filter_text_replaced | boolean Default: true Include replaced text in change detection
in_stock_only | boolean Default: true Only trigger on in-stock transitions (restock_diff processor)
follow_price_changes | boolean Default: true Monitor and track price changes (restock_diff processor)
price_change_threshold_percent | number or null Minimum price change percentage to trigger notification
notification_screenshot | boolean Default: false Include screenshot in notifications (if supported by notification URL)
filter_failure_notification_send | boolean Default: true Send notification when filters fail to match content
use_page_title_in_list | boolean or null Display page title in watch list (null = use system default)
history_snapshot_max_length | integer or null [ 1 .. 1000 ] Maximum number of history snapshots to keep (null = use system default)
| object Weekly schedule limiting when checks can run
| Array of objects <= 100 items Array of condition rules for change detection logic (empty array when not set)
conditions_match_logic | string Default: "ALL" Enum: "ALL" "ANY" Logic operator - ALL (match all conditions) or ANY (match any condition)
llm_intent | string <= 2000 characters Default: "" Plain-English intent for AI-based change filtering. The AI evaluates every detected change against this and only notifies when it matches.
llm_change_summary | string <= 2000 characters Default: "" Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.
llm_change_summary_mode | string Default: "replace" Enum: "replace" "append" Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.

overrides_watch

boolean or null

Whether this tag's settings override watch settings for all watches in this tag/group.

- true: Tag settings override watch settings
- false: Tag settings do not override (watches use their own settings)
- null: Not decided yet / inherit default behavior

url_match_pattern | string Automatically apply this tag to any watch whose URL matches this pattern. Supports fnmatch wildcards (* and ?): e.g. ://example.com/ or github.com/myorg. Plain strings are matched as case-insensitive substrings. Leave empty to disable auto-matching.
tag_colour | string^(#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}))?$ Background colour for this tag's badge, as a hex colour (#rgb or #rrggbb), e.g. #4f8ef7. Only hex colours are accepted - the value is rendered into a CSS stylesheet. Leave empty to use the colour auto-generated from the tag name.

### Responses

Development server

http://localhost:5000/api/v1/tag

Production server

https://yourdomain.com/api/v1/tag

Custom server

{protocol}://{host}/api/v1/tag

### Request samples

- Payload
- curl
- Python

Content type
application/json
`
{

- "title": "Important Sites"

}`

### Response samples

- 201

Content type
application/json
`
{

- "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f"

}`

## Get single tag

Retrieve tag information, set notification_muted status, recheck all web page change monitors (watches) in tag.

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Tag unique ID

##### query Parameters

muted | string Enum: "muted" "unmuted" Set mute state
recheck | string Value: "true" Queue all web page change monitors (watches) with this tag for recheck

### Responses

Development server

http://localhost:5000/api/v1/tag/{uuid}

Production server

https://yourdomain.com/api/v1/tag/{uuid}

Custom server

{protocol}://{host}/api/v1/tag/{uuid}

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/tag/550e8400-e29b-41d4-a716-446655440000" \
      -H "x-api-key: YOUR_API_KEY"

### Response samples

- 200

Content type
application/json
`
{

- "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
- "date_created": 0,
- "url": "http://example.com",
- "title": "string",
- "tag": "string",
- "tags":
  [
  - "string"
  ],
- "paused": true,
- "notification_muted": true,
- "method": "GET",
- "fetch_backend": "system",
- "headers":
  {
  - "property1": "string",
  - "property2": "string"
  },
- "body": "string",
- "proxy": "string",
- "ignore_status_codes": true,
- "webdriver_delay": 0,
- "webdriver_js_execute_code": "string",
- "time_between_check":
  {
  - "weeks": 52000,
  - "days": 365000,
  - "hours": 8760000,
  - "minutes": 525600000,
  - "seconds": 31536000000
  },
- "time_between_check_use_default": true,
- "notification_urls":
  [
  - "string"
  ],
- "notification_title": "string",
- "notification_body": "string",
- "notification_format": "text",
- "track_ldjson_price_data": true,
- "browser_steps":
  [
  - {
    - "operation": "string",
    - "selector": "string",
    - "optional_value": "string"
    }
  ],
- "processor": "restock_diff",
- "include_filters":
  [
  - "string"
  ],
- "subtractive_selectors":
  [
  - "string"
  ],
- "ignore_text":
  [
  - "string"
  ],
- "trigger_text":
  [
  - "string"
  ],
- "text_should_not_be_present":
  [
  - "string"
  ],
- "extract_lines_containing":
  [
  - "string"
  ],
- "extract_text":
  [
  - "string"
  ],
- "trim_text_whitespace": false,
- "sort_text_alphabetically": false,
- "remove_duplicate_lines": false,
- "check_unique_lines": false,
- "strip_ignored_lines": true,
- "filter_text_added": true,
- "filter_text_removed": true,
- "filter_text_replaced": true,
- "in_stock_only": true,
- "follow_price_changes": true,
- "price_change_threshold_percent": 0,
- "has_ldjson_price_data": true,
- "notification_screenshot": false,
- "filter_failure_notification_send": true,
- "use_page_title_in_list": true,
- "history_snapshot_max_length": 1,
- "time_schedule_limit":
  {
  - "enabled": false,
  - "monday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "tuesday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "wednesday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "thursday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "friday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "saturday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "sunday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    }
  },
- "conditions":
  [
  - {
    - "field": "string",
    - "operator": "string",
    - "value": "string"
    }
  ],
- "conditions_match_logic": "ALL",
- "llm_intent": "",
- "llm_change_summary": "",
- "llm_change_summary_mode": "replace",
- "llm_prefilter": "string",
- "llm_evaluation_cache": { },
- "llm_last_tokens_used": 0,
- "llm_tokens_used_cumulative": 0,
- "llm_tokens_this_period": 0,
- "llm_tokens_period_key": "string",
- "overrides_watch": true,
- "url_match_pattern": "string",
- "tag_colour": "string"

}`

## Update tag

Update an existing tag using JSON

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Tag unique ID

##### Request Body schema: application/json
required

url | string <uri> <= 5000 characters URL to monitor for changes
title | string or null <= 5000 characters Custom title for the web page change monitor (watch), not to be confused with page_title
tag | string <= 5000 characters Tag UUID to associate with this web page change monitor (watch)
tags | Array of strings Array of tag UUIDs
paused | boolean Whether the web page change monitor (watch) is paused
notification_muted | boolean Whether notifications are muted
method | string Enum: "GET" "POST" "DELETE" "PUT" HTTP method to use

fetch_backend

string^(system|html_requests|html_webdriver|extra_b...
Default: "system"

Backend to use for fetching content. Common values:

- `system` (default) - Use the system-wide default fetcher
- `html_requests` - Fast requests-based fetcher
- `html_webdriver` - Browser-based fetcher (Playwright/Puppeteer)
- `extra_browser_*` - Custom browser configurations (if configured)
- Plugin-provided fetchers (if installed)

| object HTTP headers to include in requests
body | string or null <= 5000 characters HTTP request body
proxy | string or null <= 5000 characters Proxy configuration
ignore_status_codes | boolean or null Ignore HTTP status code errors (boolean or null)
webdriver_delay | integer or null Delay in seconds for webdriver
webdriver_js_execute_code | string or null <= 5000 characters JavaScript code to execute
| object Time intervals between checks. All fields must be non-negative. At least one non-zero value required when not using default settings.
time_between_check_use_default | boolean Default: true Whether to use global settings for time between checks - defaults to true if not set
notification_urls | Array of strings <= 100 items [ items <= 1000 characters ] Notification URLs for this web page change monitor (watch). Maximum 100 URLs.
notification_title | string or null <= 5000 characters Custom notification title
notification_body | string or null <= 5000 characters Custom notification body
notification_format | string Enum: "text" "html" "htmlcolor" "markdown" "System default" Format for notifications
track_ldjson_price_data | boolean or null Whether to track JSON-LD price data
| Array of objects <= 100 items Browser automation steps. Maximum 100 steps allowed.
processor | string Default: "text_json_diff" Enum: "restock_diff" "text_json_diff" Optional processor mode to use for change detection. Defaults to `text_json_diff` if not specified.
include_filters | Array of strings <= 100 items [ items <= 5000 characters ] CSS/XPath selectors to extract specific content from the page
subtractive_selectors | Array of strings <= 100 items [ items <= 5000 characters ] CSS/XPath selectors to remove content from the page
ignore_text | Array of strings <= 100 items [ items <= 5000 characters ] Text patterns to ignore in change detection
trigger_text | Array of strings <= 100 items [ items <= 5000 characters ] Text/regex patterns that must be present to trigger a change
text_should_not_be_present | Array of strings <= 100 items [ items <= 5000 characters ] Text that should NOT be present (triggers alert if found)
extract_lines_containing | Array of strings <= 100 items [ items <= 5000 characters ] Keep only lines containing these substrings (plain text, case-insensitive) — simpler alternative to regex
extract_text | Array of strings <= 100 items [ items <= 5000 characters ] Regex patterns to extract specific text after filtering
trim_text_whitespace | boolean Default: false Strip leading/trailing whitespace from text
sort_text_alphabetically | boolean Default: false Sort lines alphabetically before comparison
remove_duplicate_lines | boolean Default: false Remove duplicate lines from content
check_unique_lines | boolean Default: false Compare against all history for unique lines
strip_ignored_lines | boolean or null Remove lines matching ignore patterns
filter_text_added | boolean Default: true Include added text in change detection
filter_text_removed | boolean Default: true Include removed text in change detection
filter_text_replaced | boolean Default: true Include replaced text in change detection
in_stock_only | boolean Default: true Only trigger on in-stock transitions (restock_diff processor)
follow_price_changes | boolean Default: true Monitor and track price changes (restock_diff processor)
price_change_threshold_percent | number or null Minimum price change percentage to trigger notification
notification_screenshot | boolean Default: false Include screenshot in notifications (if supported by notification URL)
filter_failure_notification_send | boolean Default: true Send notification when filters fail to match content
use_page_title_in_list | boolean or null Display page title in watch list (null = use system default)
history_snapshot_max_length | integer or null [ 1 .. 1000 ] Maximum number of history snapshots to keep (null = use system default)
| object Weekly schedule limiting when checks can run
| Array of objects <= 100 items Array of condition rules for change detection logic (empty array when not set)
conditions_match_logic | string Default: "ALL" Enum: "ALL" "ANY" Logic operator - ALL (match all conditions) or ANY (match any condition)
llm_intent | string <= 2000 characters Default: "" Plain-English intent for AI-based change filtering. The AI evaluates every detected change against this and only notifies when it matches.
llm_change_summary | string <= 2000 characters Default: "" Instructions for the AI to summarise changes in notifications. When set, replaces {{diff}} with a human-readable description.
llm_change_summary_mode | string Default: "replace" Enum: "replace" "append" Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.

overrides_watch

boolean or null

Whether this tag's settings override watch settings for all watches in this tag/group.

- true: Tag settings override watch settings
- false: Tag settings do not override (watches use their own settings)
- null: Not decided yet / inherit default behavior

url_match_pattern | string Automatically apply this tag to any watch whose URL matches this pattern. Supports fnmatch wildcards (* and ?): e.g. ://example.com/ or github.com/myorg. Plain strings are matched as case-insensitive substrings. Leave empty to disable auto-matching.
tag_colour | string^(#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}))?$ Background colour for this tag's badge, as a hex colour (#rgb or #rrggbb), e.g. #4f8ef7. Only hex colours are accepted - the value is rendered into a CSS stylesheet. Leave empty to use the colour auto-generated from the tag name.

### Responses

Development server

http://localhost:5000/api/v1/tag/{uuid}

Production server

https://yourdomain.com/api/v1/tag/{uuid}

Custom server

{protocol}://{host}/api/v1/tag/{uuid}

### Request samples

- Payload
- curl
- Python

Content type
application/json
`
{

- "url": "http://example.com",
- "title": "string",
- "tag": "string",
- "tags":
  [
  - "string"
  ],
- "paused": true,
- "notification_muted": true,
- "method": "GET",
- "fetch_backend": "system",
- "headers":
  {
  - "property1": "string",
  - "property2": "string"
  },
- "body": "string",
- "proxy": "string",
- "ignore_status_codes": true,
- "webdriver_delay": 0,
- "webdriver_js_execute_code": "string",
- "time_between_check":
  {
  - "weeks": 52000,
  - "days": 365000,
  - "hours": 8760000,
  - "minutes": 525600000,
  - "seconds": 31536000000
  },
- "time_between_check_use_default": true,
- "notification_urls":
  [
  - "string"
  ],
- "notification_title": "string",
- "notification_body": "string",
- "notification_format": "text",
- "track_ldjson_price_data": true,
- "browser_steps":
  [
  - {
    - "operation": "string",
    - "selector": "string",
    - "optional_value": "string"
    }
  ],
- "processor": "restock_diff",
- "include_filters":
  [
  - "string"
  ],
- "subtractive_selectors":
  [
  - "string"
  ],
- "ignore_text":
  [
  - "string"
  ],
- "trigger_text":
  [
  - "string"
  ],
- "text_should_not_be_present":
  [
  - "string"
  ],
- "extract_lines_containing":
  [
  - "string"
  ],
- "extract_text":
  [
  - "string"
  ],
- "trim_text_whitespace": false,
- "sort_text_alphabetically": false,
- "remove_duplicate_lines": false,
- "check_unique_lines": false,
- "strip_ignored_lines": true,
- "filter_text_added": true,
- "filter_text_removed": true,
- "filter_text_replaced": true,
- "in_stock_only": true,
- "follow_price_changes": true,
- "price_change_threshold_percent": 0,
- "notification_screenshot": false,
- "filter_failure_notification_send": true,
- "use_page_title_in_list": true,
- "history_snapshot_max_length": 1,
- "time_schedule_limit":
  {
  - "enabled": false,
  - "monday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "tuesday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "wednesday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "thursday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "friday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "saturday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    },
  - "sunday":
    {
    - "enabled": true,
    - "start_time": "00:00",
    - "duration":
      {
      - "hours": "24",
      - "minutes": "00"
      }
    }
  },
- "conditions":
  [
  - {
    - "field": "string",
    - "operator": "string",
    - "value": "string"
    }
  ],
- "conditions_match_logic": "ALL",
- "llm_intent": "",
- "llm_change_summary": "",
- "llm_change_summary_mode": "replace",
- "overrides_watch": true,
- "url_match_pattern": "string",
- "tag_colour": "string"

}`

## Delete tag

Delete a tag/group and remove it from all web page change monitors (watches)

##### Authorizations:

ApiKeyAuth

##### path Parameters

uuid required | string <uuid> Tag unique ID

### Responses

Development server

http://localhost:5000/api/v1/tag/{uuid}

Production server

https://yourdomain.com/api/v1/tag/{uuid}

Custom server

{protocol}://{host}/api/v1/tag/{uuid}

### Request samples

- curl
- Python

    curl -X DELETE "http://localhost:5000/api/v1/tag/550e8400-e29b-41d4-a716-446655440000" \
      -H "x-api-key: YOUR_API_KEY"

## Notifications

Configure global notification endpoints that can be used across all your watches. Supports various notification services including email, Discord, Slack, webhooks, and many other popular platforms. These settings serve as defaults that can be overridden at the individual watch or tag level.

The notification syntax uses https://github.com/caronc/apprise.

## Get notification URLs

Return the notification URL list from the configuration

##### Authorizations:

ApiKeyAuth

### Responses

Development server

http://localhost:5000/api/v1/notifications

Production server

https://yourdomain.com/api/v1/notifications

Custom server

{protocol}://{host}/api/v1/notifications

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/notifications" \
      -H "x-api-key: YOUR_API_KEY"

### Response samples

- 200

Content type
application/json
`
{

- "notification_urls":
  [
  - "http://example.com"
  ]

}`

## Add notification URLs

Add one or more notification URLs to the configuration

##### Authorizations:

ApiKeyAuth

##### Request Body schema: application/json
required

notification_urls required | Array of strings <uri> [ items <uri > ] List of notification URLs

### Responses

Development server

http://localhost:5000/api/v1/notifications

Production server

https://yourdomain.com/api/v1/notifications

Custom server

{protocol}://{host}/api/v1/notifications

### Request samples

- Payload
- curl
- Python

Content type
application/json
`
{

- "notification_urls":
  [
  - "mailto:admin@example.com",
  - "discord://webhook_id/webhook_token"
  ]

}`

### Response samples

- 201

Content type
application/json
`
{

- "notification_urls":
  [
  - "http://example.com"
  ]

}`

## Replace notification URLs

Replace all notification URLs with the provided list (can be empty)

##### Authorizations:

ApiKeyAuth

##### Request Body schema: application/json
required

notification_urls required | Array of strings <uri> [ items <uri > ] List of notification URLs

### Responses

Development server

http://localhost:5000/api/v1/notifications

Production server

https://yourdomain.com/api/v1/notifications

Custom server

{protocol}://{host}/api/v1/notifications

### Request samples

- Payload
- curl
- Python

Content type
application/json
`
{

- "notification_urls":
  [
  - "http://example.com"
  ]

}`

### Response samples

- 200

Content type
application/json
`
{

- "notification_urls":
  [
  - "http://example.com"
  ]

}`

## Delete notification URLs

Delete one or more notification URLs from the configuration

##### Authorizations:

ApiKeyAuth

##### Request Body schema: application/json
required

notification_urls required | Array of strings <uri> [ items <uri > ] List of notification URLs

### Responses

Development server

http://localhost:5000/api/v1/notifications

Production server

https://yourdomain.com/api/v1/notifications

Custom server

{protocol}://{host}/api/v1/notifications

### Request samples

- Payload
- curl
- Python

Content type
application/json
`
{

- "notification_urls":
  [
  - "http://example.com"
  ]

}`

## Search

Search and filter your watches by URL patterns, titles, or tags. Useful for quickly finding specific monitors in large collections or identifying watches that match certain criteria.

## Search watches

Search web page change monitors (watches) by URL or title text

##### Authorizations:

ApiKeyAuth

##### query Parameters

q required | string Search query to match against watch URLs and titles
tag | string Tag name to limit results (name not UUID)
partial | string Allow partial matching of URL query

### Responses

Development server

http://localhost:5000/api/v1/search

Production server

https://yourdomain.com/api/v1/search

Custom server

{protocol}://{host}/api/v1/search

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/search?q=example.com" \
      -H "x-api-key: YOUR_API_KEY"

### Response samples

- 200

Content type
application/json
`
{

- "watches":
  {
  - "095be615-a8ad-4c33-8e9c-c7612fbf6c9f":
    {
    - "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f",
    - "url": "http://example.com",
    - "title": "Example Website Monitor",
    - "tags":
      [
      - "550e8400-e29b-41d4-a716-446655440000"
      ],
    - "paused": false,
    - "notification_muted": false
    }
  }

}`

## Import

Bulk import multiple URLs for monitoring. Accepts plain text lists of URLs and can automatically apply tags, proxy settings, and other configurations to all imported watches simultaneously.

## Import watch URLs with configuration

Import a list of URLs to monitor with optional watch configuration. Accepts line-separated URLs in request body.

Configuration via Query Parameters:

You can pass ANY watch configuration field as query parameters to apply settings to all imported watches. All parameters from the Watch schema are supported (processor, fetch_backend, notification_urls, etc.).

Special Parameters:

- `tag` / `tag_uuids` - Assign tags to imported watches
- `proxy` - Use specific proxy for imported watches
- `dedupe` - Skip duplicate URLs (default: true)

Type Conversion:

- Booleans: `true`, `false`, `1`, `0`, `yes`, `no`
- Arrays: Comma-separated or JSON format (`[item1,item2]`)
- Objects: JSON format (`{"key":"value"}`)
- Numbers: Parsed as int or float

##### Authorizations:

ApiKeyAuth

##### query Parameters

tag_uuids | string Example: tag_uuids=550e8400-e29b-41d4-a716-446655440000 Tag UUID(s) to apply to imported watches (comma-separated for multiple)
tag | string Example: tag=production Tag name to apply to imported watches
proxy | string Example: proxy=proxy1 Proxy key to use for imported watches
dedupe | boolean Default: true Skip duplicate URLs (default true)

##### Request Body schema: text/plain
required

string

### Responses

Development server

http://localhost:5000/api/v1/import

Production server

https://yourdomain.com/api/v1/import

Custom server

{protocol}://{host}/api/v1/import

### Request samples

- Payload
- curl
- Python

Content type
text/plain

    https://example.com
    https://example.org
    https://example.net

### Response samples

- 200

Content type
application/json
`
[

- "497f6eca-6276-4993-bfeb-53cbbbba6f08"

]`

## System Information

Retrieve system status and statistics about your changedetection.io instance, including total watch counts, uptime information, and version details.

## Get system information

Return information about the current system state

##### Authorizations:

ApiKeyAuth

### Responses

Development server

http://localhost:5000/api/v1/systeminfo

Production server

https://yourdomain.com/api/v1/systeminfo

Custom server

{protocol}://{host}/api/v1/systeminfo

### Request samples

- curl
- Python

    curl -X GET "http://localhost:5000/api/v1/systeminfo" \
      -H "x-api-key: YOUR_API_KEY"

### Response samples

- 200

Content type
application/json
`
{

- "watch_count": 42,
- "tag_count": 5,
- "uptime": "2 days, 3:45:12",
- "version": "0.50.10"

}`

## Plugin API Extensions

## How Processor Plugins Extend the API

changedetection.io uses a processor plugin system to handle different types of change detection. Each processor lives in `changedetectionio/processors/<name>/` and may include an `api.yaml` file that extends the core Watch schema with processor-specific configuration fields.

### How it works

At startup, changedetection.io scans all installed processors for an `api.yaml` file. Any schemas and code samples defined there are deep-merged into the live API specification, making the processor's configuration fields valid on all watch create and update requests.

The live, fully-merged spec is always available at `/api/v1/full-spec` — use that URL with Swagger UI or Redoc to see the complete schema for your specific installation.

### Writing a processor `api.yaml`

Place an `api.yaml` in the processor plugin's own directory, alongside its `__init__.py` (e.g. `changedetectionio/processors/my_processor/api.yaml`). The schema name must follow the convention `processor_config_<processor_name>` (e.g. `processor_config_restock_diff`). That same key is used as the JSON field name when creating or updating a watch.

A minimal `api.yaml` for a hypothetical `my_processor`:

    components:
      schemas:
        processor_config_my_processor:
          type: object
          description: Configuration for my_processor
          properties:
            some_option:
              type: boolean
              default: true
              description: Enable some behaviour

    paths:
      /watch:
        post:
          x-code-samples:
            - lang: curl
              label: my_processor example
              source: |
                curl -X POST "http://localhost:5000/api/v1/watch" \
                  -H "x-api-key: YOUR_API_KEY" \
                  -H "Content-Type: application/json" \
                  -d '{
                    "url": "https://example.com",
                    "processor": "my_processor",
                    "processor_config_my_processor": { "some_option": true }
                  }'

The `paths` section in `api.yaml` is used only for injecting additional `x-code-samples` into existing endpoints — you cannot define new routes via plugin.

### Built-in plugin: `restock_diff`

The `restock_diff` processor is always shipped with changedetection.io. It monitors product availability and price changes using structured data (JSON-LD / schema.org microdata) and text heuristics. It is activated by setting `"processor": "restock_diff"` on a watch.

It adds the `processor_config_restock_diff` block to the Watch schema with these fields:

Field | Type | Default | Description
--- | --- | --- | ---
`in_stock_processing` | string | `in_stock_only` | `in_stock_only` — only alert Out-of-Stock→In-Stock · `all_changes` — alert any availability change · `off` — disable stock tracking
`follow_price_changes` | boolean | `true` | Monitor and alert on price changes
`price_change_min` | number|null | — | Alert when price drops below this value
`price_change_max` | number|null | — | Alert when price rises above this value
`price_change_threshold_percent` | number|null | — | Minimum % change since the original price to trigger an alert

#### CREATE — Add a restock/price monitor

    curl -X POST "http://localhost:5000/api/v1/watch" \
      -H "x-api-key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "url": "https://example.com/product/widget",
        "processor": "restock_diff",
        "processor_config_restock_diff": {
          "in_stock_processing": "in_stock_only",
          "follow_price_changes": true,
          "price_change_threshold_percent": 5
        }
      }'

#### READ — Retrieve the monitor

The response JSON includes `processor_config_restock_diff` alongside all standard watch fields:

    curl -X GET "http://localhost:5000/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091" \
      -H "x-api-key: YOUR_API_KEY"

    {
      "uuid": "cc0cfffa-f449-477b-83ea-0caafd1dc091",
      "url": "https://example.com/product/widget",
      "processor": "restock_diff",
      "processor_config_restock_diff": {
        "in_stock_processing": "in_stock_only",
        "follow_price_changes": true,
        "price_change_threshold_percent": 5,
        "price_change_min": null,
        "price_change_max": null
      }
    }

#### UPDATE — Change thresholds without recreating the monitor

Only fields included in the request body are updated; omitted fields are left unchanged.

    curl -X PUT "http://localhost:5000/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091" \
      -H "x-api-key: YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "processor_config_restock_diff": {
          "in_stock_processing": "all_changes",
          "follow_price_changes": true,
          "price_change_min": 10.00,
          "price_change_max": 500.00
        }
      }'

#### DELETE — Remove the monitor

    curl -X DELETE "http://localhost:5000/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091" \
      -H "x-api-key: YOUR_API_KEY"

For the complete schema-validated documentation including all processor fields, fetch the live spec and load it into Swagger UI or Redoc:

    GET /api/v1/full-spec

## Get full live API spec

Return the fully merged OpenAPI specification for this instance.

Unlike the static `api-spec.yaml` shipped with the application, this endpoint returns the spec dynamically merged with any `api.yaml` schemas provided by installed processor plugins.

Use this URL with Swagger UI or Redoc to get schema-accurate documentation for your specific install — it includes every `processor_config_<name>` schema block contributed by installed processors (e.g. `processor_config_restock_diff` from the built-in restock plugin).

This endpoint requires no authentication and returns YAML.

To load it directly in Swagger UI, paste the URL into the "Explore" box:

    http://localhost:5000/api/v1/full-spec

### Responses

Development server

http://localhost:5000/api/v1/full-spec

Production server

https://yourdomain.com/api/v1/full-spec

Custom server

{protocol}://{host}/api/v1/full-spec

### Request samples

- curl
- Python

    # Fetch the live merged spec (no API key needed)
    curl -X GET "http://localhost:5000/api/v1/full-spec"