brightdata/skills/skills/scraper-studio/SKILL.md
scraper-studio
Build and run AI-generated Bright Data scrapers from the terminal via `bdata scraper create` and `bdata scraper run`. Use this skill whenever the user wants to generate a scraper from a natural-language description, build a custom scraper without writing code, turn a URL + plain-English description into a reusable scraper, run an existing Bright Data collector against a URL, or batch-scrape a list of URLs through one collector. Triggers on phrases like 'build me a scraper for', 'create a scraper
- Source repository stars
- 256
- Declared platforms
- 0
- Static risk flags
- 2
- Last source update
- 2026-06-25
- Source checked
- 2026-08-25
Decision brief
What it does: where it fits
Build a scraper from natural language, then run it. Two commands live in this skill:
Not for
- Inventing command names. The commands are exactly bdata scraper create and bdata scraper run. There is no bdata generate, no bdata scrape-batch, no bdata data, no bdata build. If you're tempted to use one of those, you'…
- Re-running create after a timeout. Generation creates a fresh collector every time. If polling times out, the half-built collector is still printed in the error output. Resume it in the web UI or wait and re-poll — don'…
Compatibility matrix
Platform support, with evidence labels
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
Inspect first. Install second.
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/brightdata/skills --skill "skills/scraper-studio"Inspect the Agent Skill "scraper-studio" from https://github.com/brightdata/skills/blob/e825f02fbcd7a89087fd1053a57ddcd45113370f/skills/scraper-studio/SKILL.md at commit e825f02fbcd7a89087fd1053a57ddcd45113370f. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
What the source asks the agent to do
- 01
Setup gate (run first)
Halt and route to setup if either check fails. Both commands require an authenticated CLI.
Halt and route to setup if either check fails. Both commands require an authenticated CLI. - 02
Full create-then-run workflow
Capture the collectorid cleanly with jq, then chain into run with the multi-URL batch path:
Capture the collectorid cleanly with jq, then chain into run with the multi-URL batch path: - 03
Pick your path
Review the “Pick your path” section in the pinned source before continuing.
Review and apply the “Pick your path” source section. - 04
Action 1 — scraper create
Generate a scraper from a URL + plain-English description.
Generate a scraper from a URL + plain-English description.The description is the most important input. A good description names every field you want and any conditions on how to find them. See references/prompts.md for examples of strong vs. weak descriptions. - 05
Minimal
bdata scraper create https://example.com/product/1 \ "Extract title, price, currency, image URL, and availability \ from this product page. If the price has a strike-through \ original price, capture both as price and originalprice."
bdata scraper create https://example.com/product/1 \ "Extract title, price, currency, image URL, and availability \ from this product page. If the price has a strike-through \ original price, capture both as price and o…
Permission review
Static risk signals and limitations
Network access
The documentation includes network, browsing, or remote request actions.
bdata scraper create https://example.com/product/1 \Network access
The documentation includes network, browsing, or remote request actions.
bdata scraper create https://example.com/product/1 \Runs scripts
The documentation asks the agent to run terminal commands or scripts.
If `/dca/crawl` server-side times out, it returns 202 with `{"error":"crawl_results_timeout","response_id":"r_late_..."}`. The CLI surfaces the `response_id` and exits with a "Re-run without --sync" message. Do exactly that — drop `--sync` Runs scripts
The documentation asks the agent to run terminal commands or scripts.
**Treating sync timeout as failure.** A `--sync` 202 timeout returns a valid `response_id` — the job is still running on the backend. Re-run the same command without `--sync` to pick it up.Evidence record
Why each signal appears
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 91/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 256 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Provenance and original SKILL.md
- Repository
- brightdata/skills
- Skill path
- skills/scraper-studio/SKILL.md
- Commit
- e825f02fbcd7a89087fd1053a57ddcd45113370f
- License
- MIT
- Collected
- 2026-08-25
- Default branch
- main
View the original SKILL.md
Bright Data — Scraper Studio
Build a scraper from natural language, then run it. Two commands live in this skill:
bdata scraper create <url> <description>— describe what you want in plain English; Bright Data's AI Flow generates a scraper template and returns acollector_id.bdata scraper run <collector_id> <url>— run that collector (or any existing one from the Bright Data web UI) against a URL and get the extracted data back.
The bridge between the two is collector_id. It is printed by create and consumed by run. Always save it.
For pre-built scrapers on platforms like Amazon, LinkedIn, TikTok, Instagram, YouTube, Reddit, etc., stop and use the data-feeds skill instead — those scrapers already exist, are faster, cheaper, and more reliable than building a new one. Use Scraper Studio when no pre-built scraper covers the target site, or when the user wants a custom shape of output for an existing platform.
Setup gate (run first)
if ! command -v bdata >/dev/null 2>&1; then
echo "bdata CLI not installed — see bright-data-best-practices/references/cli-setup.md"
elif ! bdata zones >/dev/null 2>&1; then
echo "bdata not authenticated — run: bdata login (or: bdata login --device for SSH)"
fi
Halt and route to setup if either check fails. Both commands require an authenticated CLI.
Pick your path
| Situation | Action |
|---|---|
| User describes data they want from a URL, no scraper exists yet | bdata scraper create <url> "<description>" → save the collector_id |
User has a collector_id and wants data from one URL | bdata scraper run <collector_id> <url> (default async + poll) |
User has a collector_id and wants data from many URLs | bdata scraper run <collector_id> --urls "u1,u2,..." or --input-file urls.txt (single batch call) |
| Page is small and you want fast feedback (≤ ~50 s, single URL) | bdata scraper run … --sync |
| Scraper ran but returned wrong / empty / partial data | inspect the output, then bdata scraper heal <collector_id> "<what's wrong>" → review preview → approve → re-run to verify |
| Site is a known platform (Amazon, LinkedIn, TikTok, …) | stop — use data-feeds skill |
| You want SERP / discovery, not extraction | use search skill |
| You want a one-off raw page fetch | use scrape skill |
Action 1 — scraper create
Generate a scraper from a URL + plain-English description.
bdata scraper create <url> "<description>" [--name <name>] \
[--deliver-webhook <url>] [--timeout <seconds>] \
[--json | --pretty] [-o <path>] [--timing] [-k <api-key>]
The description is the most important input. A good description names every field you want and any conditions on how to find them. See references/prompts.md for examples of strong vs. weak descriptions.
# Minimal
bdata scraper create https://example.com/product/1 \
"Extract title, price, currency, image URL, and availability \
from this product page. If the price has a strike-through \
original price, capture both as price and original_price."
# Save the full AI output for inspection
bdata scraper create https://example.com/product/1 \
"Extract title, price, and image URL" \
--name product-scraper-v1 \
--pretty -o create.json
What happens under the hood
create chains three Bright Data API calls — surface this to the user so they can debug from logs:
POST /dca/collector— creates an empty scraper template with a stub webhook delivery target (https://example.com/webhookby default). Returns acollector_idlikec_mp3tuab31lswoxvpws.POST /dca/collectors/{collector_id}/automate_template— triggers Bright Data's AI Flow with the description + URL.GET .../automate_template/progress(polled) — waits forstatus: "done". Generation typically takes 5–10 minutes for moderately complex pages.
Critical: hold the collector_id
Every failure path in create (AI trigger fails, polling times out, generation finishes with status: "failed") still leaves a partially-built collector at the printed collector_id. Always tell the user the id is recoverable — they can:
- Open
https://brightdata.com/cp/scrapers/{collector_id}to finish or inspect it in the web UI. - Re-trigger generation programmatically against the same id.
- Delete it from the UI if they want a clean slate.
Never claim "create failed, start over" without surfacing the collector_id from the response.
--timeout — default 600 s
AI generation can run 5–10 min for complex pages. If the page is simple, the default is plenty. For an elaborate description on a heavy site, raise it:
bdata scraper create https://complex-site.com/page \
"Extract all 30 fields …" \
--timeout 1200
On Timeout after N seconds waiting for AI generation, the collector_id is still printed. Re-check progress in the web UI rather than re-running create (which builds a new collector).
--deliver-webhook — placeholder by default
The CLI sets a stub webhook (https://example.com/webhook). This satisfies the API contract but does not deliver anything. For CLI use, leave the stub — you'll fetch results synchronously via scraper run. The real delivery target can be reconfigured in the Bright Data web UI if the user wants webhook delivery for production runs.
Action 2 — scraper run
Execute a scraper against one or more URLs.
bdata scraper run <collector_id> [url] \
[--urls "u1,u2,..." | --input-file <path>] \
[--sync [--sync-timeout 25-50]] \
[--timeout <seconds>] [--name <name>] [--version <version>] \
[--json | --pretty] [-o <path>] [--timing] [-k <api-key>]
Pick exactly one input source: positional <url>, --urls, or --input-file. Combining them errors with only one input source.
Multi-URL routes through /dca/trigger as a single API call with an array body — the canonical pattern from the Scraper Studio Node and Python reference projects (triggerWithUrls / trigger_with_urls). One snapshot, one poll loop, one merged result array. Do not hand-roll a for url in $(cat urls.txt); do bdata scraper run ... loop — that's N API calls for what should be one.
Choosing the run mode
┌─────────────────────────────────────────────────┐
│ Expected to finish in ≤ ~50 seconds? │
└─────────────────────────────────────────────────┘
yes no
│ │
▼ ▼
┌──────────────────────┐ ┌────────────────────────┐
│ --sync │ │ default (no flag) │
│ /dca/crawl │ │ trigger_immediate + │
│ one-shot, 25–50 s │ │ poll get_result │
└──────────────────────┘ └────────────────────────┘
│
│ on 202 timeout: response_id is printed —
│ re-run WITHOUT --sync to poll for it
▼
(cleanly fall back to async)
| Mode | Endpoint | When to use |
|---|---|---|
| Default (single URL, async + poll) | /dca/trigger_immediate → poll /dca/get_result | Anything you expect to take more than ~50 s, anything paginated, anything you're not sure about. This is the safe default for one URL. |
--sync (single URL) | /dca/crawl | Single-page extractions you expect to complete in under 50 s. Faster path: one request, no polling. Incompatible with multi-URL — /dca/crawl accepts only one URL. |
Multi-URL (--urls / --input-file) | /dca/trigger (array body) → poll /dca/dataset | 2+ URLs through the same collector. One API call, one snapshot ID, one merged result array. Use the longer --timeout (default 3600s) for big batches. |
# Default — async + poll (recommended for most cases)
bdata scraper run c_mp3tuab31lswoxvpws https://www.amazon.com/dp/B08N5WRWNW
# Pretty-printed, saved to disk
bdata scraper run c_mp3tuab31lswoxvpws https://www.amazon.com/dp/B08N5WRWNW \
--pretty -o product.json
# Sync mode for a fast page
bdata scraper run c_mp3tuab31lswoxvpws https://example.com/p/1 --sync
# Sync with a tighter server timeout
bdata scraper run c_mp3tuab31lswoxvpws https://example.com/p/1 \
--sync --sync-timeout 30
# Multi-URL via comma-separated list — one batch call
bdata scraper run c_mp3tuab31lswoxvpws \
--urls "https://example.com/p/1,https://example.com/p/2,https://example.com/p/3" \
--pretty -o products.json
# Multi-URL via file (one URL per line; # comments and blanks ignored)
bdata scraper run c_mp3tuab31lswoxvpws --input-file urls.txt -o products.json
# Multi-URL via JSON array
echo '["https://example.com/p/1","https://example.com/p/2"]' > urls.json
bdata scraper run c_mp3tuab31lswoxvpws --input-file urls.json
--sync-timeout is bounded to 25–50
Anything outside that range exits with --sync-timeout must be between 25 and 50 seconds. Default is 50. Use values < 50 only when you want to fail fast and fall back to async on slow pages.
--sync timeout recovery
If /dca/crawl server-side times out, it returns 202 with {"error":"crawl_results_timeout","response_id":"r_late_..."}. The CLI surfaces the response_id and exits with a "Re-run without --sync" message. Do exactly that — drop --sync and re-run the same command; the default async path will poll /dca/get_result for the existing response_id. Do not treat sync timeout as a hard failure.
Silent auto-fallback to batch (paginated / large pages)
When a single URL expands to more pages than the realtime job limit allows (paginated listings, infinite scroll, "all reviews" pages, etc.), the realtime endpoints return an error like:
Request generated 501 pages and exceeded realtime job limit of 51 pages
The CLI detects this and automatically falls back to the batch flow (/dca/trigger → poll /dca/dataset). A one-line notice is printed. No flag is needed. Batch jobs use a longer poll interval (10 s) and a longer default timeout (1 hour).
If the user only sees the notice and a long wait, that is expected — large jobs take time. Do not "fix" the fallback by switching APIs or restructuring the scraper; let it run.
--name and --version
--name <name>— tag this run in the Bright Data dashboard. Useful when you're scripting many runs and want to find one later.--version <version>— pin a specific scraper version (commonlydevwhen iterating in the web UI). Omit to use the latest published version.
Action 3 — scraper heal
Fix an existing scraper in place when it ran but returned wrong, empty, or partial data. The scraper's collector_id stays the same — it is improved, not replaced.
bdata scraper heal <collector_id> "<what's wrong>" [--url <verify-url>] \
[--timeout <seconds>] [--max-retries <n>] [--no-retry] \
[--json | --pretty] [-o <path>] [--timing] [-k <api-key>]
You are the detector. The CLI never decides on its own that a scraper is broken — you inspect the run output and decide. A heal is slow and billable, so only heal when the data is actually wrong, not just legitimately empty.
The <prompt> is required and is the most important input. Name exactly what is wrong and what the correct output should be: "The price field returns null — the selector moved into a <span data-testid=...>. Capture price and currency again." Vague prompts ("fix it") produce vague heals. The prompt is capped at 1000 characters.
What happens under the hood
POST /dca/collectors/{collector_id}/refactor_templatewith{prompt, custom_input: []}— triggers the AI self-healing job.GET .../refactor_template/progress(polled) — waits forstatus: "done", same job shape and timing asautomate_template.
Output + the verify loop
heal (without --auto-approve) usually ends at an approval gate rather
than completing immediately. The response carries status: "awaiting_approval"
with two key fields:
preview_result— sample rows the fixed scraper would produce, so you can judge whether the fix is correct before committing it.diff_summary— a summary of what changed in the template.next_step— points atbdata scraper approve <collector_id>to commit (or--rejectto discard).
{
"collector_id": "c_mp3tuab31lswoxvpws",
"status": "awaiting_approval",
"preview_result": [{"price": "29.99", "currency": "USD"}],
"diff_summary": "Updated price selector from .price to span[data-testid='price']",
"next_step": "bdata scraper approve c_mp3tuab31lswoxvpws"
}
Review preview_result, then run bdata scraper approve <collector_id> to
commit the fix — or pass --reject to discard it and re-heal with a sharper
prompt. approve polls to done and hands back a next_step =
bdata scraper run <id> <url> to verify.
Pass --url <verify-url> to heal so the approve and run steps are concrete.
The full self-healing loop is now:
run → inspect → heal → review preview → approve → run → verify
To skip the gate entirely, use heal --auto-approve — it approves automatically
and polls through to done.
Failure is non-destructive
If a heal fails (429 cap exhausted, timeout, terminal failed), the existing scraper is unchanged and still works as it did before. The CLI says so and prints the collector_id. Unlike a failed create, nothing half-built is left behind.
Action 4 — scraper approve
A scraper heal (without --auto-approve) stops at an approval gate:
status: "awaiting_approval", with preview_result (sample rows the fixed
scraper would produce) and a diff_summary. Review the preview, then commit
the fix:
bdata scraper approve <collector_id> [--reject] [--url <verify-url>] \
[--timeout <seconds>] [--json | --pretty] [-o <path>] [-k <api-key>]
- Approves by default (
POST /dca/collectors/{id}/resume_automation_job {"message": true}), then polls todoneand hands back anext_step=bdata scraper run <id> <url>to verify. --rejectsends{"message": false}to discard the proposed fix; re-heal with a sharper prompt to try again.- If a heal needs multiple approvals,
approvemay stop atawaiting_approvalagain — just run it again.
awaiting_approval is not a failure — it means the fix is ready and
waiting for your decision.
Full create-then-run workflow
Capture the collector_id cleanly with jq, then chain into run with the multi-URL batch path:
# 1. Create the scraper, save the AI output, extract the collector_id
bdata scraper create https://example.com/product/1 \
"Extract title, price, currency, image URL, and availability" \
--pretty -o create.json
# 2. Pull the collector_id (or copy from the human-readable summary)
COLLECTOR_ID=$(jq -r '.collector_id // .id' create.json)
echo "Built: $COLLECTOR_ID"
# 3. Run it on every URL in one batch — single API call, merged result array
bdata scraper run "$COLLECTOR_ID" --input-file urls.txt \
--pretty -o out/results.json
Do not wrap bdata scraper run in a for url in $(cat urls.txt); do ... done loop — that's N API calls and N snapshots. Use --input-file urls.txt (or --urls "...") instead; the CLI POSTs all of them to /dca/trigger in a single array body and returns one merged result array.
For more end-to-end recipes (batch input file shapes, error recovery, web-UI handoff), see references/recipes.md.
Common mistakes
-
Inventing command names. The commands are exactly
bdata scraper createandbdata scraper run. There is nobdata generate, nobdata scrape-batch, nobdata data, nobdata build. If you're tempted to use one of those, you're hallucinating — runbdata scraper --helpto verify. -
Re-running
createafter a timeout. Generation creates a fresh collector every time. If polling times out, the half-built collector is still printed in the error output. Resume it in the web UI or wait and re-poll — don't burn another collector. -
Defaulting to
--syncfor everything. Sync caps at 50 s server-side. Any paginated page or heavy SPA will time out. Default async is the right choice unless you specifically know the page is small. -
Skipping Scraper Studio for known platforms. If the target is Amazon, LinkedIn, TikTok, Instagram, YouTube, Reddit, etc., the
data-feedsskill exposes pre-built scrapers that are faster, cheaper, and more reliable. Only build a custom scraper when no pre-built one exists for the site, or when the user explicitly wants a custom output shape. -
Treating sync timeout as failure. A
--sync202 timeout returns a validresponse_id— the job is still running on the backend. Re-run the same command without--syncto pick it up. -
Throwing away
collector_id/response_idon error. The CLI prints them in every failure path on purpose. Both are recoverable via the API and the web UI. Always surface them to the user. -
Trying to disable the batch auto-fallback. It has no flag. The fallback is the correct behavior when a URL expands past the realtime page limit. Let it run.
-
Hand-rolling a
for url in $(cat urls.txt); do bdata scraper run ...loop. That's N API calls, N snapshot IDs, and N poll loops for what the API natively treats as one batch. Use--input-file urls.txtor--urls "u1,u2,..."— the CLI posts the whole array to/dca/triggerin a single request and returns one merged result array. This mirrors the canonicaltriggerWithUrls/trigger_with_urlshelpers from the Scraper Studio reference SDKs. -
Vague descriptions in
create. A description like "scrape the page" produces a generic scraper. Name every field, name conditions ("if there's a sale price, capture both"), name disambiguators ("the price near the title, not in the recommendations sidebar"). See references/prompts.md. -
Re-running
createto fix a broken scraper. That builds a new collector and orphans the old one. To fix an existing scraper, usebdata scraper heal <collector_id> "<what's wrong>"— it mutates the scraper in place so your savedcollector_idkeeps working and improves. -
Treating
awaiting_approvalas a failure. It is the normal end state of a heal — the fix is computed and waiting for your decision. Reviewpreview_result, thenbdata scraper approve <id>(or--reject). Useheal --auto-approveto skip the gate.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
bdata: command not found | CLI not installed | See brightdata-cli for install. |
Invalid or expired API key | Not logged in | bdata login (or bdata login --device for SSH). |
create returns no id | API call failed before template was created | Check --timing output for the failing request; verify network and account status. |
Timeout after 600 seconds waiting for AI generation | Page is complex; default poll exceeded | The collector_id is still printed. Open it in the web UI; or re-run with --timeout 1200. |
status: "failed" from progress poll | AI Flow couldn't build the template | Improve the description — be more specific about fields and selectors. Try again with a cleaner URL (e.g. a canonical product page, not a search result). |
--sync 202 with crawl_results_timeout | Page took > sync server cap | Re-run without --sync to poll /dca/get_result for the printed response_id. |
--sync-timeout must be between 25 and 50 seconds | Out-of-range value | Use a value in [25, 50]. |
Request generated N pages and exceeded realtime job limit | URL expanded too far | This is handled automatically — wait for the batch fallback notice and let it poll. |
No data returned, just [] or {} | Selectors didn't match | The scraper template ran but extracted nothing. Open https://brightdata.com/cp/scrapers/{collector_id} to inspect/edit; or rebuild with a tighter description. |
Reference files
- references/prompts.md — How to write a description for
scraper createthat the AI Flow can act on. Examples of strong vs. weak descriptions, field-listing patterns, and conditional rules. - references/recipes.md — End-to-end recipes: capture
collector_idfrom create, batch run a list of URLs, handle sync→async fallback, recover from a failed create, list scrapers from the dashboard. - references/api-flow.md — Exact REST endpoints, payloads, and status sentinels the CLI uses (
/dca/collector,/dca/collectors/{id}/automate_template,/dca/trigger_immediate,/dca/get_result,/dca/crawl,/dca/trigger,/dca/dataset). Read this when debugging unexpected CLI output or when the user wants to hit the API directly.
Frequently asked questions
What to verify before installation and use
What does the scraper-studio source document cover?
Build a scraper from natural language, then run it. Two commands live in this skill:
How do I install scraper-studio?
The source record exposes this install command: npx skills add https://github.com/brightdata/skills --skill "skills/scraper-studio". Inspect the command and pinned source before running it.
Which permission-related actions were detected?
Static rules flagged network, exec-script in the source; the page lists the matching lines and excerpts.
Alternatives
Compare before choosing
coreyhaines31/marketingskills
ab-testing
When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program
garrytan/gbrain
bulk-ingestion
End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.
alirezarezvani/claude-skills
app-store-optimization
App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist
dotnet/skills
migrate-vstest-to-mtp
Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing