---
title: "Notifications · Scrape.ly Docs"
description: "What Scrape.ly notifies you about, on which channel, and how to configure it."
url: https://scrape.ly/docs/notifications
markdown: https://scrape.ly/docs/notifications.md
---

# Notifications

> What Scrape.ly notifies you about, on which channel, and how to configure it.

Scrape.ly notifies you about billing, storage, schedules and automations, your Actors, and your account by email and in the dashboard. Low-balance alerts can also call a webhook. Configure everything in **Settings → Notifications**, or with `GET` / `PUT /v2/users/me/notification-settings`.

## Delivery channels

| Channel | How it works |
| --- | --- |
| **Dashboard** | In-app notification in the dashboard bell. Appears without a page refresh. |
| **Email** | Sent from `Scrape.ly <noreply@scrape.ly>` to your notification email: your account email, or another address you verified with a code. See [Notification email](#notification-email). |
| **Webhook** | HTTP `POST` for low-balance alerts only. |

The **Delivery channels** card at the top of the page has the master switches: **Dashboard**, **Email**, and **Notification email**. Turning a channel off silences it for every notification type that respects it (see [Issues and messages](#issues-and-messages) for the exceptions).

## How a notification is delivered

For each event, Scrape.ly checks, in order:

1. The channel's master switch (`consoleNotificationsEnabled` or `emailNotificationsEnabled`).
2. The per-type switch in **What you get notified about**, for example `scheduleFailureEmail`.
3. A resource-level setting, where one exists: a schedule's own notification setting or a custom alert's channels.
4. Delivery requirements: the weekly email quota and deduplication.

Delivery is best effort. A failed email, webhook, or dashboard notification is logged and never rolls back the action that triggered it.

## Notification types

Each row in **Settings → Notifications → What you get notified about** has an **Email** and a **Dashboard** switch. These are the types and the settings behind them.

### Billing and account

| Dashboard row | What triggers it | Settings |
| --- | --- | --- |
| **Out of prepaid usage** | A charge takes your balance below your low-balance threshold. At most once per 24 hours. | `lowBalanceEmail`, `lowBalanceWeb` |
| **Plan expiration** | Your paid plan's renewal date passed. Sent once per expiry. | `planExpirationEmail`, `planExpirationWeb` |
| **Credit expiration** | A pay-as-you-go credit package expires within 7 days. Sent once per package. | `creditExpirationEmail`, `creditExpirationWeb` |
| **API key created** | Your API key was reset. At most once per hour. | `apiKeyCreatedEmail`, `apiKeyCreatedWeb` |

#### Low balance alert

The **Low balance alert** card sets when the alert fires and whether it also calls a webhook:

| Dashboard field | Setting | Notes |
| --- | --- | --- |
| **Threshold** | `lowBalanceThresholdNd` | In nanodollars (`$1 = 1_000_000_000`); the dashboard takes dollars. The default `0` turns the alert off. |
| **Webhook** | `lowBalanceWebhook` | Also call the webhook when the alert fires. |
| **Webhook URL** | `lowBalanceWebhookUrl` | Any public `http` or `https` URL. Local and private-network addresses are rejected. |

When a charge takes your balance below the threshold, the alert goes to email, the dashboard, and (if **Webhook** is on) your webhook URL, at most once per 24 hours:

```json
{
  "event": "low_balance",
  "userId": "uSeRiDeXaMpLe123",
  "balance": "5.00",
  "threshold": "10.00",
  "balanceNd": 5000000000,
  "thresholdNd": 10000000000,
  "timestamp": "2026-01-01T00:00:00.000Z"
}
```

The webhook times out after 5 seconds and redirects are not followed.

> [!NOTE]
> A second webhook is also sent whenever a run starts, or storage cleanup runs, while your balance is below the threshold. It goes to `lowBalanceWebhookUrl` whenever a URL and a threshold are set, even if the **Webhook** switch is off, and it is not deduplicated. Its payload has no `event` field, and `balance` and `threshold` are numbers in nanodollars: `{ "userId": "...", "balance": 5000000000, "threshold": 10000000000, "timestamp": "..." }`. Handle both shapes, or leave the URL empty if you don't want webhooks.

### Storage

**Storage expiration** (`storageExpirationEmail`, `storageExpirationWeb`) is a daily digest: one email and one dashboard notification per day listing unnamed storages that were deleted by retention and those that expire within the next 3 days. Named storages don't expire this way. Retention is covered in [Storage](https://scrape.ly/docs/storage.md).

### Schedules and automations

**Schedule failures** (`scheduleFailureEmail`, `scheduleFailureWeb`) are the failure alert of your schedules and [automations](https://scrape.ly/docs/automations.md). Each automation has one alert, **Alert me if it fails** in its options (on by default). It fires when:

- in an automation that only starts runs (no **Keep**, AI step, or **Send**), like a schedule: one of its runs can't start;
- in an automation that keeps, uses AI, or sends: every run failed or couldn't start, and none returned results.

The alert goes out by email and in the dashboard, following the account switches above. An automation sends at most one failure email per hour. Turning **Alert me if it fails** off overrides the account setting for that automation. Over the API it is `options.notifyOnFailure` on the automation and `notificationsEnabled` on the schedule; both are the same setting.

### Your Actors and Actors you use

| Dashboard row | What triggers it | Settings |
| --- | --- | --- |
| **Actor auto-test failures** | Your published Actor fails its daily auto-test 3 days in a row and is marked under maintenance. | `actorAutoTestEmail`, `actorAutoTestWeb` |
| **Actor maintenance expired** | Your Actor has been under maintenance for 30 days and is deprecated. | `actorMaintenanceEmail`, `actorMaintenanceWeb` |
| **Actor pricing changed** | An Actor you ran successfully in the last 30 days changed its pricing. The owner is not notified. | `actorPricingEmail`, `actorPricingWeb` |

### Issues and messages

Issue and direct-message notifications are console-only. They don't follow the account switches:

- **Issues**: when someone opens an issue on your Actor, you get a dashboard notification. Comments notify everyone subscribed to that issue who has comment notifications on (set per issue with the issue subscription endpoints in the [Store API](https://scrape.ly/docs/api-store.md)).
- **Direct messages**: new conversation requests, accepted requests, replies, and closed conversations notify the other participant in the dashboard. Replies respect the per-conversation dashboard setting (see [Messages API](https://scrape.ly/docs/api-messaging.md)).

> [!WARNING]
> The **Issues** and **Direct messages** rows in **Settings → Notifications**, the per-conversation email setting, and the global **Dashboard** switch currently have no effect on these notifications. No email is sent for issues or messages.

### Custom Actor alerts

Set alerts on an Actor's runs to get notified when a metric crosses a threshold, a run ends in a given status, or a dataset field looks wrong. Alerts are checked after each run finishes.

- Owners' alerts fire on every run of their Actor. Alerts you set on someone else's public Actor fire only for your own runs.
- Each alert picks its channels (`notifyEmail`, `notifyWeb`). Email still needs the global **Email** switch; dashboard notifications respect the global **Dashboard** switch.
- An alert notifies at most once per minute.
- Alert emails count toward the weekly email quota.

Create and manage alerts with the [Actor alerts API](https://scrape.ly/docs/api-misc.md#actor-alerts), which lists every metric and statistic.

## Email quota

Notification emails are limited to 50 per week by default, counted per UTC week (Monday to Sunday). These emails count toward the quota: schedule failures, storage digests, and custom Actor alerts.

Platform notices skip the quota: low balance, plan and credit expiration, Actor auto-test, maintenance, and pricing changes, and API key created. They still respect the channel and per-type switches.

When you reach the quota, further counted emails that week are dropped and you get one "quota reached" email. Dashboard notifications and webhooks are never counted.

## Settings API

```
GET /v2/users/me/notification-settings
PUT /v2/users/me/notification-settings
```

The settings are a flat JSON object of booleans plus a few delivery fields, with no `data` wrapper. `PUT` changes only the fields you send. Run tokens can't call these endpoints. The full field list and errors are in the [Users API](https://scrape.ly/docs/api-users.md#notification-settings).

```bash
curl -X PUT https://api.scrape.ly/v2/users/me/notification-settings \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "lowBalanceThresholdNd": 10000000000,
    "lowBalanceWebhook": true,
    "lowBalanceWebhookUrl": "https://example.com/hooks/balance"
  }'
```

```api-test
{ "method": "GET", "path": "/v2/users/me/notification-settings" }
```

### Notification email

Emails go to your account email unless you set another address. In **Settings → Notifications**, enter another address under **Notification email** and Scrape.ly sends it a 6-digit code, valid for 10 minutes; the address is used once you enter the code. **Use account email** switches back at any time, without a code.

```
POST /v2/users/me/notification-email/verification
POST /v2/users/me/notification-email/verification/confirm
DELETE /v2/users/me/notification-email/verification
DELETE /v2/users/me/notification-email
```

1. `POST …/verification` with `{ "email": "alerts@example.com" }` emails the code and returns `{ "pendingNotificationEmail": … }`. Your account email needs no code: asking for one returns `409 account_email`.
2. `POST …/verification/confirm` with `{ "code": "123456" }` makes the pending address your notification email. A wrong code returns `invalid_code`; after 5 wrong attempts, request a new code.
3. `DELETE …/verification` cancels a pending change. `DELETE /v2/users/me/notification-email` goes back to your account email.

`notificationEmail` in the settings is the address in use, and `notificationEmailSource` says whether it is your `account` email or a `custom` one. `PUT /v2/users/me/notification-settings` accepts `notificationEmail` only as `null` or your account email (both mean "use the account email"), or the current address; any other address returns `409 email_verification_required`.

## Dashboard notifications API

```
GET /v2/console-notifications
GET /v2/console-notifications/unread-count
PATCH /v2/console-notifications/read-all
PATCH /v2/console-notifications/{notificationId}/read
DELETE /v2/console-notifications
```

List with `offset` and `limit` (default 50, max 100). Scrape.ly keeps roughly your newest 1,000 dashboard notifications and trims older ones. See the [Messages & notifications API](https://scrape.ly/docs/api-messaging.md#dashboard-notifications) for response shapes.

---

- Previous: [API keys & permissions](https://scrape.ly/docs/api-keys.md)
- Next: [Quick start](https://scrape.ly/docs/quickstart.md)
- All docs: [Docs index](https://scrape.ly/docs.md), [llms.txt](https://scrape.ly/llms.txt)
