# BioSpace Scraper - Biotech & Pharma Jobs (`santamaria-automations/biospace-scraper`) Actor

Extract job listings from BioSpace, the leading US biotech and pharma job board. Returns title, company, location, salary, discipline, career level, therapy area, full description, apply URL and posting dates. From $3 per 1,000 jobs, about $8 with full job details.

- **URL**: https://apify.com/santamaria-automations/biospace-scraper.md
- **Developed by:** [NanoScrape](https://apify.com/santamaria-automations) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 3 total users, 2 monthly users, 93.3% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 actor starts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## BioSpace Scraper - US Biotech, Pharma & Medical Device Jobs

Pull job listings from [BioSpace](https://www.biospace.com/jobs), a life-science career board (with positions from pharma, biotech startups and CROs). Every row returns salary, discipline, hotbed cluster, required education, the full description as text, HTML and Markdown, the employer's apply URL and exact posting timestamps. No API key needed.

### Sample output

```json
{
  "id": "3081205",
  "title": "Program Lead II, Clinical Program Development",
  "job_url": "https://jobs.biospace.com/job/3081205/program-lead-ii-clinical-program-development",
  "company_name": "AbbVie",
  "company_logo_url": "https://assets.biospace.com/public/logos/397714",
  "company_profile_url": "https://www.biospace.com/employer/397714/abbvie",
  "company_type": "pharma",
  "industry": "Pharmaceutical",
  "location": "Irvine, CA",
  "country": "US",
  "city": "Irvine",
  "region": "CA",
  "employment_type": "Full-time",
  "remote_option": "onsite",
  "salary_min": 160500,
  "salary_max": 305000,
  "salary_currency": "USD",
  "salary_period": "annual",
  "salary_text": "USD 160,500 - 305,000 per year",
  "description_snippet": "Company Description\n\nAbout AbbVie\n\nAbbVie's mission is to discover and deliver innovative medicines...",
  "description_full": "Company Description\n\nAbout AbbVie\n\nAbbVie's mission is to discover and deliver innovative medicines and solutions...",
  "description_html": "<p>Company Description</p><p><strong>About AbbVie</strong></p>...",
  "description_md": "Company Description\n\n**About AbbVie**\n\nAbbVie's mission is...",
  "posted_at_datetime": "2026-09-29T13:24:52.093Z",
  "posted_at_text": "Sep 29, 2026",
  "expires_at": "2026-10-29",
  "apply_url": "https://careers.abbvie.com/en/job/program-lead-ii-clinical-program-development-in-irvine-ca-jid-33130",
  "direct_apply": false,
  "discipline": "Clinical, Clinical Research",
  "career_level": "senior",
  "therapy_area": "oncology",
  "required_education": "Bachelors Degree",
  "hotbed": "Biotech Beach",
  "search_query": "clinical research",
  "source_platform": "biospace.com"
}
```

### Pricing

Pay per event. You only pay for results.

| Event | Price |
|-------|-------|
| Actor start (`job-start`) | $0.001 per run |
| Search result (`job-serp-result`) | $0.003 per job |
| Detail result (`job-detail-result`) | $0.005 per job, charged only when the full description was actually parsed |
| Company detail (`company-detail-result`) | $0.005 per unique employer when includeCompanyDetails is on, charged only when the employer page resolved |

That is about $3 per 1,000 jobs with Include Full Job Details off, and about $8 per 1,000 jobs with it on (the default). A detail page that fails to load or has no description is not charged the detail event. Include Company Details is off by default; when on, each employer is fetched and charged once per run, however many of its jobs are returned.

New to Apify? Every account gets a $5 free monthly platform credit, enough to test this actor properly before you commit.

### Input

| Field | Type | Required | Description | Example |
|-------|------|----------|-------------|---------|
| `searchQueries` | array | No | Keywords, one search each. BioSpace matches them against title, employer and description text. Empty lists the newest jobs. | `["clinical research associate", "medical writer"]` |
| `searchUrls` | array | No | Pre-built BioSpace search URLs. Filters and sort are read from the URL. | `["https://jobs.biospace.com/search-jobs?q=clinical&sort=Date"]` |
| `directUrls` | array | No | BioSpace job page URLs (`/job/<id>/...`). Fetched directly with the full description. | `["https://jobs.biospace.com/job/3080938/"]` |
| `location` | string | No | US city or state. Resolved with BioSpace's own location search, then combined with `radiusKm`. | `Boston, MA` |
| `radiusKm` | integer | No | Radius around `location`. Default 80 km (about 50 miles). | `40` |
| `sortBy` | string | No | `newest` (default) or `relevance`. Both are applied by BioSpace and give different orderings. | `newest` |
| `postedWithinDays` | integer | No | Only jobs posted in the last N days. With `newest` sorting the run stops at the first older job. | `7` |
| `maxResults` | integer | No | Total cap across all queries. Default 20. | `200` |
| `maxResultsPerQuery` | integer | No | Cap per keyword. Default 200. | `100` |
| `includeJobDetails` | boolean | No | Fetch each job page for the full description, apply URL, employer address and phone. Default true. | `true` |
| `includeCompanyDetails` | boolean | No | Fetch each unique employer's BioSpace page once and add company website, careers site, About text, headquarters, phone and social links to every job of that employer. Default false. $0.005 per unique employer. | `false` |
| `discipline` | string | No | `clinical`, `regulatory`, `quality`, `engineering`, `science-r-and-d`, `manufacturing-and-production`, `marketing`, `sales-and-service`, `information-technology`, `administration`. | `clinical` |
| `requiredEducation` | string | No | `high-school-or-equivalent`, `associate-degree`, `bachelors-degree`, `masters-degree-mba`, `doctorate-phd-md`, `other`. | `doctorate-phd-md` |
| `positionType` | string | No | `full-time`, `part-time`, `contract`, `consultant`. | `contract` |
| `remoteOnly` | boolean | No | Only jobs marked remote. | `false` |
| `titleFilter` | string | No | Comma-separated title terms (OR-match, case-insensitive). Non-matching rows are dropped before any detail fetch, so you do not pay for them. | `"scientist, biologist"` |
| `maxConcurrency` | integer | No | Concurrent detail-page requests (1 to 20). Default 5. | `5` |

Copy-paste example:

```json
{
  "searchQueries": ["clinical research", "biotech sales"],
  "location": "Boston, MA",
  "radiusKm": 80,
  "sortBy": "newest",
  "postedWithinDays": 14,
  "maxResultsPerQuery": 100,
  "maxResults": 200,
  "includeJobDetails": true
}
```

### What you get

| Field | Description |
|-------|-------------|
| `id` | BioSpace job ID (stable dedup key) |
| `title` | Job title |
| `job_url` | Job page URL on jobs.biospace.com |
| `company_name` | Employer name |
| `company_logo_url`, `company_profile_url` | Employer logo and BioSpace employer page |
| `company_address`, `company_phone` | Employer contact address and phone (detail mode) |
| `company_website`, `company_careers_url`, `company_about`, `company_headquarters`, `company_social_urls` | Employer's own website, careers site, About text, headquarters address and social profile URLs from its BioSpace page (only with Include Company Details; `company_phone` is also taken from that page). When BioSpace links a careers site as the website, the site root is derived into `company_website` and the careers link goes to `company_careers_url` |
| `company_type`, `industry` | Employer type (pharma, biotech, medical-device, diagnostics and so on) and BioSpace industry |
| `location`, `city`, `region`, `country` | Location as shown by BioSpace, split into parts |
| `employment_type` | Full-time, Part-time, Contract or Consultant |
| `remote_option` | onsite, hybrid or remote |
| `salary_min`, `salary_max`, `salary_currency`, `salary_period`, `salary_text` | Salary when disclosed (structured field, or parsed from the pay range in the description), otherwise null |
| `description_snippet` | First 300 characters of the description |
| `description_full`, `description_html`, `description_md` | Full description as plain text, HTML and Markdown (detail mode) |
| `posted_at_datetime` | ISO 8601 UTC posting timestamp |
| `posted_at_text` | Posted date as printed by BioSpace |
| `expires_at` | ISO date the listing expires |
| `apply_url`, `external_apply_url`, `direct_apply` | Where to apply (the job page when the application happens on BioSpace, the employer link otherwise), the employer link, and whether it happens on BioSpace (detail mode) |
| `discipline` | BioSpace discipline tags, comma separated |
| `career_level` | entry, mid, senior or executive, inferred from the title |
| `therapy_area` | Therapy area keyword found in the description (detail mode) |
| `required_education` | Required education level |
| `hotbed` | BioSpace biotech cluster tag (Genetown, Biotech Beach, BioForest and so on) |
| `security_clearance` | `required` or `preferred` when the description mentions a clearance, otherwise null |
| `search_query` | The keyword and location that produced the row |
| `source_platform`, `scraped_at` | Always `biospace.com`, and the scrape timestamp |

With Include Full Job Details off you get the search-result fields and the short `description_snippet` only.

#### Deprecation notes

The following field names are deprecated and will be removed after **2027-09-29**:

- `company`, use `company_name`
- `source_url`, use `job_url`
- `posted_at`, use `posted_at_datetime` (the old field holds the date only)

Both the deprecated and canonical fields are emitted in every row during the window. Please migrate downstream consumers before the removal date.

### Use with AI Agents (MCP)

Connect this actor to any MCP-compatible AI client: Claude Desktop, Claude.ai, Cursor, VS Code, LangChain, LlamaIndex, or custom agents.

Configure the MCP server with BioSpace Scraper preconfigured at `mcp.apify.com?tools=santamaria-automations/biospace-scraper`.

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=santamaria-automations/biospace-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}
```

For per-tool schemas and copy-paste snippets for MCP clients, see the [MCP tab](https://console.apify.com/actors/B9krPZ4ilawIHsbeu/info/api/mcp?build=latest).

See the [auto-generated API tab](https://console.apify.com/actors/B9krPZ4ilawIHsbeu/info/api) for language-specific examples (cURL, JS, Python, .NET, Ruby, PHP).

**Example prompt once connected:**

> "Use `biospace-scraper` to find senior clinical research associate roles posted in the last 7 days within 80 km of Boston. Return company, salary and apply URL as a table."

### Why this actor

- Life-science-native fields that generalist boards do not carry: `discipline`, `hotbed`, `required_education`, `therapy_area` and `industry`.
- Real server-side filtering and sorting: keyword, location with radius, discipline, education, position type, remote and newest or relevance ordering are all applied by BioSpace, so you only pay for rows you asked for.
- Recent-only runs are cheap: with `postedWithinDays` and `newest` sorting the scrape stops at the first older job.
- Full description as text, HTML and Markdown, plus the employer's own apply URL.
- Failed detail fetches are not charged.

### Common use cases

- Build a Genetown or Biotech Beach prospect list for a life-science recruiter (filter `hotbed`).
- Track new senior regulatory-affairs openings across pharma weekly with `postedWithinDays: 7`.
- Refresh a clinical research associate pipeline for a CRO's talent team every Monday.
- Monitor hiring signals at specific employers by running one keyword per company name.

### Notes and limits

- BioSpace lists around 3,900 jobs at any time. BioSpace returns 20 jobs per search page. With details on, expect roughly 1.5 seconds per job at the default concurrency (about 2 minutes for 90 jobs); raise `maxConcurrency` for faster large runs, or turn details off for search-only speed.
- Keywords match title, employer and description text, so a broad keyword can return loosely related roles. Use `titleFilter` to keep only rows whose title matches.
- The location index is US-centric. Some jobs outside the US are listed by BioSpace and appear in unfiltered searches.
- BioSpace sometimes tags Canadian jobs as US (or US jobs as another country). The actor corrects `country` when the location ends in a Canadian province or in "United States".
- Include Company Details reads the employer page BioSpace maintains, so fields such as phone or social links are only present when the employer filled them in (fill rates vary by employer). Employer pages cannot be listed as a job source: BioSpace has no employer filter on its job search.
- Many listings do not disclose salary. That is the employer's choice, not a scraping issue.
- `therapy_area` and `career_level` are inferred from the description and title. Treat them as hints.

### Related actors

- [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor): extract jobs from any company career page.
- [Website Email Scraper](https://apify.com/santamaria-automations/website-email-scraper): feed it `company_website` to collect employer emails.
- [Website Contact Extractor](https://apify.com/santamaria-automations/website-contact-extractor): feed it `company_website` to extract contact names, phones and socials.
- [Indeed HTTP Scraper](https://apify.com/santamaria-automations/indeed-http-scraper): general job listings from Indeed.
- [Glassdoor Scraper](https://apify.com/santamaria-automations/glassdoor-scraper): jobs, salaries and company ratings.
- [HealtheCareers Scraper](https://apify.com/santamaria-automations/healthecareers-scraper): US healthcare and clinical roles.
- [USAJobs Federal Scraper](https://apify.com/santamaria-automations/usajobs-federal-scraper): US federal science, health and research roles.

### Support

- **Questions or issues?** Email contact@nanoscrape.com, we typically reply within 6 hours. You can also open a ticket in the [Issues tab](https://console.apify.com/actors/B9krPZ4ilawIHsbeu/info/issues) on the actor page.
- **Feature request for this actor?** Open a ticket in the [Issues tab](https://console.apify.com/actors/B9krPZ4ilawIHsbeu/info/issues) or email contact@nanoscrape.com with the field you need and, if possible, a URL that shows the data live.
- **Need a scraper for a job board we don't cover yet?** Email contact@nanoscrape.com with the target site and your rough usage volume. We ship one-off boards regularly.

# Actor input Schema

## `searchQueries` (type: `array`):

Biotech job titles or skills (e.g. 'clinical research associate', 'medical writer'). Each keyword runs as a separate search and is matched on BioSpace against job title, employer and description text. Leave empty to list the newest jobs. A job matched by several keywords appears once, under the first keyword.

## `searchUrls` (type: `array`):

Pre-built BioSpace search URLs, for example https://jobs.biospace.com/search-jobs?q=clinical\&discipline=clinical\&sort=Date. Keyword, discipline, education, position type, remote, location and sort are read from each URL and applied as is. Pagination, maxResultsPerQuery and the other limits still apply.

## `directUrls` (type: `array`):

BioSpace job page URLs (https://jobs.biospace.com/job/<id>/...). Each page is fetched directly, no search is run, and the row includes the full description. Billed with the same events as search results.

## `location` (type: `string`):

US city or state, e.g. 'Boston', 'San Diego', 'Cambridge, MA'. Resolved with BioSpace's own location search and combined with the radius below. Known biotech hubs work without a state. BioSpace's location index is US-centric.

## `radiusKm` (type: `integer`):

Search radius around the location. Ignored when no location is set. Default 80 km (about 50 miles).

## `sortBy` (type: `string`):

'newest' returns the most recently posted jobs first (BioSpace 'Date' sort). 'relevance' uses BioSpace's keyword relevance ranking. Both are applied by BioSpace itself.

## `postedWithinDays` (type: `integer`):

Only return jobs posted in the last N days. Leave empty for no limit. With newest-first sorting the scrape stops at the first older job, so recent-only runs are fast and cheap.

## `maxResults` (type: `integer`):

Total cap across all queries.

## `maxResultsPerQuery` (type: `integer`):

Maximum results per search keyword.

## `includeJobDetails` (type: `boolean`):

When ON, each job page is fetched for the full description (text, HTML, Markdown), apply URL, employer address and phone, discipline tags and hotbed. Adds one request per job and one 'detail' charge per job whose description was parsed. When OFF you get the search-result fields and a short description snippet only.

## `includeCompanyDetails` (type: `boolean`):

Fetch each employer's BioSpace page once per run and add the company website, careers site, About text, headquarters address, phone and social links to every job of that employer. Every unique employer costs an extra $0.005 (company-detail-result), no matter how many of its jobs are returned. Off by default.

## `discipline` (type: `string`):

Filter by BioSpace discipline.

## `requiredEducation` (type: `string`):

Filter by the education level the job requires.

## `positionType` (type: `string`):

Filter by employment type.

## `remoteOnly` (type: `boolean`):

Only return jobs marked remote.

## `titleFilter` (type: `string`):

Comma-separated list of terms to match against job titles (case-insensitive OR-match). Only jobs whose title contains one of the terms are emitted. Non-matching rows are dropped before the detail fetch, so you don't pay for detail on filtered-out jobs. Leave empty to disable.

## `maxConcurrency` (type: `integer`):

Maximum number of concurrent detail page requests (only used when Include Full Job Details is on).

## Actor input object example

```json
{
  "searchQueries": [
    "clinical research associate"
  ],
  "location": "Boston, MA",
  "radiusKm": 80,
  "sortBy": "newest",
  "maxResults": 20,
  "maxResultsPerQuery": 200,
  "includeJobDetails": true,
  "includeCompanyDetails": false,
  "discipline": "",
  "requiredEducation": "",
  "positionType": "",
  "remoteOnly": false,
  "titleFilter": "",
  "maxConcurrency": 5
}
```

# Actor output Schema

## `jobListings` (type: `string`):

Dataset with one row per BioSpace job. Canonical fields: id, title, job_url, company_name, location, salary_min/max, description_full/snippet/html/md, posted_at_datetime, posted_at_text, apply_url. Deprecated aliases company, source_url and posted_at are still emitted until 2027-09-29. With includeCompanyDetails on, rows also carry company_website, company_careers_url, company_about, company_headquarters, company_phone and company_social_urls.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchQueries": [
        "clinical research associate"
    ],
    "radiusKm": 80,
    "sortBy": "newest",
    "maxResults": 20,
    "maxResultsPerQuery": 200,
    "includeJobDetails": true,
    "maxConcurrency": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/biospace-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchQueries": ["clinical research associate"],
    "radiusKm": 80,
    "sortBy": "newest",
    "maxResults": 20,
    "maxResultsPerQuery": 200,
    "includeJobDetails": True,
    "maxConcurrency": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/biospace-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchQueries": [
    "clinical research associate"
  ],
  "radiusKm": 80,
  "sortBy": "newest",
  "maxResults": 20,
  "maxResultsPerQuery": 200,
  "includeJobDetails": true,
  "maxConcurrency": 5
}' |
apify call santamaria-automations/biospace-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,santamaria-automations/biospace-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/B9krPZ4ilawIHsbeu/builds/envyRHAfevLT17nXH/openapi.json
