Appearance
Files & artifacts
Scraping produces artifacts - raw HTML snapshots, screenshots, aggregated JSON/CSV results. They live in the workspace file registry and are downloaded through short-lived tokens, so no storage internals are ever exposed.
The dashboard's Files page shows one record per request - a Web Scraping API call, a Scraper API call, a batch, a crawl or a no-code run - named by its product, with a button for every format of its result: JSON, Markdown, Text, HTML, screenshot, CSV, XML. Every record links to the run it came from (Open run): the batch page, the no-code scraper's own page or the request log, where its settings are and its results can be downloaded again.
Artifact types
type | Produced by | Content |
|---|---|---|
raw_html | Web Scraping API / batch items / crawler pages | The persisted raw page HTML. |
screenshot | screenshot: true requests | Full-page PNG. |
json_results | Website Crawler | Aggregated crawl results as JSON. |
csv_results | Website Crawler | Aggregated crawl results as CSV. |
markdown_results | Website Crawler with markdown output | Every page's Markdown in one file. |
text_results | Website Crawler with text output | Every page's text in one file. |
A Web Scraping API request, a batch item or an async request also keeps a content JSON with the Markdown, text, extracted JSON and network data it asked for. A request answered from the shared cache is a record of its own too: it keeps the page and the content it was served. A Scraper API call's record offers the JSON it answered with (<product>-<request>.json). The page it was parsed from is listed only when the call asked for it with include_html; the pages of its internal helper steps are never listed.
Scraping responses reference artifacts by safe ids only:
json
"files": [
{ "id": "3f6f…", "type": "screenshot", "mime_type": "image/png", "size_bytes": 48213 }
]Endpoints
| Method & path | Purpose |
|---|---|
GET /api/v1/files | List workspace files (paginated, sortable, filterable). |
GET /api/v1/files/groups | The registry grouped by request, with product names. |
GET /api/v1/files/{id}/content | Inline text preview (first 1 MiB) for text artifacts. |
GET /api/v1/files/{id}/raw | Stream the whole file (any type) with an API key. |
POST /api/v1/files/{id}/download-token | Issue a short-lived download token. |
GET /api/v1/files/{id}/download | Download the binary with that token in a header. |
The list, the text preview and /raw accept an API key with the files:read scope as well as your dashboard session (a dashboard session also needs a role that may download files). Use /raw from code: it streams the full file - a large HTML page, a screenshot PNG or the content.json of an async request - and every read is recorded in the download audit. Issuing a download token needs the dashboard session (details). Every file is scoped to your workspace - a foreign id returns FILE_NOT_FOUND. A result file appears here once its request is completed and delivered to you (charged, or free by design); the files of a request that timed out, was stopped or could not be paid are never listed and are removed automatically.
One record per request
GET /api/v1/files/groups returns one record per request instead of one row per file. Parameters: page, per_page (default 15, up to 100), sort (createdAt or -createdAt, default newest first) and product_code - an API product code such as airbnb_search, or batch_web_scraping / website_crawler.
json
{
"data": [
{
"id": "12b4d5f3-7e0f-4f61-b0f3-d999b1e64c2c",
"ownerType": "scrape_request",
"productCode": "airbnb_search",
"productName": "Airbnb Search API",
"sourceUrl": null,
"fileCount": 2,
"totalSizeBytes": 1003520,
"createdAt": "2026-10-30T19:53:00.000Z",
"expiresAt": "2026-11-06T19:53:00.000Z",
"exports": [],
"artifacts": [
{
"format": "json",
"fileId": "…",
"contentPart": null,
"filename": "airbnb-search-12b4d5f3.json",
"mimeType": "application/json; charset=utf-8",
"sizeBytes": 41210
},
{
"format": "html",
"fileId": "…",
"contentPart": null,
"filename": "airbnb-search-77facccf.html",
"mimeType": "text/html; charset=utf-8",
"sizeBytes": 959488
}
]
}
],
"meta": { "total": 1, "page": 1, "per_page": 15, "last_page": 1 }
}sourceUrl is your target URL for the Web Scraping API and the crawler; a Scraper API record and a batch have none (a batch has one target per item, listed on its page). A crawl lists its result files and first pages; fileCount counts all of them.
A batch is one record, not one per URL: ownerType is batch_job, id is the batch job id, fileCount and totalSizeBytes cover every item's files, and artifacts is empty. Instead it carries exports - the whole batch merged into one file per format it was started with:
json
{
"id": "f2a9c1f5-fc3f-48d1-9e91-824d02ec934a",
"ownerType": "batch_job",
"productCode": "batch_web_scraping",
"productName": "Batch",
"fileCount": 120,
"artifacts": [],
"exports": [
{ "format": "json", "filename": "batch-results-f2a9c1f5-fc3f-48d1-9e91-824d02ec934a.json" },
{ "format": "markdown", "filename": "batch-results-f2a9c1f5-fc3f-48d1-9e91-824d02ec934a.md" }
]
}JSON is always offered (every item with its outcome and content); Markdown and Text only when the batch asked for them in outputFormat. Each one downloads through the batch export; a single item's own file is still available from the batch page.
Markdown and Text of a request live inside its content JSON: an artifact with contentPart: "markdown" (or "text") is served on its own by adding ?format=markdown to /content (preview) or to /download - the download is a .md / .txt file.
Download flow
bash
# 1. Issue a token (short-lived, single file)
curl -X POST "https://api.scrapeit.io/api/v1/files/FILE_ID/download-token" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
# → { "data": { "token": "…", "expires_at": "…" } }
# 2. Download with the token in the x-download-token header
curl -L -o screenshot.png \
-H "x-download-token: DOWNLOAD_TOKEN" \
"https://api.scrapeit.io/api/v1/files/FILE_ID/download"The token is accepted only in the x-download-token header: in a URL it would end up in proxy logs and browser history. A request with ?token= and no header returns 400 VALIDATION_ERROR and leaves the token unused. Expired or wrong tokens return FILE_DOWNLOAD_TOKEN_EXPIRED / FILE_DOWNLOAD_TOKEN_INVALID - just issue a fresh one.
Why tokens?
Buckets, object keys and storage credentials are internal. The token flow means a leaked URL dies within minutes and every download is attributable to a workspace member.
Retention
Every file - raw HTML, screenshots, the JSON result of a Scraper API call, and the result files of a crawl or a no-code run with its crawled pages' HTML - is kept for your plan's window (raw_html_retention_hours, shown in the dashboard), counted from when the file was made, then deleted automatically: 24 hours on Free, 3 days on Starter, 7 days on Pro, 14 days on Business, 21 days on Ultra. Download anything you need long-term. The job itself stays in your history for 6 months; its files past the window answer FILE_NOT_FOUND.