# Cross-platform OSINT Seed-list Monitor (`automation-lab/cross-platform-osint-seed-list-monitor`) Actor

Monitor public Telegram, RSS, and web seed lists. Export normalized OSINT evidence records with source URLs, content hashes, and deltas.

- **URL**: https://apify.com/automation-lab/cross-platform-osint-seed-list-monitor.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Cross-platform OSINT Seed-list Monitor

Turn a seed list of public accounts, URLs, and feeds into a normalized OSINT evidence dataset.

This actor is built for repeatable public-source monitoring inspired by election-disinformation workflows: analysts start with known entities, refresh public records, preserve source URLs, and compare what is new between runs.

### What does Cross-platform OSINT Seed-list Monitor do?

Cross-platform OSINT Seed-list Monitor collects public records from conservative no-login sources and outputs one consistent evidence schema.

It currently supports:

- 🛰️ Telegram public channel preview pages
- 📰 RSS and Atom feeds
- 🌐 Public web pages and articles
- 🔁 Run-to-run content hash deltas
- 🔎 Keyword annotations for analyst triage

### Who is it for?

This actor is useful for teams that need repeatable public evidence collection, not a one-off scrape.

- 🗳️ Election integrity and civil-society monitoring teams
- 🧑‍💻 OSINT researchers and investigative journalists
- 🛡️ Risk intelligence and trust-and-safety analysts
- 🎓 Academic researchers studying narratives over time
- 📊 Agencies building briefing datasets from public sources

### Why use this monitor?

Single-platform scrapers are useful when you already know the exact source. Influence and disinformation investigations usually start with a mixed watchlist: Telegram channels, source domains, campaign pages, RSS feeds, and keywords.

This actor keeps that workflow in one place:

- one input seed list
- one dataset schema
- one content hash per evidence record
- one `runDelta` field for scheduled monitoring
- one export that downstream tools can join, filter, and audit

### What sources are supported in v1?

V1 is intentionally conservative.

It focuses on public, no-login HTTP sources that are reliable enough for scheduled actor runs:

- `telegram` — public `t.me/s/<channel>` previews
- `rss` — RSS and Atom feed items
- `web` — page-level public web/article extraction

### What is not included yet?

The actor does not log in to X, Facebook, TikTok, Instagram, VK, or private Telegram groups.

Those platforms can be added later through delegated Apify actors when a buyer wants that exact workflow. This keeps v1 reliable and avoids brittle login or CAPTCHA-heavy paths.

### Data you can extract

| Field | Description |
| --- | --- |
| `source` | `telegram`, `rss`, or `web` |
| `sourceUrl` | Direct URL for the public evidence record |
| `seed` | Original seed value from your watchlist |
| `seedLabel` | Optional human label for the seed |
| `matchedEntity` | Telegram channel or domain |
| `recordType` | Telegram message, RSS item, or web page |
| `publishedAt` | Source timestamp when available |
| `scrapedAt` | Collection timestamp |
| `title` | Page or feed title when available |
| `text` | Extracted evidence text |
| `authorName` | Source author/channel when available |
| `mediaUrls` | Public media URLs found on the record |
| `outlinks` | Links found in the evidence |
| `engagement` | Views or similar public metrics when exposed |
| `contentHash` | SHA-256 hash for dedupe and deltas |
| `runDelta` | `new` or `seen` across scheduled runs |
| `matchedKeywords` | Keywords found in the record text |

### How much does it cost to monitor OSINT seed lists?

The actor uses pay-per-event pricing.

You pay a small start fee for each run and a per-record fee for each normalized evidence record saved to the dataset. Current configured prices are:

| Event | Free plan tier | Bronze tier | Notes |
| --- | ---: | ---: | --- |
| Run started | $0.005000 | $0.005000 | Charged once per run |
| Evidence record | $0.000035858 | $0.000031181 | Charged for each normalized dataset item |

Approximate run-cost examples before Apify platform credits or subscriptions:

| Example run | Items saved | Free plan tier estimate | Bronze tier estimate |
| --- | ---: | ---: | ---: |
| Smoke test | 20 | ~$0.00572 | ~$0.00562 |
| Small watchlist | 50 | ~$0.00679 | ~$0.00656 |
| Realistic v1 validation | 120 | ~$0.00930 | ~$0.00874 |
| Larger scheduled refresh | 1,000 | ~$0.04086 | ~$0.03618 |

Free-plan users still see the `FREE` tier event price above; Apify may apply any platform credits or free usage allowance in your account separately. Start with low limits so you can estimate the number of records your sources produce:

- 1-3 seeds
- 20-50 records per seed
- 1-3 Telegram pages per seed

Then increase limits for scheduled monitoring once you know the sources are relevant.

### Quick start

