---
title: "Search, alerts & utilities · Scrape.ly Docs"
description: "Health and auth checks, search, Actor alerts, bookmarks, templates, and integrations."
url: https://scrape.ly/docs/api-misc
markdown: https://scrape.ly/docs/api-misc.md
---

# Search, alerts & utilities

> Health and auth checks, search, Actor alerts, bookmarks, templates, and integrations.

Cross-cutting endpoints: health and auth checks, global search, Actor alerts, bookmarks, Actor templates, the support form, and third-party integrations. Paths are relative to `https://api.scrape.ly`.

Endpoints require authentication unless noted.

## Health check

```
GET /health
```

Liveness probe. **No authentication required.** The path has no `/v2` prefix.

```bash
curl https://api.scrape.ly/health
```

The response is a bare JSON object with no `data` wrapper:

```json
{ "status": "ok", "timestamp": "2026-01-01T00:00:00.000Z" }
```

When the service is unhealthy it returns `503` with `{ "status": "unhealthy" }`. Check the status code; the body carries no other details.

Rate limited to **60 requests per minute per IP address**, lower than the general API limit, so size monitoring intervals accordingly. Use [`GET /v2/auth/check`](#auth-check) when you also need to verify a token.

## Auth check

```
GET /v2/auth/check
```

Lightweight identity probe. The response is **only** `authenticated` and, when signed in, `userId`, with no `data` wrapper.

```bash
curl "https://api.scrape.ly/v2/auth/check" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
```

With a valid token:

```json
{ "authenticated": true, "userId": "uSeRiDeXaMpLe123" }
```

Without an `Authorization` header:

```json
{ "authenticated": false }
```

An invalid or revoked token is not treated as anonymous: it returns `401 token-not-valid`.

```api-test
{ "method": "GET", "path": "/v2/auth/check" }
```

## Global search

```
GET /v2/search
```

Searches **your own** Actors, runs, and tasks.

```bash
curl "https://api.scrape.ly/v2/search?q=my-actor&limit=10" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
```

| Query param | Type | Default | Description |
| --- | --- | --- | --- |
| `q` | string | — | Search term (substring match). Empty or omitted returns empty arrays. |
| `limit` | number | 10 | Max results **per resource type** (max 50). |

What `q` matches:

- **Actors**: name, ID, username, or title. Newest-modified first.
- **Runs**: run ID, Actor name, or Actor username. Newest first.
- **Tasks**: task name, task ID, or Actor name. Newest-modified first.

```json
{
  "data": {
    "actors": [
      {
        "id": "actor-uuid",
        "name": "my-actor",
        "username": "jane",
        "title": "My Scraper",
        "description": "...",
        "isPublic": true,
        "pictureUrl": null,
        "createdAt": "2026-01-01T00:00:00.000Z",
        "modifiedAt": "2026-08-01T00:00:00.000Z"
      }
    ],
    "runs": [
      {
        "id": "run-uuid",
        "actId": "actor-uuid",
        "status": "SUCCEEDED",
        "startedAt": "2026-08-01T00:00:00.000Z",
        "finishedAt": "2026-08-01T00:05:00.000Z",
        "usageTotalUsd": 0.12,
        "usageTotalNd": 120000000,
        "actorName": "my-actor",
        "actorUsername": "jane"
      }
    ],
    "tasks": [
      {
        "id": "task-uuid",
        "name": "daily-crawl",
        "actId": "actor-uuid",
        "actorName": "my-actor",
        "actorUsername": "jane",
        "createdAt": "2026-07-01T00:00:00.000Z",
        "modifiedAt": "2026-08-01T00:00:00.000Z"
      }
    ]
  }
}
```

A run's `usageTotalUsd` is in US dollars. `usageTotalNd` is the same amount in nanodollars (`$1 = 1_000_000_000`).

```api-test
{ "method": "GET", "path": "/v2/search?q=actor&limit=3" }
```

## Actor alerts

Alerts watch the runs of an Actor you can access (you own it, or it's public) and notify you by email and/or in the dashboard when a condition is met. They are checked after each run finishes.

- Alerts on your own Actor fire for every run of it. Alerts on someone else's public Actor fire only for your runs.
- Each alert notifies at most once per minute.
- Email needs a saved notification email and counts toward your weekly email quota. See [Notifications](https://scrape.ly/docs/notifications.md#custom-actor-alerts).

### List alerts

```
GET /v2/actors/{actorId}/alerts
```

Returns **your** alerts for that Actor, newest first. The envelope is `{ "alerts": [...] }`, not `{ "data": ... }`. Boolean fields come back as `1` / `0`.

```bash [Request]
curl "https://api.scrape.ly/v2/actors/{actorId}/alerts" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
```

```json [Response]
{
  "alerts": [
    {
      "id": "alert-uuid",
      "actorId": "actor-uuid",
      "userId": "uSeRiDeXaMpLe123",
      "name": "Run failed",
      "enabled": 1,
      "triggerType": "METRIC",
      "metric": "STATUS",
      "condition": null,
      "value": null,
      "statusValue": "FAILED",
      "datasetField": null,
      "datasetFieldStatistic": null,
      "notifyEmail": 1,
      "notifyWeb": 1,
      "createdAt": "2026-08-01T12:00:00.000Z",
      "updatedAt": "2026-08-01T12:00:00.000Z"
    }
  ]
}
```

```api-test
{ "method": "GET", "path": "/v2/actors/{actorId}/alerts" }
```

### Create an alert

```
POST /v2/actors/{actorId}/alerts
```

Returns `201` with `{ "data": <alert> }`.

```bash
curl -X POST "https://api.scrape.ly/v2/actors/{actorId}/alerts" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Slow run",
    "triggerType": "METRIC",
    "metric": "DURATION",
    "condition": "GREATER_THAN",
    "value": 600,
    "notifyEmail": true,
    "notifyWeb": true
  }'
```

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes | Display name. |
| `triggerType` | string | Yes | `METRIC` or `DATASET_FIELD_STATS`. |
| `metric` | string | For `METRIC` | A metric from the table below, or `STATUS`. |
| `condition` | string | For comparisons | `GREATER_THAN`, `LESS_THAN`, or `EQUALS`. |
| `value` | number | For comparisons | Threshold. |
| `statusValue` | string | With `metric: "STATUS"` | Run status to match, such as `FAILED`, `TIMED-OUT`, `ABORTED`, or `SUCCEEDED`. |
| `datasetField` | string | For dataset triggers | Top-level field name; letters, digits, and underscores only. |
| `datasetFieldStatistic` | string | For dataset triggers | `FILLED_PERCENTAGE`, `AVG_VALUE`, `MIN_VALUE`, `MAX_VALUE`, or `AVG_LENGTH`. |
| `enabled` | boolean | No | Default `true`. |
| `notifyEmail` | boolean | No | Default `true`. |
| `notifyWeb` | boolean | No | Dashboard notification. Default `true`. |

Only `name` and `triggerType` are validated. An alert with an unknown metric, statistic, or condition, or with missing fields, is saved but never fires.

**Status alerts**: set `metric` to `STATUS` and `statusValue` to a run status. `condition` and `value` are ignored.

**Metric alerts** compare one run metric with `value`:

| Metric | Unit |
| --- | --- |
| `DURATION` | Seconds |
| `USAGE` | Run cost in USD |
| `COMPUTE_UNITS` | Compute units |
| `NUMBER_OF_RESULTS`, `NUMBER_OF_DATASET_ITEMS` | Items in the default dataset |
| `NUMBER_OF_DATASET_FIELDS` | Fields in the build's dataset schema |
| `DURATION_PER_RESULT` | Seconds per dataset item |
| `COST_PER_RESULT` | USD per dataset item |
| `MAX_CPU_USAGE` | Peak CPU usage |
| `MAX_MEMORY_USAGE` | Peak memory, bytes |
| `SIZE_OF_KEY_VALUE_STORE` | Bytes |
| `NUMBER_OF_REQUESTS_HANDLED` | Handled request queue requests |
| `NUMBER_OF_DATASET_READS`, `NUMBER_OF_DATASET_WRITES` | Operations |
| `NUMBER_OF_KV_STORE_READS`, `NUMBER_OF_KV_STORE_WRITES`, `NUMBER_OF_KV_STORE_LISTS` | Operations |
| `NUMBER_OF_REQUEST_QUEUE_READS`, `NUMBER_OF_REQUEST_QUEUE_WRITES` | Operations |
| `NUMBER_OF_REQUESTS` | Request queue reads + writes |
| `SIZE_OF_INTERNAL_DATA_TRANSFER`, `SIZE_OF_EXTERNAL_DATA_TRANSFER` | Bytes |

**Dataset field alerts** (`DATASET_FIELD_STATS`) compute a statistic over one field of the run's default dataset, sampling up to 1,000 items, and compare it with `value`. `FILLED_PERCENTAGE` is the share of items where the field is present and not null.

### Get, update, or delete an alert

```
GET /v2/actors/{actorId}/alerts/{alertId}
PUT /v2/actors/{actorId}/alerts/{alertId}
DELETE /v2/actors/{actorId}/alerts/{alertId}
```

`GET` and `PUT` return `{ "data": <alert> }`. `PUT` is partial: only fields you send change. `DELETE` returns `204` with an empty body.

```bash
curl -X PUT "https://api.scrape.ly/v2/actors/{actorId}/alerts/{alertId}" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": false }'

curl -X DELETE "https://api.scrape.ly/v2/actors/{actorId}/alerts/{alertId}" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
```

### Dataset schema

```
GET /v2/actors/{actorId}/dataset-schema
```

Output fields from the build you run (the owner's default build, or the [User Build](https://scrape.ly/docs/publishing.md#user-build) for everyone else), useful for picking a `datasetField`. The response is `{ "fields": [{ "name", "type", "format", "title", "description" }] }` with no `data` wrapper, or `{ "fields": [] }` when the build has no dataset schema.

```bash
curl "https://api.scrape.ly/v2/actors/{actorId}/dataset-schema" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
```

```api-test
{ "method": "GET", "path": "/v2/actors/{actorId}/dataset-schema" }
```

## Bookmarks

Bookmark Actors for quick access.

```
POST /v2/actors/{actorId}/bookmark
DELETE /v2/actors/{actorId}/bookmark
GET /v2/actors/{actorId}/bookmark
GET /v2/users/me/bookmarks
```

`{actorId}` is an Actor ID or a `username~name` slug; both address the same bookmark. Bookmarks are per user, and adding or removing one twice is harmless. You can have up to 500 bookmarks.

`GET /v2/actors/{actorId}/bookmark` checks whether **you** bookmarked that Actor: `{ "data": { "bookmarked": true, "count": null } }`. Bookmark counts are not public: `count` is the Actor's total only when you own it, and `null` otherwise.

`GET /v2/users/me/bookmarks` lists your bookmarked Actors, newest first, one page at a time:

| Parameter | Description |
| --- | --- |
| `offset` | Number of bookmarks to skip. Default `0`. |
| `limit` | Page size, 1 to 200. Default `50`. |
| `search` | Optional. Matches the Actor's title, name or username, ignoring case; every word must match. Up to 200 characters. |

The response is `{ "data": { "total": 120, "offset": 0, "limit": 50, "count": 50, "items": [...] } }`. `total` counts all your bookmarks that match `search` (or all of them without one), so you can page through them with `offset`. Each item has `id`, `name`, `username`, `title`, `description`, `isPublic`, `pictureUrl` and `bookmarkedAt`. Actors that were made private by their owner or deleted drop out of the list.

```bash
curl -X POST "https://api.scrape.ly/v2/actors/{actorId}/bookmark" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
```

`POST` returns `{ "data": { "success": true, "bookmarked": true, "count": null } }` (`count` as for `GET`), `404 not-found` if the Actor doesn't exist or is another user's private Actor, or `403 limit-reached` if you already have 500 bookmarks (remove one to add another; bookmarking an Actor you already bookmarked still succeeds). `DELETE` returns `{ "data": { "success": true, "bookmarked": false, "count": null } }`.

## Actor templates

Starter templates for new Actors: the same catalog the dashboard's Actor creation wizard and `scrapely create --template` use. The template values in the examples below are illustrative; read the live catalog for real ones.

### List templates

```
GET /v2/actor-templates
```

**No authentication required.**

```bash [Request]
curl https://api.scrape.ly/v2/actor-templates
```

```json [Response]
{
  "data": [
    {
      "id": "js-crawlee-cheerio",
      "name": "js-crawlee-cheerio",
      "aliases": [],
      "displayName": "Crawlee + Cheerio",
      "description": "Fast HTML scraping with Crawlee and Cheerio.",
      "language": "javascript",
      "useCases": ["scraping"],
      "folder": "js-crawlee-cheerio",
      "mainFile": "src/main.js"
    }
  ],
  "total": 1
}
```

`language` is `javascript`, `typescript`, or `python`. `name` always equals `id`. You can also refer to a template by any of its `aliases`.

```api-test
{ "method": "GET", "path": "/v2/actor-templates" }
```

### Get a template

```
GET /v2/actor-templates/{templateId}
```

**No authentication required.** Returns the template plus the contents of its entry-point file and README for previews (`null` when missing).

```json
{
  "data": {
    "template": { "id": "js-crawlee-cheerio", "name": "js-crawlee-cheerio", "displayName": "Crawlee + Cheerio" },
    "files": {
      "main": "import { Actor } from ...",
      "readme": "# Crawlee + Cheerio ..."
    }
  }
}
```

```api-test
{ "method": "GET", "path": "/v2/actor-templates/js-crawlee-cheerio" }
```

### Create an Actor from a template

```
POST /v2/actors/from-template
```

Creates an Actor hosted on Scrape.ly with the template's files as its source (version `0.0.1`, build tag `latest`). It doesn't start a build.

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `templateId` | string | Yes | Template ID or alias. |
| `name` | string | Yes | Actor name, max 40 characters. |
| `title` | string | No | Defaults to the template's `displayName`. |
| `description` | string | No | Max 500 characters. Defaults to the template's description. |

```bash
curl -X POST https://api.scrape.ly/v2/actors/from-template \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "templateId": "js-crawlee-cheerio", "name": "my-scraper" }'
```

Returns `201` with `{ "data": { "actor": { ... }, "template": { "id", "displayName" } } }`. Your Actor-count limit applies.

### Create a GitHub repository from a template

```
POST /v2/actor-templates/{templateId}/git-repo
```

Requires a connected [GitHub integration](#integrations). Scrape.ly creates a **private** repository under your GitHub user account (not an organization), pushes the template files, creates an Actor whose source is that repository, and starts the first build.

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `repoName` | string | Yes | 1–100 characters: letters, digits, `.`, `-`, `_`. |
| `actorName` | string | No | Lowercase letters, digits, and `-`, max 40 characters. Defaults to `repoName`. If taken, a 6-digit suffix is added. |
| `title` / `description` | string | No | Default to the template's values. |
| `autoBuild` | boolean | No | Default `true`: register a GitHub push webhook so every push rebuilds the Actor. |

`201` response:

```json
{
  "data": {
    "actorId": "actor-uuid",
    "actorName": "my-scraper",
    "gitVersionAttached": true,
    "webhookRegistered": true,
    "webhookUrl": "https://api.scrape.ly/v2/actors/actor-uuid/builds?token=...",
    "buildStarted": true,
    "repo": { "fullName": "jane/my-scraper", "branch": "main" }
  }
}
```

If the repository can't be created, the Actor is deleted again and nothing is left behind. Webhook registration and the first build are best effort; check `webhookRegistered` and `buildStarted`.

> [!WARNING]
> `webhookUrl` contains your API key. Treat the response as secret. Resetting your API key breaks this webhook, so re-register it after a reset.

### Template errors

| Status | Type | Meaning |
| --- | --- | --- |
| 400 | `invalid-input` | Missing or invalid body field |
| 400 | `github-not-connected` | Connect GitHub first |
| 400 | `profanity-detected` | Name, title, or description contains blocked words |
| 404 | `template-not-found` | Unknown template ID |
| 409 | `name-already-exists` | Actor name taken and no free alternative found |
| 502 | `template-catalog-unavailable` / `template-fetch-failed` | Template source temporarily unavailable |

## Support form

```
POST /v2/public/support
```

Sends a message to Scrape.ly support. **Authentication is optional**: with a valid API key, your user ID, account email, and username are attached, and your account email is used if you leave `email` empty.

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `message` | string | Yes | 10–5,000 characters. |
| `email` | string | Yes, unless authenticated | Reply-to address. |
| `kind` | string | No | `support` (default) or `contact`. |
| `topic` | string | No | `account`, `actors`, `api`, `store`, `bug`, `billing`, `partnership`, `general`, or `other`. Unknown values become `other` (support) or `general` (contact). |
| `name` | string | No | Max 120 characters. |
| `subject` | string | No | Max 200 characters. |

```bash [Request]
curl -X POST https://api.scrape.ly/v2/public/support \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane@example.com",
    "topic": "api",
    "subject": "Question about datasets",
    "message": "How do I export a dataset as CSV?"
  }'
```

```json [Response]
{ "data": { "ok": true, "authenticated": false, "userId": null } }
```

Rate limits: 5 requests per hour per IP address, 10 per day per account when authenticated, and 5 per hour per email address. Errors: `400 invalid-input` (bad `kind`, invalid email, or message under 10 characters), `429 rate-limit-exceeded`, and `502 email-failed` (email `support@scrape.ly` directly instead).

## Integrations

Connect Slack and GitHub to your account. In the dashboard these live in **Settings → Connections**.

### List integrations

```
GET /v2/integrations
```

```bash [Request]
curl "https://api.scrape.ly/v2/integrations" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
```

```json [Response]
{
  "data": {
    "slack": { "connected": true },
    "github": { "connected": false }
  }
}
```

Each value includes `connected`. When connected, `credential` (provider metadata) and `integration` (`integrationType`, `enabled`, `config`, timestamps) are also present. For GitHub, `scopes`, `missingScopes`, and `reconnectRequired` tell you whether the connection needs to be renewed to grant newly required scopes.

```api-test
{ "method": "GET", "path": "/v2/integrations" }
```

### Disconnect

```
DELETE /v2/integrations/{type}
```

`type` is one of `slack`, `github`, `gmail`, `google_drive`, or `airtable`. Returns `204`. Invalid types return `400 invalid-integration`.

```bash
curl -X DELETE "https://api.scrape.ly/v2/integrations/slack" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
```

### OAuth

These routes start a browser OAuth flow and redirect back to the dashboard, which opens **Settings → Connections**. Open them in a browser while signed in; they are not JSON APIs.

| Endpoint | Description |
| --- | --- |
| `GET /v2/integrations/oauth/slack` | Redirect to Slack authorization. |
| `GET /v2/integrations/oauth/slack/callback` | Slack return URL. Stores credentials and redirects to the dashboard. |
| `GET /v2/integrations/github` | Redirect to GitHub authorization. |
| `GET /v2/integrations/github/callback` | GitHub return URL. Stores credentials and redirects to the dashboard. |

Callbacks return `400 invalid-request` for a missing `code` or `state` and `400 invalid-state` for an expired OAuth state.

### GitHub repositories

```
GET /v2/integrations/github/repos
```

Lists repositories for the connected GitHub account (most recently updated first when not searching). Requires a GitHub integration (`400 not-connected` otherwise).

| Query param | Type | Default | Description |
| --- | --- | --- | --- |
| `page` | number | 1 | Page number. |
| `per_page` | number | 30 | Page size. |
| `search` | string | — | Search your repositories instead of browsing. |

```bash [Request]
curl "https://api.scrape.ly/v2/integrations/github/repos?page=1&per_page=30&search=scraper" \
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
```

```json [Response]
{
  "data": {
    "repos": [
      {
        "id": 123,
        "name": "my-scraper",
        "full_name": "jane/my-scraper",
        "description": "My scraper",
        "html_url": "https://github.com/jane/my-scraper",
        "language": "JavaScript",
        "stargazers_count": 0,
        "forks_count": 0,
        "private": false,
        "fork": false,
        "updated_at": "2026-08-01T00:00:00Z"
      }
    ],
    "total_count": 12,
    "page": 1,
    "per_page": 30
  }
}
```

## Errors

| Status | Type | Meaning |
| --- | --- | --- |
| 400 | `invalid-input` | Missing alert name or trigger type, or invalid template/support input |
| 400 | `not-connected` / `github-not-connected` | GitHub is not connected |
| 400 | `invalid-integration` | Unknown integration type |
| 401 | `token-not-valid` | Invalid or revoked token |
| 403 | `forbidden` | Actor is private and you don't own it |
| 404 | `actor-not-found` / `alert-not-found` / `template-not-found` | Unknown Actor, alert, or template |
| 429 | `rate-limit-exceeded` | Too many requests |

---

- Previous: [Messages & notifications](https://scrape.ly/docs/api-messaging.md)
- Next: [Standby mode](https://scrape.ly/docs/api-standby.md)
- All docs: [Docs index](https://scrape.ly/docs.md), [llms.txt](https://scrape.ly/llms.txt)
