Skip to content
API

Datasets

Create datasets, push items, and export them as JSON, CSV, Excel, XML, or RSS.

Datasets store tabular results (dataset items) from Actor runs. All endpoints are prefixed with https://api.scrape.ly/v2. Authenticate with Authorization: Bearer $SCRAPELY_TOKEN. Get dataset items also accepts a signed URL instead of a token.

Refer to a dataset by its UUID. Get dataset and Get dataset statistics also accept a named ID, username~dataset-name, where username is your own public username. All other routes, including the items routes, require the UUID.

Unnamed datasets (created without a name) expire after your account's unnamed-storage retention period: 2 days (48 hours) on the free plan, and 31, 60 or 90 days on the Starter, Scale or Business plan. On the free plan, the default storages of your latest 10 runs are kept until those runs are deleted. Named datasets do not expire. Creating a named dataset that you already own returns the existing dataset.

A run's default dataset is also reachable under the run: /v2/actor-runs/{runId}/dataset and its sub-paths (for example /v2/actor-runs/{runId}/dataset/items) are rewritten to /v2/datasets/{defaultDatasetId}/.... You must own the run.

Endpoints

MethodPathDescription
GET/v2/datasetsList datasets you own
POST/v2/datasetsCreate a dataset
GET/v2/datasets/{datasetId}Get dataset metadata
PUT/v2/datasets/{datasetId}Rename a dataset
DELETE/v2/datasets/{datasetId}Delete a dataset and its items
GET/v2/datasets/{datasetId}/itemsGet items in JSON, JSONL, CSV, HTML, XLSX, XML, RSS, or PDF
HEAD/v2/datasets/{datasetId}/itemsGet the item headers without a body
POST/v2/datasets/{datasetId}/itemsAppend items
GET/v2/datasets/{datasetId}/statisticsPer-field statistics

Errors and limits

Errors use the standard envelope { "error": { "type": "...", "message": "..." } }.

Statuserror.typeWhen
400invalid-requestMalformed dataset ID, or the dataset is too large to sort or to compute statistics.
400schema-validation-errorPushed items fail the dataset's schema.
402insufficient-balanceCreating a dataset or pushing items with no available credit.
403forbiddenThe dataset belongs to another account.
403insufficient-permissionsA limited-permission Actor run token tried to use a dataset outside its scope.
404record-not-foundThe dataset does not exist. Get dataset items also returns this for datasets you cannot read. Also returned when the dataset is deleted, or scheduled for deletion, while items are being pushed.
409name-takenRenaming to a name you already use for another dataset.
413request-too-largeA JSON request body over 10 MB.
429rate-limit-exceededStorage rate limit, or too many large item downloads running at once.
429storage-backpressureStorage is catching up. Nothing was written; retry after Retry-After (5 seconds).
503service-unavailableStorage is temporarily unavailable on create, push, delete, or read. Retry after Retry-After (5 seconds). A 503 on push may mean the items were stored.

Dataset, key-value store, and request queue routes share a storage rate limit: by default 5,000 requests per minute for your account, plus a per-IP ceiling of 5,000 requests per minute. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset; a 429 also carries Retry-After.

Get list of datasets

GET/v2/datasets

Lists datasets you own. Unnamed datasets are omitted unless you pass unnamed=1.

Query paramTypeDescription
unnamedboolean1 or true includes unnamed datasets.
namestringCase-insensitive substring match on the dataset name.
sortBystringcreatedAt (default), modifiedAt, or name.
descboolean1 or true reverses the sort order. Default is ascending.
offsetnumberNumber of datasets to skip (default 0).
limitnumberPage size (default 1000, max 1000).
curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  "https://api.scrape.ly/v2/datasets?unnamed=1&limit=20&desc=1"

actId and actRunId are always null in list items. Use Get dataset for the run link.

GET/v2/datasets?limit=5&unnamed=1

Create dataset

POST/v2/datasets

Send name in the JSON body or as a query parameter. Omit it to create an unnamed dataset.

Body / query fieldTypeDescription
namestringOptional dataset name. If you already own a dataset with this name, that dataset is returned with 200 instead of creating a new one.
.bash
curl -X POST https://api.scrape.ly/v2/datasets \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-results"}'

A new dataset returns 201 with a Location header and the same body shape as Get dataset. urlSigningSecretKey is null in this response; read it with Get dataset.

Get dataset

GET/v2/datasets/{datasetId}

Accepts a UUID or username~dataset-name.

curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  https://api.scrape.ly/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10
  • urlSigningSecretKey is the key for signed items URLs. Only this endpoint returns it.
  • cleanItemCount counts items that have at least one field whose name does not start with #.
  • fields and schema are always null, and generalAccess is always RESTRICTED.