1. Open the actor on Apify.
2. Add Telegram channels, RSS feeds, or public URLs to `seeds`.
3. Choose source types: `telegram`, `rss`, and/or `web`.
4. Set `maxRecordsPerSeed`.
5. Optionally add `matchKeywords`.
6. Run the actor.
7. Export the dataset as JSON, CSV, Excel, or via API.

### Example input

```json
{
  "seeds": [
    { "value": "telegram", "label": "Telegram News", "type": "telegramChannel" },
    { "value": "https://blog.apify.com/rss/", "label": "Apify Blog RSS", "type": "url" },
    { "value": "https://blog.apify.com/qriton-election-disinformation-analysis/", "label": "Qriton case study", "type": "url" }
  ],
  "sourceTypes": ["telegram", "rss", "web"],
  "maxRecordsPerSeed": 50,
  "maxPagesPerSeed": 3,
  "matchKeywords": ["election", "disinformation", "OSINT"],
  "includeRunDeltas": true
}
````

### Example output

```json
{
  "source": "telegram",
  "sourceUrl": "https://t.me/telegram/450",
  "seed": "telegram",
  "seedLabel": "Telegram News",
  "matchedEntity": "telegram",
  "recordType": "telegram_message",
  "publishedAt": "2024-01-01T12:00:00+00:00",
  "scrapedAt": "2026-07-08T15:00:00.000Z",
  "text": "Public message text...",
  "authorName": "telegram",
  "outlinks": ["https://example.com"],
  "engagement": { "views": 12345 },
  "contentHash": "...",
  "runDelta": "new",
  "matchedKeywords": ["election"]
}
```

### Telegram monitoring tips

Use public channel handles such as `telegram` or `durov`, or full URLs like `https://t.me/s/telegram`.

Private channels, groups, and login-only content are not supported.

Increase `maxPagesPerSeed` to collect more history. Each public Telegram preview page usually contains up to 20 messages.

### RSS monitoring tips

RSS and Atom feeds work well for newsrooms, blogs, agency updates, and public advisories.

If a URL is not a feed, the actor will skip RSS parsing and can still process the same URL through the `web` source type.

### Web page monitoring tips

The web collector saves one page-level evidence record per URL.

It is best for canonical pages, articles, reports, and landing pages. It is not a deep crawler. Add RSS feeds when you need many items from one publication.

### Run-to-run deltas

When `includeRunDeltas` is enabled, the actor stores content hashes in the run key-value store.

Records are marked:

- `new` — hash was not seen in previous runs using the same default key-value store
- `seen` — hash already existed from an earlier run

This is useful for scheduled watchlists.

### Keyword matching

`matchKeywords` annotates records but does not filter them out.

That design preserves the full evidence trail while still making analyst triage easier.

For strict filtering, filter the dataset after export or in your downstream workflow.

### Integrations

You can connect the dataset to:

- Google Sheets for analyst review
- Slack or email alerts for `runDelta = new`
- vector databases for narrative clustering
- BI dashboards for source counts over time
- case management tools for evidence preservation

### API usage with Node.js

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/cross-platform-osint-seed-list-monitor').call({
  seeds: [{ value: 'telegram', type: 'telegramChannel' }],
  sourceTypes: ['telegram'],
  maxRecordsPerSeed: 25,
});
console.log(run.defaultDatasetId);
```

### API usage with Python

```python
from apify_client import ApifyClient
import os

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/cross-platform-osint-seed-list-monitor').call(run_input={
    'seeds': [{'value': 'telegram', 'type': 'telegramChannel'}],
    'sourceTypes': ['telegram'],
    'maxRecordsPerSeed': 25,
})
print(run['defaultDatasetId'])
```

### API usage with cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/automation-lab~cross-platform-osint-seed-list-monitor/runs?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"seeds":[{"value":"telegram","type":"telegramChannel"}],"sourceTypes":["telegram"],"maxRecordsPerSeed":25}'
```

### MCP usage

Use Apify MCP with Claude Desktop or Claude Code:

```text
https://mcp.apify.com/?tools=automation-lab/cross-platform-osint-seed-list-monitor
```

Claude Code setup:

```bash
claude mcp add apify-osint-monitor https://mcp.apify.com/?tools=automation-lab/cross-platform-osint-seed-list-monitor
```

Claude Desktop JSON config example:

```json
{
  "mcpServers": {
    "apify-osint-monitor": {
      "url": "https://mcp.apify.com/?tools=automation-lab/cross-platform-osint-seed-list-monitor"
    }
  }
}
```

Example prompts:

- "Run the OSINT seed-list monitor for these Telegram channels and summarize new records."
- "Export all `runDelta = new` records from the latest dataset."
- "Compare keyword matches across RSS and Telegram records."

### Scheduling workflows

