Send Email Report & Slack, Discord, Teams, Telegram Alerts
Pricing
from $0.90 / 1,000 notification sents
Send Email Report & Slack, Discord, Teams, Telegram Alerts
Send a dataset report when any scraper finishes: email (your own SMTP or Resend) with a preview table and CSV/JSON attachment, plus Slack, Discord, Microsoft Teams, Telegram or webhook alerts. Sends only when there are items, retries each channel on its own. $0.0009 per notification.
Pricing
from $0.90 / 1,000 notification sents
Rating
0.0
(0)
Developer
Charles Markette
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
Send Email Report & Slack, Discord, Teams, Telegram Alerts (Notify Step) is the last step after any scraper. When a run finishes, it sends a short report of the run's dataset (the item count, a preview table and links to the dataset and the run) as an email and as Slack, Discord, Microsoft Teams, Telegram or webhook notifications, all through your own accounts. It's for anyone who schedules scrapers or monitors on Apify and wants to be told when there's something new, without opening Apify Console or building a Zapier flow.
- Email through your own SMTP server (Gmail, Outlook, SendGrid, Amazon SES, Mailgun, your company server …) or a Resend API key, with an HTML table, a plain-text version, and an optional CSV or JSON attachment of the data.
- Slack, Discord and Microsoft Teams through their incoming webhooks (in Teams, the new Workflows webhooks).
- Telegram through your own bot.
- Any webhook (Zapier, Make, n8n, your own API): a JSON POST with the count, links and the first items.
Connect it once on your scraper's Integrations tab, and every run reports to you.
Why use this notification Actor?
- Reliable. Each channel is sent and retried on its own: rate limits (HTTP 429) and server errors (5xx) are retried with backoff, honouring the service's
Retry-After. One channel failing never stops the others, and the run fails only when every channel failed, so a broken webhook gets noticed without hiding the messages that did arrive. If the platform restarts a run, channels already recorded as sent are not sent again (see Limitations for the small gap). - Your own providers. Messages go out from your SMTP server, your Resend account, your Slack/Discord/Teams webhooks and your Telegram bot. Nothing is relayed through a third-party mail service, and you can use your own domain and sender name.
- Many channels in one step. Fill in any combination; each gets a message formatted for it (Slack blocks, Discord embeds, a Teams Adaptive Card, Telegram HTML, a real HTML table in email).
- Only when it matters. By default it sends nothing when the dataset is empty, or set a minimum number of items. Skipped runs send nothing and aren't charged for notifications.
- Safe with scraped data. Every value is escaped for its format (HTML in email, Telegram HTML, Slack's
&,<,>, Discord markdown), so scraped text can't break the message, inject links, or ping@everyone. Long values are shortened, and messages are kept within each service's size limits. - Your secrets stay secret. Passwords, API keys, bot tokens and webhook URLs (which are secrets too) are stored encrypted, and they're masked in every log line, error message and output.
Use cases
- New-item alerts: a Slack or Telegram message when a monitor finds new listings, jobs, leads or price drops.
- Daily email report: an HTML table of the day's results with the full dataset attached as CSV, sent to you or a client.
- Team channels: post results to a Microsoft Teams or Discord channel your team already watches.
- Hand off to automation: trigger Zapier, Make, n8n or your own API with the item count, links and first items.
- Run health: with When to send: Always, get a message after every run, including empty ones, so you notice when a scraper stops finding data.
How to use it
Setup (about 2 minutes per channel)
Fill in only the channels you want. To check your setup, run the Actor once without a dataset: it sends a real test message with 3 sample items to every configured channel (charged like any other notification). Or turn on Dry run (free) to see the rendered messages in the output without sending anything.
Slack
- Go to api.slack.com/apps, Create New App → From scratch, and pick your workspace.
- Open Incoming Webhooks, turn on Activate Incoming Webhooks, click Add New Webhook to Workspace, pick a channel and Allow.
- Copy the
https://hooks.slack.com/services/…URL into Slack incoming webhook URL. (Slack's guide)
Discord
- In your server, open Server Settings → Integrations and click Create Webhook.
- Pick the channel, then Copy Webhook URL into Discord webhook URL. (Discord's guide)
Microsoft Teams
- In Teams, open the channel's More options (…) → Workflows, and choose the template Send webhook alerts to a channel.
- Confirm the account, pick the team and channel, select Add workflow, and copy the URL it shows into Microsoft Teams webhook URL. (Microsoft's guide)
Old Office 365 connector webhooks also work while Microsoft still accepts them, but Microsoft is retiring them, so new setups should use Workflows.
Telegram
- In Telegram, message @BotFather, send
/newbotand follow the steps. Copy the token (123456789:AA…) into Telegram bot token. (Telegram's guide) - Send your bot any message (or add it to a group, or make it an admin of your channel). Then open
https://api.telegram.org/bot<your token>/getUpdatesin a browser and copy the"chat":{"id": …}number into Telegram chat ID. For a public channel you can use@channelnameinstead.
Email with Resend
- Sign up at resend.com, add and verify your sending domain (Resend: domains).
- Create an API key with sending access (Resend: API keys) and paste it into Resend API key.
- Set From (an address on your verified domain) and To.
Email with SMTP
- Fill in SMTP server, port and security from your provider: usually STARTTLS on port 587, or SSL on port 465.
- Fill in username and password. Gmail, Outlook and iCloud need an app password instead of your normal password (Gmail: Sign in with app passwords; it needs 2-Step Verification).
- Set From and To.
Any webhook: paste the URL, and optionally headers such as {"Authorization": "Bearer …"}.
Use it after a scraper (integration): a notification after every run
- Open your scraper's Actor or saved task, go to the Integrations tab and click Add integration.
- Search for this Actor, choose to start it when the run succeeded, and set the input. Apify fills in
{{resource.defaultDatasetId}}with that run's dataset:
{"datasetId": "{{resource.defaultDatasetId}}","actorName": "Amazon price tracker","condition": "onlyIfItems","subject": "{actorName}: {itemCount} new deals","messageTemplate": "{actorName} found {itemCount} items on {date}.","previewFields": ["title", "price", "url"],"previewRows": 10,"slackWebhookUrl": "https://hooks.slack.com/services/…","smtpHost": "smtp.gmail.com","smtpPort": 587,"smtpSecurity": "starttls","smtpUsername": "you@gmail.com","smtpPassword": "your app password","emailTo": ["you@example.com"],"attachment": "csv"}
- Save, and test the integration on a past run.
The message placeholders use single braces ({itemCount}), because Apify fills in every {{…}} in an integration's input itself and rejects variables it doesn't know. The older {{itemCount}} form still works in manual runs and saved tasks.
Only new items: put Merge & Deduplicate Datasets in "only new" mode between the scraper and this Actor (connect this Actor to the dedupe Actor's runs), and you're told only about items you haven't seen before.
Input example
A Telegram and Discord alert with a minimum of 5 items:
{"datasetId": "aBcDeFgHiJkLmNoPq","actorName": "Job board monitor","condition": "minItems","minItems": 5,"previewFields": ["title", "company", "url"],"telegramBotToken": "123456789:AA…","telegramChatId": "-1001234567890","discordWebhookUrl": "https://discord.com/api/webhooks/…"}
| Field | Notes |
|---|---|
| Dataset | The dataset to summarize. In integrations use {{resource.defaultDatasetId}}. Empty = a test message with 3 sample items (sent and charged like a normal notification). |
| Run URL / Name shown in messages | Optional, shown in messages. |
| When to send | onlyIfItems (default), always, or minItems with Minimum items. Runs that don't qualify send nothing. |
| Dry run | Renders every configured message into OUTPUT and the dataset without sending (free). With no channel configured, it previews all of them. |
| Subject / Message | Placeholders: {itemCount}, {datasetId}, {datasetUrl}, {runUrl}, {actorName}, {date} (UTC). The old {{itemCount}} form is still accepted, but don't use it in integrations. Links to the dataset and the run are added automatically. |
| Preview fields | Fields to show (dots for nested ones, e.g. seller.name). Empty = the first 8 fields. |
| Preview rows | Default 10, max 100. Chat apps may show fewer to stay within their limits (see below). |
| SMTP server, port, security, username, password | Your SMTP account. Security: starttls, ssl or none. With none, a username or password is refused (credentials are never sent unencrypted), so none only suits a trusted relay without login. |
| Resend API key | Instead of SMTP. Fill in one or the other, not both. |
| From, To, Cc, Bcc, Reply-To | Email addresses. Each entry may hold several addresses separated by , or ;. Bcc recipients are never shown in the email headers. |
| Attach the dataset | Email only: none, csv or json. |
| Slack / Discord / Teams webhook URL | One URL per channel. Discord can also post under a custom name; Discord doesn't allow names containing "discord" or "clyde", so such a name is ignored (with a warning) and the webhook's own name is used. |
| Telegram bot token + chat ID | Both are needed. |
| Webhook URL + headers | A JSON POST: itemCount, datasetId, datasetUrl, runUrl, actorName, date, subject, message, fields and items (the first Preview rows items, unchanged). |
All passwords, keys, tokens, webhook URLs and webhook headers are secret inputs, stored encrypted.
Output example
The run's dataset has one row per configured channel:
[{"channel": "email","status": "sent","error": null,"message": "accepted by smtp.gmail.com","target": "smtp.gmail.com:587 (1 recipient)","attempts": 1,"itemCount": 42,"datasetId": "aBcDeFgHiJkLmNoPq","sentAt": "2026-10-13T08:30:05+00:00"},{"channel": "slack","status": "sent","error": null,"message": "posted","target": "hooks.slack.com","attempts": 1,"itemCount": 42,"datasetId": "aBcDeFgHiJkLmNoPq","sentAt": "2026-10-13T08:30:04+00:00"}]
channelisemail,slack,discord,teams,telegramorwebhook;statusissent,failed,skippedordry run;errorsays why a channel failed (with secrets masked);targetshows just the host, chat ID or number of recipients.- The key-value store
OUTPUTholds the same per-channel results plus the item count, whether the condition was met, and the attachment note. In a dry run, each channel also holds the exact message that would be sent (preview). - Without any channel configured, the run returns a single row with setup instructions and sends nothing.
How much does it cost to send notifications?
This Actor uses pay-per-event pricing: $0.0009 per notification sent, plus Apify's $0.00005 run start fee. One notification is one channel message that the service accepted; an email to several recipients is one notification. Test messages (a run without a dataset) are real notifications and are charged. Skipped runs (empty dataset, or fewer than your minimum), dry runs, channels that failed, and the result rows in the dataset aren't charged as notifications; only the start fee applies.
Examples use the Free-plan rate. Where an example doesn't add it, each run also has its run-start charge, counted per GB of Actor memory (minimum one; one at the default memory); Apify Proxy (where used) is billed separately.
Worked example: a scraper that runs every day and reports to Slack and email sends 2 notifications per run: 2 × $0.0009 + $0.00005 = $0.00185 per run, about $0.06 per month.
If you set a maximum cost per run, the Actor sends only as many channels as that allows and marks the rest as skipped.
FAQ
Gmail or Outlook says the SMTP login was rejected.
Use an app password, not your normal password. Gmail needs 2-Step Verification turned on before you can create one.
Slack answers 404 or 410.
The webhook or its channel no longer exists, or the channel was archived. Create a new incoming webhook and paste its URL.
My Telegram bot doesn't post.
Send the bot a message first (or add it to the group, or make it an admin of the channel), then get the chat ID from getUpdates. Group IDs start with -.
The placeholders show up as text, or the integration refuses my input.
In integrations use single braces, like {itemCount}. Apify fills in double-brace {{…}} variables itself and rejects the ones it doesn't know.
"The dataset ID is still a template".
{{resource.defaultDatasetId}} is filled in only when the Actor runs from an integration. For a manual run, pick the dataset.
Nothing was sent, and the run succeeded.
The dataset was empty (or had fewer items than Minimum items). Choose When to send: Always if you want a message after every run.
Can I send to several Slack channels or email lists?
Email takes several To, Cc and Bcc addresses. For several Slack, Discord or Teams channels, connect one integration per channel.
Limitations
- Slack: 3,000 characters per text block and 50 blocks per message; the preview is kept to about 12,000 characters.
- Discord: message text up to 2,000 characters, up to 10 embeds and 6,000 characters across all embeds, so Discord shows up to 10 items.
- Telegram: 4,096 characters per message, so it shows as many items as fit. If Telegram ever rejects the formatting, the message is resent as plain text.
- Teams: 28 KB per message, so the card shows as many items as fit.
- Email: the table shows up to 100 items. Values are cut at 300 characters in email and 120 in chat apps.
- Attachment: about 10 MB. A bigger dataset attaches its first items, and the email says how many. If even one item is over 10 MB, the attachment is skipped (and the email says so). Your provider's own size limit still applies; many SMTP servers allow 10 to 25 MB.
- Retries: Slack, Discord, Teams, Telegram, Resend and the webhook get up to 4 attempts (on HTTP 429, 5xx and network errors; Resend also on a concurrent request with the same idempotency key), waiting at most 60 seconds at a time and 90 seconds in total per channel. A service that asks for a longer wait counts as failed for this run. SMTP gets up to 3 attempts (on connection errors and temporary 4xx replies). Channels are sent in parallel.
- Restarts: after each message goes out, the channel is recorded in the run's key-value store, and a restarted run (for example after a platform migration) skips recorded channels. A restart in the moment between a message going out and that record being saved can still send that channel twice. Charges carry a per-run, per-channel idempotency key, so such a repeat isn't charged twice.
- Duplicates: if a service accepts a message but its answer is lost (for example a timeout), the retry can deliver it twice. Resend emails are sent with a per-run idempotency key, so Resend won't send the same email twice within 24 hours; if a restarted run's email differs slightly (for example the time in the subject), Resend refuses it and the channel is reported as "probably already sent".
- Webhook URLs must use
https(the generic webhook may also usehttp). Redirects aren't followed. - The dataset is read once: without an attachment, only the preview rows are read and the item count comes from the dataset's metadata; with an attachment, items are read in pages of 100 until the 10 MB cap.
- Formatting: Telegram and Discord limits are counted the way those services count (UTF-16 code units, so an emoji can count as 2). If Telegram still says a message is too long, it's retried once with a shorter preview. Markdown characters in your data are escaped in Teams cards. In the CSV attachment, any value starting with
=,+,-,@(or their full-width forms), a tab or a carriage return gets a leading'so spreadsheet apps don't run it as a formula; plain numbers such as-5or1.5e3are left as they are. - Values of custom webhook headers are masked in logs when they're longer than 8 characters or the header name looks like a credential (
Authorization,X-Api-Key,…Token,…Secret…). - Not affiliated with Slack, Discord, Microsoft, Telegram or Resend.
Related Actors
This notification Actor is part of a small suite of Actors that work together after any scraper:
| Actor | Use it to |
|---|---|
| Merge & Deduplicate Datasets | Keep only items not seen in earlier runs, so you're alerted only about new ones. |
| Google Sheets Sync | Keep the full results in a Google Sheet and link it in your message. |
| Dataset Delivery | Deliver the full dataset as a file to SFTP, FTP, Dropbox or Google Drive. |
| SEC Funding Rounds Tracker | Get a daily Slack or email digest of new startup funding rounds. |
| Vector DB Sync | Keep a Pinecone or Qdrant index in sync with your crawls. |
| Phone Number Validator & Formatter | Check phone numbers in new leads before you are alerted about them. |
| RSS & Atom Feed Reader | Get an email or chat message with new feed items after each run. |
| Dataset Filter & Transform | Filter the rows first, so you are alerted only about the ones that matter. |
| Bulk URL Status Checker | Get an alert when any of your URLs breaks or its SSL certificate is about to expire. |
| Broken Link Checker | Crawl your site on a schedule and get an alert when broken links appear. |
| Website Contact Info Scraper | Scan company websites for emails, phones and social profiles. |
| Career Page Jobs Scraper | Get an email or Slack message when tracked companies post new jobs. |