GET/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10

Update dataset

PUT/v2/datasets/{datasetId}

Renames the dataset. {datasetId} must be a UUID. name is the only field this endpoint changes.

Body fieldTypeDescription
namestringNew dataset name. An empty string makes the dataset unnamed. Returns 409 name-taken if you already have another dataset with this name.
.bash
curl -X PUT https://api.scrape.ly/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10 \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "renamed-results"}'

Returns the updated dataset object (with urlSigningSecretKey set to null).

Delete dataset

DELETE/v2/datasets/{datasetId}

Deletes the dataset and all its items. {datasetId} must be a UUID. Returns 204 No Content.

.bash
curl -X DELETE -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  https://api.scrape.ly/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10

Get dataset items

.text
GET /v2/datasets/{datasetId}/items
HEAD /v2/datasets/{datasetId}/items

Returns items directly, not wrapped in the data envelope. {datasetId} must be a UUID. HEAD returns the same headers without a body.

Pagination is reported in response headers:

HeaderValue
X-Apify-Pagination-OffsetThe offset you sent.
X-Apify-Pagination-LimitThe limit you sent, or 999999999999 when no limit was set.
X-Apify-Pagination-CountItems in this response (for streamed responses, items read before filters such as skipEmpty).
X-Apify-Pagination-TotalItems in the dataset.
X-Apify-Pagination-Desctrue or false.

Query parameters

Query paramTypeDescription
formatstringjson (default), jsonl, csv, html, xlsx, xml, rss, or pdf. Unknown values return JSON.
offsetnumberItems to skip (default 0).
limitnumberMaximum items to return. Missing, 0, or negative returns all remaining items.
descboolean1 or true returns items newest-first. With sortBy, reverses the field order instead.
sortBystringSort by this top-level item field across the whole dataset. Empty values (null, missing, "") sort last. Limited to datasets of at most 10,000 items and 32 MB; larger datasets return 400.
fieldsstringComma-separated top-level fields to keep.
omitstringComma-separated top-level fields to drop.
unwindstringComma-separated fields to unwind. An array field produces one item per element; an object field has its keys merged into the item.
flattenstringComma-separated object fields to flatten one level into field.child keys.
cleanboolean1 or true is the same as skipHidden=1&skipEmpty=1.
skipHiddenbooleanDrop fields whose names start with #.
skipEmptybooleanSkip items with no fields left.
skipFailedPagesbooleanSkip items that have an errorInfo property.
simplifiedbooleanLegacy crawler format: keep only url, pageFunctionResult, and errorInfo, then unwind pageFunctionResult.
attachmentboolean1 or true sets Content-Disposition: attachment (attachment; filename="dataset.xlsx" for XLSX). PDF always sends Content-Disposition with a filename from the dataset name: inline by default, attachment with this option.
delimiterstringCSV field delimiter (default ,).
skipHeaderRowbooleanCSV: omit the header row.
bombooleanCSV: prepend a UTF-8 byte order mark. On by default; bom=0 or bom=false turns it off.
escapeFormulasbooleanCSV: a text value or column name that starts with =, +, -, @, a tab, or a carriage return gets a leading ', so spreadsheets show it as text instead of running it as a formula. Numbers such as -12.5 stay as they are. On by default; escapeFormulas=0 or escapeFormulas=false writes values unchanged.
xmlRootstringXML root element name (default items).
xmlRowstringXML element name for each item (default item).
signaturestringSigned-URL token. See Signed items URLs.

Options are applied to each item in this order: fields, omit, unwind, flatten, skipHidden/clean, skipEmpty/clean, skipFailedPages, simplified. offset and limit select items before these options run, so filters can return fewer items than limit. There is no view parameter; it is ignored.

curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  "https://api.scrape.ly/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10/items?format=json&offset=0&limit=100&fields=url,title,price&clean=1"
GET/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10/items?format=json&limit=10&clean=1

Output formats

formatContent-TypeNotes
jsonapplication/jsonOne JSON array.
jsonlapplication/x-jsonlinesOne JSON object per line.
csvtext/csvNested objects and arrays become parent/child and parent/0 columns. Every value is quoted and each line ends with CRLF.
htmltext/htmlA single <table> with the same columns as CSV.
xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetOne sheet named Data with the same columns as CSV.
xmlapplication/xml<items><item>...</item></items>, renamed by xmlRoot and xmlRow. A @ key becomes attributes and a # key becomes text content.
rssapplication/rss+xml<rss><channel><item>...</item></channel></rss>.
pdfapplication/pdfA table with one column per top-level field. See PDF.
.bash
curl -H "Authorization: Bearer $SCRAPELY_TOKEN" -o results.csv \
  "https://api.scrape.ly/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10/items?format=csv&bom=0&attachment=1"

