Skip to main content
Setup prompt
This sample is one Python file, enrich_csv.py, that turns a CSV of LinkedIn profile URLs into a CSV of names, titles, companies and, if you ask for them, work emails. It uses two Forager endpoints: the person lookup (1 credit per row) and the bulk work email lookup (5 credits per address found, one batch for the whole file). It prints the credit estimate and asks before it spends anything, and a second run skips rows that are already in the output file.

What you need

  • Python 3.9 or newer and pip install requests.
  • FORAGER_API_KEY and FORAGER_ACCOUNT_ID in the environment, from the Web App.
  • A CSV with a linkedin_url column. The fictional sample below is what the walkthrough uses.
input.csv

The script

1

Parse the URLs and estimate the cost

The person lookup takes the LinkedIn public identifier, the slug after /in/. Everything else in the URL (scheme, www, trailing slash, query string) is dropped. Rows that already have an id in the output file are skipped, so a crashed run can be resumed.
enrich_csv.py (part 1 of 3)
2

Call the API with retries

One helper sends every request. A 403 stops the run (the key or Account ID is wrong, retrying cannot help), a 429 waits and retries, and anything else is recorded in the row’s error column so one bad row does not stop the file. See errors and rate limits.
enrich_csv.py (part 2 of 3)
3

Run the file end to end

The main function prints how many rows are new and what they cost, waits for a y unless you pass --yes, enriches row by row (appending to the output as it goes), and runs the work email batch last so a crash mid-file never loses the person data already fetched.
enrich_csv.py (part 3 of 3)
4

Run it

Output (illustrative)
output.csv (illustrative)

Edge cases the script handles

  • A URL that is not a profile URL (a company page, an empty cell) is counted and skipped, never sent.
  • A person the lookup cannot resolve gets the status code and body in error and the run continues.
  • Duplicate URLs in the input are collapsed by the bulk endpoint, which charges one lookup for identical rows.
  • Not enough credits for the batch: the bulk endpoint rejects the whole batch and charges nothing, so the person data already written is safe. Buy credits, then re-run with --work-emails; the person lookups are skipped and only the batch runs again.
  • Resuming: rows with an id in the output file are skipped. Delete a row from the output to redo it.

Adapt it

  • Need phone numbers instead? Replace bulk_work_emails with one phone number lookup per row (person_id from the person lookup, 15 credits per lookup). There is no bulk phone endpoint.
  • Thousands of rows? Run the batch in chunks and send a webhook_url instead of polling. See Bulk work email lookup.
  • Whole datasets are cheaper as a data feed than as API calls.

Python quickstart

The client this script is built on, step by step.

Contact enrichment guide

Every field in the person record.

Credit pricing

What each call costs.

Report bad data

Send back invalid addresses with the feedback endpoints.
Last modified on November 1, 2026