Schedule the actor hourly, daily, or weekly depending on source volatility.

For election or crisis monitoring, use smaller but more frequent runs. For background research, use daily or weekly runs with higher limits.

### Evidence quality notes

The actor records public source URLs and content hashes to support repeatable evidence handling.

It does not guarantee that a source page will remain online. Export datasets or store snapshots if long-term preservation is required.

### Legality

Only collect public data that you are allowed to process.

### Legal and ethical use

Only collect public data that you are allowed to process.

Respect platform terms, privacy rights, and local laws. Do not use this actor for doxxing, harassment, or unauthorized surveillance.

### Troubleshooting

If you get few Telegram records, confirm that the channel is public and available at `https://t.me/s/<channel>`.

If an RSS seed returns no items, check that the URL is a real RSS or Atom feed. Try enabling `web` for page-level extraction.

If all records are marked `seen`, clear the default key-value store or disable `includeRunDeltas` for a fresh baseline.

### FAQ

#### Can it monitor X, TikTok, Facebook, or VK?

Not directly in v1. Those platforms are better handled through dedicated Apify actors or future delegated-source integrations.

#### Does it require proxies?

No proxy is required for the current public no-login collectors.

#### Can I use keywords as seeds?

Keyword seeds are accepted for workflow compatibility, but v1 collectors focus on handles and URLs. Use `matchKeywords` to annotate collected records.

#### Does it remove duplicate records?

It deduplicates by content hash within a run and stores hashes for cross-run `new`/`seen` deltas.

### Related scrapers

Useful automation-lab actors for future delegated workflows:

- https://apify.com/automation-lab/telegram-scraper
- https://apify.com/automation-lab/twitter-x-scraper
- https://apify.com/automation-lab/tiktok-search-scraper
- https://apify.com/automation-lab/facebook-pages-scraper
- https://apify.com/automation-lab/youtube-scraper

### Changelog

#### 0.1

Initial version with Telegram public previews, RSS/Atom feeds, public web pages, normalized evidence records, content hashes, and run-to-run deltas.

# Actor input Schema

## `seeds` (type: `array`):

Seed entities to monitor. Use Telegram channel handles/URLs, RSS feed URLs, public web URLs, or keyword labels for future delegated workflows.

## `sourceTypes` (type: `array`):

Choose which public no-login collectors to run. Telegram uses t.me public previews; RSS and web use HTTP.

## `maxRecordsPerSeed` (type: `integer`):

Maximum normalized evidence records to save for each seed. Keep this low for first tests, then increase for scheduled monitoring.

## `maxPagesPerSeed` (type: `integer`):

How many public Telegram history pages to paginate per channel. Each page usually contains up to 20 messages.

## `sinceDate` (type: `string`):

Optional ISO date/time filter. Older records are skipped when the source exposes a timestamp.

## `matchKeywords` (type: `array`):

Optional words or phrases to mark in the matchedKeywords output field. This does not filter records; it annotates evidence.

## `includeRunDeltas` (type: `boolean`):

Store content hashes in the default key-value store and mark records as new or seen across scheduled runs.

## `requestTimeoutSecs` (type: `integer`):

Per-request timeout for public HTTP collectors.

## Actor input object example

```json
{
  "seeds": [
    {
      "value": "telegram",
      "label": "Telegram News",
      "type": "telegramChannel"
    },
    {
      "value": "https://blog.apify.com/rss/",
      "label": "Apify Blog RSS",
      "type": "url"
    },
    {
      "value": "https://blog.apify.com/qriton-election-disinformation-analysis/",
      "label": "Qriton case study",
      "type": "url"
    }
  ],
  "sourceTypes": [
    "telegram",
    "rss",
    "web"
  ],
  "maxRecordsPerSeed": 20,
  "maxPagesPerSeed": 3,
  "matchKeywords": [
    "election",
    "disinformation",
    "OSINT"
  ],
  "includeRunDeltas": true,
  "requestTimeoutSecs": 20
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "seeds": [
        {
            "value": "telegram",
            "label": "Telegram News",
            "type": "telegramChannel"
        },
        {
            "value": "https://blog.apify.com/rss/",
            "label": "Apify Blog RSS",
            "type": "url"
        },
        {
            "value": "https://blog.apify.com/qriton-election-disinformation-analysis/",
            "label": "Qriton case study",
            "type": "url"
        }
    ],
    "sourceTypes": [
        "telegram",
        "rss",
        "web"
    ],
    "maxRecordsPerSeed": 20,
    "maxPagesPerSeed": 3,
    "matchKeywords": [
        "election",
        "disinformation",
        "OSINT"
    ],
    "includeRunDeltas": true,
    "requestTimeoutSecs": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/cross-platform-osint-seed-list-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "seeds": [
        {
            "value": "telegram",
            "label": "Telegram News",
            "type": "telegramChannel",
        },
        {
            "value": "https://blog.apify.com/rss/",
            "label": "Apify Blog RSS",
            "type": "url",
        },
        {
            "value": "https://blog.apify.com/qriton-election-disinformation-analysis/",
            "label": "Qriton case study",
            "type": "url",
        },
    ],
    "sourceTypes": [
        "telegram",
        "rss",
        "web",
    ],
    "maxRecordsPerSeed": 20,
    "maxPagesPerSeed": 3,
    "matchKeywords": [
        "election",
        "disinformation",
        "OSINT",
    ],
    "includeRunDeltas": True,
    "requestTimeoutSecs": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/cross-platform-osint-seed-list-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "seeds": [
    {
      "value": "telegram",
      "label": "Telegram News",
      "type": "telegramChannel"
    },
    {
      "value": "https://blog.apify.com/rss/",
      "label": "Apify Blog RSS",
      "type": "url"
    },
    {
      "value": "https://blog.apify.com/qriton-election-disinformation-analysis/",
      "label": "Qriton case study",
      "type": "url"
    }
  ],
  "sourceTypes": [
    "telegram",
    "rss",
    "web"
  ],
  "maxRecordsPerSeed": 20,
  "maxPagesPerSeed": 3,
  "matchKeywords": [
    "election",
    "disinformation",
    "OSINT"
  ],
  "includeRunDeltas": true,
  "requestTimeoutSecs": 20
}' |
apify call automation-lab/cross-platform-osint-seed-list-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/cross-platform-osint-seed-list-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Cross-platform OSINT Seed-list Monitor",
        "description": "Monitor public Telegram, RSS, and web seed lists. Export normalized OSINT evidence records with source URLs, content hashes, and deltas.",
        "version": "0.1",
        "x-build-id": "7VAdhIglFXa9SdxoZ"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/automation-lab~cross-platform-osint-seed-list-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-automation-lab-cross-platform-osint-seed-list-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/automation-lab~cross-platform-osint-seed-list-monitor/runs": {
            "post": {
                "operationId": "runs-sync-automation-lab-cross-platform-osint-seed-list-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/automation-lab~cross-platform-osint-seed-list-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-automation-lab-cross-platform-osint-seed-list-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",
                "required": [
                    "seeds"
                ],
                "properties": {
                    "seeds": {
                        "title": "Public accounts, URLs, feeds, or keywords",
                        "type": "array",
                        "description": "Seed entities to monitor. Use Telegram channel handles/URLs, RSS feed URLs, public web URLs, or keyword labels for future delegated workflows."
                    },
                    "sourceTypes": {
                        "title": "Sources to collect",
                        "uniqueItems": true,
                        "type": "array",
                        "description": "Choose which public no-login collectors to run. Telegram uses t.me public previews; RSS and web use HTTP.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "telegram",
                                "rss",
                                "web"
                            ],
                            "enumTitles": [
                                "Telegram public channel previews",
                                "RSS/Atom feeds",
                                "Public web pages"
                            ]
                        },
                        "default": [
                            "telegram",
                            "rss",
                            "web"
                        ]
                    },
                    "maxRecordsPerSeed": {
                        "title": "Maximum records per seed",
                        "minimum": 1,
                        "maximum": 500,
                        "type": "integer",
                        "description": "Maximum normalized evidence records to save for each seed. Keep this low for first tests, then increase for scheduled monitoring.",
                        "default": 20
                    },
                    "maxPagesPerSeed": {
                        "title": "Maximum Telegram pages per seed",
                        "minimum": 1,
                        "maximum": 25,
                        "type": "integer",
                        "description": "How many public Telegram history pages to paginate per channel. Each page usually contains up to 20 messages.",
                        "default": 3
                    },
                    "sinceDate": {
                        "title": "Only records since date",
                        "type": "string",
                        "description": "Optional ISO date/time filter. Older records are skipped when the source exposes a timestamp."
                    },
                    "matchKeywords": {
                        "title": "Highlight keywords",
                        "type": "array",
                        "description": "Optional words or phrases to mark in the matchedKeywords output field. This does not filter records; it annotates evidence.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "includeRunDeltas": {
                        "title": "Track run-to-run deltas",
                        "type": "boolean",
                        "description": "Store content hashes in the default key-value store and mark records as new or seen across scheduled runs.",
                        "default": true
                    },
                    "requestTimeoutSecs": {
                        "title": "Request timeout in seconds",
                        "minimum": 5,
                        "maximum": 60,
                        "type": "integer",
                        "description": "Per-request timeout for public HTTP collectors.",
                        "default": 20
                    }
                }
            },
            "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
                                    }
                                }
                            },
                            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