PDF

format=pdf applies fields, omit, unwind, flatten, clean, offset, limit, and desc like the other formats, then lays the items out as a report.

AspectBehavior
HeadingDataset name, dataset ID, run ID, row count, and generation time (UTC). Unnamed datasets are titled with the Actor when you own the dataset, otherwise Dataset {datasetId}.
ColumnsTop-level fields in fields order, or in first-seen order without fields, plus a # column with each item's position in the dataset.
OrientationPortrait up to 6 columns, landscape from 7.
Wide datasetsMore than 16 columns render as one key/value block per item instead of a table.
PagesColumn header repeated on every page; Page X of Y footer.
ValuesNested arrays and objects are written inline (a, b, key: value). Long text wraps and is cut with ….
Item capAt most 2,000 items are read. The PDF notes how many of the selected items it contains; page on with offset. X-Apify-Pagination-Count is the number read.
Row capAt most 5,000 rows after unwind.
Text capAbout 3 million characters. Rendering stops with a note in the PDF.
FontsDejaVu Sans: Latin, Greek, Cyrillic, and common symbols. Characters outside it, such as CJK, show as empty boxes; use another format for those datasets.
FilenameContent-Disposition: inline (or attachment with attachment=1) and a filename from the dataset name, or dataset-{datasetId}.pdf.
.bash
curl -H "Authorization: Bearer $SCRAPELY_TOKEN" -o results.pdf \
  "https://api.scrape.ly/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10/items?format=pdf&fields=title,url,price&clean=1"

Large downloads

Requests for up to 1,000 items are built in memory. Larger requests, including requests with no limit, are streamed. You can run up to 4 streamed downloads at once; beyond that the API returns 429 rate-limit-exceeded with Retry-After: 5. If a streamed download fails partway, the connection is closed instead of ending normally, so a truncated file is detectable. A PDF is always finished in memory before it is sent, which is why it has its own caps.

Signed items URLs

A signed URL lets someone download items without your API token. Append signature=<token>, where the token is minted with the dataset's urlSigningSecretKey from Get dataset. A signature:

  • covers the HTTP method and the path /v2/datasets/{datasetId}/items, not the query string, so the recipient can change format, limit, and the other options;
  • expires: there are no permanent signatures;
  • is only checked when the request has no Authorization header.

The JavaScript API client mints these URLs:

.javascript
import { ScrapelyClient } from 'scrapely-client';

const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN, baseUrl: 'https://api.scrape.ly' });
const url = await client.dataset('3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10').createItemsPublicUrl({
  clean: true,
  expiresInSecs: 24 * 3600,
});
// Append &format=csv (or any other option) to the returned URL as needed.

Without expiresInSecs, the client signs the URL for one hour.

The token format is described in Signed URLs on the key-value stores page; datasets use the same scheme with an empty record key.

Store items

POST/v2/datasets/{datasetId}/items

Appends items. {datasetId} must be a UUID. The body is a JSON array of objects, or a single JSON object (stored as one item). The request body is limited to 10 MB; split larger pushes into several requests.

Returns 201 with an empty JSON object {} and a Location header pointing at the items URL.

.bash
curl -X POST https://api.scrape.ly/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10/items \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"url": "https://example.com", "title": "Example"}]'

If the dataset was created by an Actor run whose dataset schema defines fields (JSON Schema draft-07), every item is validated first. If any item fails, nothing is stored and the response is 400:

.json
{
  "error": {
    "type": "schema-validation-error",
    "message": "Schema validation failed",
    "data": {
      "invalidItems": [
        { "itemPosition": 0, "validationErrors": [{ "instancePath": "/price", "message": "must be number" }] }
      ]
    }
  }
}

A 429 storage-backpressure means nothing was written, so retry after Retry-After. A 503 service-unavailable may mean the items were stored, so a blind retry can store them twice. A 404 record-not-found means the dataset was deleted, or scheduled for deletion, during the push. See Errors and limits.

Get dataset statistics

GET/v2/datasets/{datasetId}/statistics

Returns statistics for every top-level field that appears on any item. Each field has nullCount (items where the field is missing or null). Fields with numeric values also have min and max. Accepts a UUID or username~dataset-name. Datasets with more than 10,000 items or more than 32 MB return 400 invalid-request.

curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  https://api.scrape.ly/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10/statistics
GET/v2/datasets/3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10/statistics