Enriching Tables with @brightdata/enrich
@brightdata/enrich (CLI command: enrich) turns a flat CSV into an enriched one. Each row is researched on the live web through Bright Data's infrastructure and an LLM agent swarm, and new columns are appended — company size, funding, tech stack, work emails, LinkedIn URLs, or anything you can describe in plain English. Every run is resumable, streams progress, and reports cost.
This skill takes a user from zero (no account) to a finished enriched CSV, and assumes nothing about prior Bright Data experience.
When you reach for this
Any time a user has a table and wants more columns sourced from the web: a list of company domains that needs employee counts and funding stages, a Salesforce export missing industries, a contact list that needs verified work emails, or a vague "can you find X for each of these." If they hand you a CSV and describe data they don't yet have, this is the tool.
The shape of the work
The flow is always the same four beats. Do them in order; don't skip the dry run.
Enrichment Progress:
- [ ] 1. Confirm prerequisites (Node ≥20, four credentials resolve)
- [ ] 2. Inspect the input CSV (identifier column, what's already filled)
- [ ] 3. Dry-run to lock config + estimate cost, then get the user's OK
- [ ] 4. Run the real enrichment, report output path + cost
Copy that checklist into your working notes and tick items off — it keeps you from spending the user's money before they've approved the plan.
Step 1 — Prerequisites
The CLI needs Node.js ≥ 20 and four credentials. If the user has never set this up, walk them through references/onboarding.md — it covers creating a Bright Data account, provisioning the two required zones, and getting an LLM key, with where-to-click pointers. Don't paraphrase those steps from memory; read that file and follow it.
The four credentials:
| Variable | What it is | Where it comes from |
|---|---|---|
BRIGHT_DATA_API_KEY |
Bright Data account API token | Bright Data dashboard → Settings → API keys |
BRIGHT_DATA_SERP_ZONE |
name of a SERP API zone | Bright Data dashboard → Proxies & Scraping → your SERP zone |
BRIGHT_DATA_UNLOCKER_ZONE |
name of a Web Unlocker zone | Bright Data dashboard → Proxies & Scraping → your Unlocker zone |
OPENROUTER_API_KEY |
LLM provider key | openrouter.ai/keys (or use OPENAI_API_KEY / ANTHROPIC_API_KEY instead) |
There are two ways to supply them. Environment variables (or a .env file in the working directory) always take precedence, which is what you want for scripted/non-interactive runs:
export BRIGHT_DATA_API_KEY=...
export BRIGHT_DATA_SERP_ZONE=...
export BRIGHT_DATA_UNLOCKER_ZONE=...
export OPENROUTER_API_KEY=...
Or the user can store them once with the interactive setup (saved to a 0600 config file in their OS config dir):
npx @brightdata/enrich login
login validates each credential against the live API before saving — a wrong key fails fast here rather than mid-run. To wipe stored credentials, enrich logout.
Verify before doing anything else. Run the bundled preflight, which checks the Node version and confirms all four credentials resolve (via a dry run, so it spends nothing):
bash scripts/preflight.sh path/to/input.csv
If it reports a missing credential, send the user to references/onboarding.md for the one that's missing rather than guessing.
Step 2 — Inspect the CSV
Look at the file before configuring the run. You need to know two things:
- The identifier column — the column the agents use to find each entity on the web. A company domain or website is ideal; a company name works; for people, an email plus first/last name columns. The CLI auto-detects this, but eyeball it so you can override with
--columnif the guess would be wrong (e.g. a file with bothdomainandpersonal_domain). - What's already filled — there's no point (and no spend) re-fetching columns the file already has. Enrich the gaps.
A quick head of the file is enough. For the example file in this repo:
head -5 examples/companies.csv
# company,domain,hq_country
# Stripe,stripe.com,United States
# ...
Here domain is the natural identifier.
Step 3 — Dry run, then get approval
Never kick off a paid run without a dry run first. --dry-run resolves the full config — identifier column, the exact fields it will add, output path, and a cost estimate — and exits without touching any API.
npx @brightdata/enrich examples/companies.csv \
--describe "employee count, total funding raised, primary tech stack" \
--dry-run
You'll get back something like the columns it will add, the detected identifier, and Estimated: ~$X.XX (Bright Data) + ~$Y.YY (LLM). Show the user this estimate and the field list, and wait for an explicit go-ahead before the real run — especially for files over a few dozen rows. Cost scales with rows × fields; a 5,000-row file is real money.
Decide how to specify fields (see the full catalog in references/fields.md):
--describe "<plain english>"— natural language. The CLI first tries to map your words onto preset fields; if it can't, an LLM designs custom fields from the description. Use this for anything bespoke ("their Series B lead investor", "whether they use Kubernetes").--fields a,b,c— exact preset field names, comma-separated. Faster and deterministic. Use when you know the names.--describeand--fieldsare mutually exclusive.
Step 4 — Run it
Once approved, drop --dry-run:
npx @brightdata/enrich examples/companies.csv \
--describe "employee count, total funding raised, primary tech stack"
The enriched file is written to <input>.enriched.csv by default (override with -o). Progress streams to stderr with a live cost meter and ETA; the final summary prints rows done/skipped/errored, total cost split by LLM vs Bright Data, and the output path. Report that summary and the output path back to the user.
The options that matter most
| Option | Use it when | Default |
|---|---|---|
--describe "<text>" |
You want fields in plain English (incl. custom) | — |
--fields a,b,c |
You know the exact preset names | — |
--column <name> |
Auto-detection picks the wrong identifier | auto |
--first-name <col> / --last-name <col> |
Enriching people — lets agents disambiguate same-company contacts | — |
-o, --output <path> |
You want a specific output filename | <input>.enriched.csv |
--concurrency <n> |
Tune rows-in-flight (lower if rate-limited, higher to go faster) | 30 |
--dry-run |
Always, before a real run | off |
--json |
You need machine-readable NDJSON instead of a CSV (pipe to jq) |
off |
--no-resume |
You want to overwrite rather than continue a prior run | resume on |
-q / -v |
Quiet (summary only) / verbose (every agent step) | normal |
Resuming is automatic
If a run is interrupted (Ctrl-C, crash, or you just stop it), re-run the exact same command and it picks up where it left off — it checks the existing output's header and skips rows already written. This only works if the field set matches, so keep --describe/--fields identical. To start fresh instead, pass --no-resume or delete the output file. This makes large files safe to run in chunks.
Enriching people, not just companies
For contact-level data (work email, LinkedIn, title, seniority), point the CLI at the name columns so it can tell two people at the same company apart:
npx @brightdata/enrich contacts.csv \
--first-name first_name --last-name last_name --column work_email \
--fields person_email,person_linkedin_url,person_title,person_seniority
Cost — set expectations honestly
Bright Data bills roughly $0.0015 per tool call; a typical row touches 5–15 calls depending on how much you ask for. LLM cost is separate and paid to your provider. As a rule of thumb a 5-field CRM fill is well under a cent of Bright Data spend per row; deep person+company enrichment runs a few cents. The --dry-run estimate is your source of truth — always surface it. Compared to commercial enrichment vendors at $0.50–$2.00/row, this is one to two orders of magnitude cheaper, but it is not free, so confirm before large runs.
When something goes wrong
For credential errors, header-mismatch on resume, empty-field results, rate limits, and other failure modes, see references/troubleshooting.md — match the error message to its row and follow the fix. Don't retry a failing command unchanged; diagnose first.
Field catalog
The 36 built-in preset fields and 6 quick-start bundles (Startup Prospecting, Enterprise Research, Quick CRM Fill, Competitor Analysis, Person Lookup, Full Company + Person) are listed with descriptions in references/fields.md. Read it when the user wants specific named fields or you need to translate a request into the right --fields list.
Installing / publishing this skill
This skill lives at skills/enriching-tables/SKILL.md in the brightdata/open-enrich repo — the layout skills.sh indexes automatically — so users install it with npx skills add brightdata/open-enrich/skills/enriching-tables. Listing details and the README badge are documented in the repo's main README ("Or drive it from your coding agent"); publishing is a one-time author task, not part of running an enrichment.