# ProjectDiscovery Notify (`rl1987/pd-notify`) Actor

Stream text or dataset records to Slack, Discord, Telegram, Email and other platforms using the ProjectDiscovery notify CLI.

- **URL**: https://apify.com/rl1987/pd-notify.md
- **Developed by:** [R.L.](https://apify.com/rl1987) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.01 / notification sent

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## ProjectDiscovery Notify – Send Slack, Discord & Telegram Notifications from Apify

**Send instant notifications to Slack, Discord, Telegram, Email, Microsoft Teams, Google Chat, Pushover, Gotify, and custom webhooks — straight from your Apify runs.** ProjectDiscovery Notify turns any scraper, monitor, or data pipeline into a **real-time alerting system**, with no servers, cron jobs, or glue code to maintain.

It wraps the popular open-source [`notify`](https://github.com/projectdiscovery/notify) CLI from [ProjectDiscovery](https://projectdiscovery.io) and makes it a first-class, **chainable Apify Actor**: a scraping or monitoring Actor produces data, and this Actor **fans that data out as notifications** to all your team's channels at once.

> 💬 **One Actor, every channel.** Configure once, deliver everywhere. Perfect for price-drop alerts, new-listing monitors, security recon findings, uptime checks, lead notifications, and any "tell me the moment something changes" workflow.

### What does ProjectDiscovery Notify do?

ProjectDiscovery Notify takes input text — typed directly **or read automatically from another Actor's dataset** — and delivers it to one or more notification channels you configure. Each line can become its own message, or you can send everything as a single **bulk** message.

Because it runs on the Apify platform, you get **scheduling, a REST API, run history, secret-encrypted credentials, proxy support, and effortless chaining** with thousands of other Actors — without running any infrastructure yourself.

### Why use ProjectDiscovery Notify?

- 🔔 **Real-time alerting for any pipeline** — get pinged the moment a scraper finds new results, a price changes, a competitor updates, or a monitor trips.
- 📡 **Multi-channel from one config** — Slack, Discord, Telegram, Email (SMTP), Microsoft Teams, Google Chat, Pushover, Gotify, or any custom webhook.
- 🔗 **Built for chaining** — read straight from an upstream Actor's dataset, so you can wire `scraper → transform → notify` in minutes.
- 🛡️ **Security & recon ready** — the classic ProjectDiscovery use case: pipe subdomain, vulnerability, or asset-discovery findings to your channels.
- 🔒 **Secrets stay secret** — webhook URLs and bot tokens are stored as encrypted Apify secrets.
- ⚡ **Zero infrastructure** — schedule it, trigger it from other Actors, or call it from the API.

### How to use ProjectDiscovery Notify to send notifications

1. Open the Actor in the Apify Console and click **Try for free**.
2. **Choose where to send.** Fill in a **quick-setup** field (Slack / Discord / Telegram), and/or paste a full **Advanced provider config (YAML)**. Both are merged, so you can mix channels freely.
3. **Provide the content.** Type **Text to send**, or point the Actor at a **Source dataset ID** from a previous run.
4. **(Optional) tune delivery** — enable **bulk** mode, restrict to specific **providers**/**IDs**, add a **delay**, **rate limit**, or a custom **message format** like `🚨 Alert: {{data}}`.
5. Click **Start**. The Actor delivers your notifications and saves a run summary to the dataset.

#### How to send Slack / Discord / Telegram notifications (quick start)

- **Slack:** paste your [incoming webhook URL](https://api.slack.com/messaging/webhooks) into `slackWebhookUrl`.
- **Discord:** paste a [channel webhook URL](https://support.discord.com/hc/en-us/articles/228383668) into `discordWebhookUrl`.
- **Telegram:** create a bot with [@BotFather](https://core.telegram.org/bots#botfather), then set `telegramApiKey` (the bot token) and `telegramChatId`.

#### Build a notification pipeline (chaining Actors)

This is where ProjectDiscovery Notify shines. Set **Source dataset ID** to the default dataset ID of an upstream Actor run, and use **Dataset fields** to choose which fields of each item become the notification line — e.g. `["title", "price", "url"]` joined by the **Dataset field separator**. Leave **Dataset fields** empty to send each item as compact JSON.

Using Apify **integrations/webhooks**, you can fire this automatically: when your scraper finishes, it triggers Notify with `{{resource.defaultDatasetId}}`, turning any scrape into an alert — `scrape → format → notify`, fully hands-off.

### Input

You must configure **at least one provider** — via the quick-setup fields, the advanced YAML, or both.

| Field | Type | Description |
| --- | --- | --- |
| `slackWebhookUrl` | string (secret) | Quick setup: Slack incoming webhook URL. |
| `slackChannel` | string | Quick setup: optional Slack channel name. |
| `discordWebhookUrl` | string (secret) | Quick setup: Discord webhook URL. |
| `telegramApiKey` | string (secret) | Quick setup: Telegram bot token (needs chat ID). |
| `telegramChatId` | string | Quick setup: Telegram chat ID. |
| `providerConfigYaml` | string (secret) | Advanced: full notify `provider-config.yaml` (any provider, multiple entries). Merged with quick-setup fields. |
| `data` | string | Raw text; one notification per non-empty line. |
| `sourceDatasetId` | string | Apify dataset to read input items from (for pipeline chaining). |
| `datasetFields` | array | Fields to extract per dataset item (empty = whole item as JSON). |
| `datasetFieldSeparator` | string | Separator used to join multiple fields. Default `" \| "`. |
| `providers` | array | Restrict to provider types (`-provider`), e.g. `slack`, `discord`. |
| `ids` | array | Restrict to provider entry IDs (`-id`). |
| `bulk` | boolean | Send as one chunked message instead of per line (`-bulk`). |
| `charLimit` | integer | Max characters per message (`-char-limit`, default 4000). |
| `delay` | integer | Seconds between notifications (`-delay`). |
| `rateLimit` | integer | Max requests per second (`-rate-limit`). |
| `msgFormat` | string | Custom format template, e.g. `Alert: {{data}}` (`-msg-format`). |
| `proxy` | string | HTTP/SOCKSv5 proxy (`-proxy`). |
| `verbose` | boolean | Verbose notify logging (`-verbose`). |

#### Provider config example (advanced YAML)

```yaml
slack:
  - id: recon
    slack_channel: recon
    slack_username: notify
    slack_format: "{{data}}"
    slack_webhook_url: "https://hooks.slack.com/services/XXXX"

telegram:
  - id: tel
    telegram_api_key: "XXXX"
    telegram_chat_id: "XXXX"
    telegram_format: "{{data}}"
```

See the full provider reference: https://github.com/projectdiscovery/notify#provider-config

### Output

The Actor pushes a single summary record per run to the dataset:

```json
{
    "success": true,
    "skipped": false,
    "sendErrors": [],
    "exitCode": 0,
    "linesSent": 3,
    "bulk": true,
    "providers": ["telegram"],
    "ids": [],
    "startedAt": "2026-06-27T12:00:00+00:00",
    "finishedAt": "2026-06-27T12:00:02+00:00",
    "stdout": "...",
    "stderr": ""
}
```

You can download the dataset in various formats such as **JSON, HTML, CSV, or Excel**, or access it via the Apify API.

#### Data table

| Field | Description |
| --- | --- |
| `success` | Whether all notifications were delivered. |
| `skipped` | `true` when there was no input to send (a no-op run). |
| `sendErrors` | List of delivery errors reported by notify (empty on success). |
| `exitCode` | Process exit code. |
| `linesSent` | Number of input lines processed. |
| `bulk` | Whether bulk mode was used. |
| `providers` / `ids` | Filters applied to the send. |
| `startedAt` / `finishedAt` | Run timestamps (UTC, ISO 8601). |
| `stdout` / `stderr` | Captured notify output. |

### Pricing — how much does it cost to send notifications?

ProjectDiscovery Notify uses simple, predictable **pay-per-event** pricing:

| Event | Price |
| --- | --- |
| **Notification sent** (per run that successfully delivers ≥ 1 notification) | **$0.01** |

- ✅ **You only pay for delivered value.** Runs that have **nothing to send** (no new data) or that **fail to deliver** are **never charged**.
- 💸 **Bulk-friendly.** In bulk mode, an entire batch (e.g. all new matches in one cycle) is one message and one $0.01 charge — so a monitor that runs every 15 minutes but only alerts occasionally costs almost nothing.
- 🧾 Platform usage (compute/proxy) is billed at cost on top of the event price. This Actor is intentionally lightweight (256 MB, runs in seconds), so usage cost is minimal.

> **Example:** A scheduled monitor that checks every 15 minutes and sends an alert on ~10 cycles per day costs about **$0.10/day** in event charges.

New to Apify? The **free tier** includes monthly usage credits, so you can try ProjectDiscovery Notify at no cost.

### Tips & advanced options

- Use **bulk** mode for large outputs to avoid flooding a channel with one message per line (and to minimize cost).
- Set a **delay** or **rate limit** if a provider throttles you.
- Use **IDs** to route different pipelines to different channels from one shared config.
- Paste credentials carefully — leading/trailing whitespace is stripped automatically, but a wrong/revoked token will surface as a delivery error in `sendErrors`.

### FAQ, legality, and support

**Are my webhook URLs and tokens stored securely?** Yes. Credential fields are marked as Apify **secrets** (encrypted at rest) and are written to a temporary, restricted file inside the run, then deleted after notify finishes.

**Which providers are supported?** All providers supported by ProjectDiscovery `notify` (currently v1.0.7): **Slack, Discord, Telegram, Pushover, SMTP/Email, Google Chat, Microsoft Teams, Gotify, and custom webhooks.**

**Will I be charged if there's nothing to send?** No. Empty/no-op runs and failed deliveries are not billed for the notification event.

**A notification failed — what now?** Check the `sendErrors` field in the dataset and the run log. Most failures are bad/revoked webhook URLs or bot tokens, an incorrect chat ID, or provider rate limits. (Telegram `Unauthorized` means an invalid bot token; "chat not found" means a wrong chat ID.)

**Is this legal?** This Actor only delivers messages to channels **you** own and configure. You are responsible for the content you send and for complying with each provider's terms of service and anti-spam rules.

For issues or feature requests, use the Actor's **Issues** tab. This Actor is a wrapper around the open-source `notify` tool, which is maintained by ProjectDiscovery.

### Data pipeline toolkit

Part of the **Data pipeline toolkit** — small, chainable Actors for cleaning, transforming, and generating data inside a larger pipeline:

- [jq Helper – transform JSON with jq](https://apify.com/rl1987/jq-helper) — Run jq programs over inline JSON or a linked Apify dataset.
- [DuckDB Helper – SQL over CSV, JSON, Parquet, Excel, SQLite](https://apify.com/rl1987/duckdb-wrapper) — Run a DuckDB SQL query over remote/local files, push results to a dataset.
- [Regex Helper](https://apify.com/rl1987/regex-helper) — Apply named regular expressions to strings, extract structured matches.
- [URL Wrangler](https://apify.com/rl1987/url-wrangler) — Join, decompose, and rewrite URLs and query params in batch.
- [ZIP Code Helper](https://apify.com/rl1987/zip-code-helper) — Resolves US ZIP codes into city, state, county, and more.
- [Postal Address Normaliser](https://apify.com/rl1987/postal-address-normaliser) — Parses and normalises postal addresses using libpostal.
- [Phone Number Wrangler](https://apify.com/rl1987/phone-number-wrangler) — Validate, format, and parse phone numbers using libphonenumber.
- [UUID Generator](https://apify.com/rl1987/uuid-generator) — Generate bulk UUIDs (v1, v3, v4, v5, v7) on demand.
- [Secure Password & Passphrase Generator](https://apify.com/rl1987/password-generator) — Generate secure passwords and diceware passphrases per NIST guidance.
- [Thumbnail Maker](https://apify.com/rl1987/thumbnail-maker) — Generates thumbnails from image URLs using ImageMagick.
- [Katana Web Crawler (ProjectDiscovery)](https://apify.com/rl1987/pd-katana) — Crawl websites with Katana, stream results as JSONL.

### Did you find this useful?

⭐ Rate this actor on Apify! Your feedback helps other users find it and helps us keep improving it.

# Actor input Schema

## `data` (type: `string`):

Raw text to send as a notification. Each line becomes a separate notification unless bulk mode is enabled. Leave empty if you read input from a source dataset instead.

## `sourceDatasetId` (type: `string`):

ID of an Apify dataset to read input from (e.g. the output of a previous Actor in your pipeline). Each item is turned into one line of notification text. Combined with the `Text to send` field if both are provided.

## `datasetFields` (type: `array`):

Which fields to extract from each source dataset item. When empty, the whole item is serialized to compact JSON. Multiple fields are joined with the field separator.

## `datasetFieldSeparator` (type: `string`):

String used to join multiple dataset fields into a single line.

## `slackWebhookUrl` (type: `string`):

Incoming webhook URL for a Slack channel. When set, a Slack provider (id `slack`) is added automatically.

## `slackChannel` (type: `string`):

Optional channel name to post to (e.g. recon). Only used when a Slack webhook URL is set.

## `discordWebhookUrl` (type: `string`):

Webhook URL for a Discord channel. When set, a Discord provider (id `discord`) is added automatically.

## `telegramApiKey` (type: `string`):

Telegram bot token. When set together with a chat ID, a Telegram provider (id `telegram`) is added automatically.

## `telegramChatId` (type: `string`):

Telegram chat ID to send messages to. Required when a Telegram bot API key is set.

## `providerConfigYaml` (type: `string`):

Contents of the notify provider-config.yaml, defining any provider(s), webhooks and credentials. Merged with the quick-setup fields above. See https://github.com/projectdiscovery/notify#provider-config for the format. Treated as a secret.

## `providers` (type: `array`):

Restrict sending to these provider types only (e.g. slack, discord, telegram). Maps to the notify `-provider` flag. Empty = all providers in the config.

## `ids` (type: `array`):

Restrict sending to provider entries with these `id` values (e.g. recon, vulns). Maps to the notify `-id` flag. Empty = all IDs.

## `bulk` (type: `boolean`):

Send the whole input as one (chunked) message instead of one notification per line. Maps to the notify `-bulk` flag.

## `charLimit` (type: `integer`):

Maximum number of characters per message. Maps to the notify `-char-limit` flag.

## `delay` (type: `integer`):

Delay in seconds between each notification. Maps to the notify `-delay` flag.

## `rateLimit` (type: `integer`):

Maximum number of HTTP requests to send per second. Maps to the notify `-rate-limit` flag. 0 = use notify default.

## `msgFormat` (type: `string`):

Custom message formatting template. Use {{data}} as the placeholder for the line content, e.g. `Alert: {{data}}`. Maps to the notify `-msg-format` flag.

## `proxy` (type: `string`):

HTTP/SOCKSv5 proxy to route notifications through, e.g. http://127.0.0.1:8080. Maps to the notify `-proxy` flag.

## `verbose` (type: `boolean`):

Enable verbose logging from notify. Maps to the notify `-verbose` flag.

## Actor input object example

```json
{
  "datasetFields": [],
  "datasetFieldSeparator": " | ",
  "providers": [],
  "ids": [],
  "bulk": false,
  "charLimit": 4000,
  "delay": 0,
  "rateLimit": 0,
  "verbose": false
}
```

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("rl1987/pd-notify").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("rl1987/pd-notify").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{}' |
apify call rl1987/pd-notify --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,rl1987/pd-notify"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/84eSEjockSgQFMs2c/builds/SvSZeEHY35xBUFhCg/openapi.json
