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
/healthLiveness probe. No authentication required. The path has no /v2 prefix.
curl https://api.scrape.ly/healthThe response is a bare JSON object with no data wrapper:
{ "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 when you also need to verify a token.
Auth check
/v2/auth/checkLightweight identity probe. The response is only authenticated and, when signed in, userId, with no data wrapper.
curl "https://api.scrape.ly/v2/auth/check" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"With a valid token:
{ "authenticated": true, "userId": "uSeRiDeXaMpLe123" }Without an Authorization header:
{ "authenticated": false }An invalid or revoked token is not treated as anonymous: it returns 401 token-not-valid.
/v2/auth/checkGlobal search
/v2/searchSearches your own Actors, runs, and tasks.
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.
{
"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).
/v2/search?q=actor&limit=3Actor 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.
List alerts
/v2/actors/{actorId}/alertsReturns your alerts for that Actor, newest first. The envelope is { "alerts": [...] }, not { "data": ... }. Boolean fields come back as 1 / 0.
curl "https://api.scrape.ly/v2/actors/{actorId}/alerts" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"/v2/actors/{actorId}/alertsCreate an alert
/v2/actors/{actorId}/alertsReturns 201 with { "data": <alert> }.
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
/v2/actors/{actorId}/alerts/{alertId}/v2/actors/{actorId}/alerts/{alertId}/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.
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
/v2/actors/{actorId}/dataset-schemaOutput fields from the build you run (the owner's default build, or the 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.
curl "https://api.scrape.ly/v2/actors/{actorId}/dataset-schema" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"/v2/actors/{actorId}/dataset-schemaBookmarks
Bookmark Actors for quick access.
/v2/actors/{actorId}/bookmark/v2/actors/{actorId}/bookmark/v2/actors/{actorId}/bookmark/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.
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
/v2/actor-templatesNo authentication required.
curl https://api.scrape.ly/v2/actor-templateslanguage is javascript, typescript, or python. name always equals id. You can also refer to a template by any of its aliases.
/v2/actor-templatesGet a template
/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).
{
"data": {
"template": { "id": "js-crawlee-cheerio", "name": "js-crawlee-cheerio", "displayName": "Crawlee + Cheerio" },
"files": {
"main": "import { Actor } from ...",
"readme": "# Crawlee + Cheerio ..."
}
}
}/v2/actor-templates/js-crawlee-cheerioCreate an Actor from a template
/v2/actors/from-templateCreates 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. |
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
/v2/actor-templates/{templateId}/git-repoRequires a connected GitHub integration. 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:
{
"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.
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
/v2/public/supportSends 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. |
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?"
}'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
/v2/integrationscurl "https://api.scrape.ly/v2/integrations" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"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.
/v2/integrationsDisconnect
/v2/integrations/{type}type is one of slack, github, gmail, google_drive, or airtable. Returns 204. Invalid types return 400 invalid-integration.
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
/v2/integrations/github/reposLists 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. |
curl "https://api.scrape.ly/v2/integrations/github/repos?page=1&per_page=30&search=scraper" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"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 |