# Milkround Scraper (`santamaria-automations/milkround-uk-scraper`) Actor

Extract UK graduate jobs, schemes, internships and placements from Milkround. Returns title, employer, salary, employment type, workplace type, sector, degree class, closing date, location, full description and employer size. Pay per event: $0.003 per job, $0.005 with detail pages.

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

## Pricing

from $3.00 / 1,000 serp results

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

## Milkround UK Graduate Jobs Scraper

Scrape UK graduate jobs, schemes, internships, placements and apprenticeships from [Milkround](https://www.milkround.com), the UK's dedicated graduate recruitment site. Give it keywords, a location or a Milkround search URL and get every listing back as structured JSON: employer, salary, scheme type, sector, degree class, start date, closing date, full description and location detail.

### What it does

Pulls live UK graduate vacancies from Milkround search results, deduplicates them and pushes them to your Apify dataset. Pagination is automatic up to your result caps. With `includeJobDetails` on, it also opens each job page for the full description, structured location, closing date, category and employer size, and extracts emails, phones and links written in the ad text. With `includeCompanyDetails` on, it adds each unique employer's profile (about text, address, website when published, open roles).

Running the actor with an empty input returns the newest Milkround graduate jobs (5 by default).

### What you get

| Field | Type | Notes |
|---|---|---|
| `id`, `title`, `job_url`, `apply_url` | string | `apply_url` always equals `job_url`: Milkround has no separate apply link |
| `company_name` (also `employer_name`) | string | Employer as shown on the listing |
| `location`, `city`, `region`, `postal_code`, `latitude`, `longitude`, `country` | string / number | Region, postcode and coordinates need detail mode |
| `salary_range` (`min`, `max`, `currency`, `period`), `salary_min`, `salary_max`, `salary_currency`, `salary_period`, `salary_text` | object / number / string | Null when the ad says "Competitive" or shows a bare number with no currency |
| `employment_type` | string | graduate-scheme, graduate-job, internship, placement-year, apprenticeship |
| `workplace_type` | string | on-site, hybrid, remote |
| `contract_type` | string | e.g. "Permanent Contract" (detail mode) |
| `sector`, `category` | string | `category` is the platform's own industry label (detail mode) |
| `degree_required`, `start_date_type`, `duration_months`, `scheme_size` | string / number | Derived from title and ad copy |
| `description`, `description_full`, `description_html`, `description_md` | string | Full text in detail mode; SERP snippet otherwise |
| `posted_at`, `posted_at_datetime`, `posted_at_text` | string | ISO date and the site's relative text |
| `closing_date`, `expires_at` | string | See the note on closing dates below |
| `is_easy_apply` | boolean | Direct apply on the platform (detail mode) |
| `badges` | array | Search page labels such as NEW or FEATURED |
| `contact_emails`, `contact_phones`, `contact_urls`, `contact_email`, `contact_phone` | array / string | Found in the ad text; Milkround has no contact-person field |
| `company_profile_url`, `company_logo_url`, `company_industry`, `company_size`, `company_founded_year` | string / number | Detail mode, when the employer has a profile |
| `company_about`, `company_phone`, `company_email`, `company_website`, `company_social_urls`, `company_address_street`, `company_address_city`, `company_address_postcode`, `company_address_country`, `company_active_jobs_count`, `company_active_jobs` | various | Only with `includeCompanyDetails`; website, phone and email only when the employer publishes them |
| `search_query`, `source_platform`, `scraped_at` | string | Which keyword produced the row, plus run metadata |

`application_url` is kept for backward compatibility and is always null.

### Sample output

```json
{
  "_type": "job",
  "id": "108051092",
  "title": "Lead Database Developer",
  "company_name": "Saga Group",
  "location": "Folkestone, South East",
  "city": "Folkestone",
  "region": "South East",
  "postal_code": "CT20 3SE",
  "country": "GB",
  "salary_text": "£55,000 to £60,000 depending on experience",
  "salary_min": 55000,
  "salary_max": 60000,
  "salary_currency": "GBP",
  "salary_period": "year",
  "employment_type": "graduate-job",
  "workplace_type": "hybrid",
  "contract_type": "Permanent Contract",
  "category": "IT, IT-Database",
  "job_url": "https://www.totaljobs.com/job/lead-database-developer/saga-group-job108051092",
  "apply_url": "https://www.totaljobs.com/job/lead-database-developer/saga-group-job108051092",
  "is_easy_apply": true,
  "posted_at": "2026-09-28",
  "expires_at": "2026-11-09",
  "company_profile_url": "https://www.totaljobs.com/jobs/saga-group?cmpId=1439148&cmp=1",
  "company_size": "1000+",
  "source_platform": "milkround.com"
}
```

### Pricing

Pay-per-event, so you only pay for what you use.

| Event | Rate |
|---|---:|
| Actor start | $0.001 per run |
| Job from search page | $0.003 per job |
| Job with detail-page enrichment | $0.005 per job |
| Company profile (unique employer, when `includeCompanyDetails=true`) | $0.005 per employer |

Every Apify account gets a $5 free monthly platform credit, enough for around 1,000 enriched graduate jobs on this actor.

### Input

```json
{
  "searchQueries": ["software engineer", "finance graduate"],
  "location": "London",
  "sortBy": "newest",
  "includeJobDetails": true,
  "maxResultsPerQuery": 25,
  "maxResults": 50
}
```

| Field | Type | Notes |
|---|---|---|
| `searchQueries` | array | Keyword queries such as `software engineer` or `finance internship`. Each runs as its own search. |
| `searchUrls` | array | Milkround search URLs. Filters in the URL are preserved and sort is applied on top. |
| `location` | string | UK city, county or postcode, applied to keyword queries. |
| `sortBy` | string | `newest` (default) or `relevance`. Use `newest` for scheduled scrapes. |
| `maxResults` | integer | Total cap across all queries. |
| `maxResultsPerQuery` | integer | Cap per keyword or URL. To give every keyword its full cap, set `maxResults` to at least `maxResultsPerQuery` times the number of keywords. |
| `includeJobDetails` | boolean | Open each job page for full description, location detail, category and employer size. |
| `includeCompanyDetails` | boolean | Also fetch each unique employer profile. Implies `includeJobDetails`. |
| `titleFilter` | string | Comma-separated title terms (OR match, case-insensitive). Non-matching rows are dropped before any detail fetch, so you do not pay for them. |
| `maxConcurrency` | integer | Concurrent detail requests (1 to 20). |

#### Precision title filter

```json
{
  "searchQueries": ["graduate scheme"],
  "titleFilter": "engineer, analyst",
  "maxResults": 50
}
```

### Speed and scale

Search-only runs return about 25 jobs per page. Detail mode fetches one extra page per job, so expect roughly 1 to 2 minutes for 30 detail rows. Very large runs are best split by keyword.

### Notes and limits

- **URLs**: Milkround and [Totaljobs](https://www.totaljobs.com) share one backend. Milkround has no job pages of its own, so `job_url` points to the totaljobs.com page where the job lives. Applying happens there through a script flow, which is why `apply_url` equals `job_url`.
- **Closing dates**: `closing_date` and `expires_at` come from the platform's listing expiry, which is set about six weeks after the posting date. It is not always an employer-set deadline; check the description for real application deadlines.
- **Salary**: many graduate schemes say "Competitive", which stays a null range. A few employers publish a bare number with no currency or period; that is kept in `salary_text` only.
- **Contacts**: Milkround has no recruiter name, email or phone field. `contact_*` fields only contain what the employer wrote in the ad text.
- **Employer website**: Milkround employer pages do not publish a website field. `company_website` is filled only when the employer's about text links to it.
- `scheme_size` is only set when the ad names a cohort size; `degree_required` stays null when the ad names no grade.
- Coverage is UK graduate opportunities; international rotational schemes appear occasionally.

### Use with an AI agent (MCP)

Connect this actor to Claude, Cursor or any MCP client to pull UK graduate opportunities on demand.

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=santamaria-automations/milkround-uk-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/S192M535Gf4IZGppm/info/api/mcp?build=latest). For the API and client code samples, see the [API tab](https://console.apify.com/actors/S192M535Gf4IZGppm/info/api).

**Example prompt once connected:**

> "Use `milkround-uk-scraper` to find 30 finance internships in London posted this week. Return a table with employer, salary and closing date."

### Common use cases

- Graduate recruitment agencies tracking new schemes daily
- University careers services benchmarking employers and salary bands
- Ed-tech vendors building account lists of UK graduate employers
- Research teams studying UK graduate labour market trends

### Related Actors

UK graduate and early-career boards:

- [TargetJobs UK Scraper](https://apify.com/santamaria-automations/targetjobs-uk-scraper): UK graduate jobs, internships, spring weeks and placement years.
- [Prospects UK Scraper](https://apify.com/santamaria-automations/prospects-uk-scraper): UK graduate careers portal with university partnerships.

Other UK job platforms:

- [Reed.co.uk Scraper](https://apify.com/santamaria-automations/reed-uk-scraper): UK jobs across all industries with salaries and full descriptions.
- [CV-Library Scraper](https://apify.com/santamaria-automations/cvlibrary-scraper): UK recruitment agency and direct employer roles.
- [Totaljobs Scraper](https://apify.com/santamaria-automations/totaljobs-scraper): UK jobs across all industries and experience levels.
- [CWJobs UK Scraper](https://apify.com/santamaria-automations/cwjobs-uk-scraper): UK IT and tech specialist board.

Broader coverage:

- [Website Job Extractor](https://apify.com/santamaria-automations/website-job-extractor): extract job listings from any website.
- [Indeed Scraper](https://apify.com/santamaria-automations/indeed-http-scraper): global job coverage with logos and benefits.
- [Glassdoor Scraper](https://apify.com/santamaria-automations/glassdoor-scraper): jobs with salary estimates and company ratings.
- [Career Site Jobs Scraper](https://apify.com/santamaria-automations/career-site-jobs-scraper): scrape jobs directly from company career pages (Greenhouse, Lever, Workday and more).
- [Website Email Scraper](https://apify.com/santamaria-automations/website-email-scraper): turn an employer website into a contact email.
- [Website Contact Extractor](https://apify.com/santamaria-automations/website-contact-extractor): pull emails, phones and socials from an employer site.

### 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/S192M535Gf4IZGppm/info/issues) on the actor page.
- **Feature request for this actor?** Open a ticket in the [Issues tab](https://console.apify.com/actors/S192M535Gf4IZGppm/info/issues) or email contact@nanoscrape.com with the field you need and 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.

# Actor input Schema

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

One or more keyword queries (for example 'software engineer', 'marketing graduate', 'finance internship'). Each runs as a separate search. Results are deduplicated.

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

How to order results on the Milkround SERP. 'newest' returns the most recently posted graduate jobs first (recommended for scheduled scrapes). 'relevance' uses Milkround keyword relevance ranking.

## `startUrls` (type: `array`):

Alias of searchUrls: Milkround search URLs to crawl in addition to any keywords. Merged into searchUrls.

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

Paste one or more Milkround.com search URLs. Go to milkround.com, run a search, and copy the URL. Filters in the URL are preserved. Can be combined with searchQueries.

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

UK city, county or postcode to filter by (for example 'London', 'Manchester', 'Bristol'). Applied to all keyword searches.

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

When true, opens each job's detail page for structured salary, closing dates and full description. Costs more but returns richer data.

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

Also fetch each unique employer's company profile page for the About-us text, phone, address, website, and a list of the employer's other currently-open roles. Deduplicated per employer within a run. Adds $0.005 per unique employer. Implies includeJobDetails=true (employer link only lives on the PDP).

## `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 event, so you don't pay for filtered-out jobs. Leave empty to disable.

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

Total cap across all queries and URLs.

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

Maximum results per search URL or keyword.

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

Maximum concurrent detail page requests. Only used when Fetch job detail pages is on.

## Actor input object example

```json
{
  "sortBy": "newest",
  "searchUrls": [
    "https://www.milkround.com/jobs/software-engineer"
  ],
  "location": "London",
  "includeJobDetails": false,
  "includeCompanyDetails": false,
  "titleFilter": "",
  "maxResults": 5,
  "maxResultsPerQuery": 5,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

Dataset of UK graduate job listings. Each row has: id, title, company_name (=employer_name), employer_logo_url, location, city, region, postal_code, latitude, longitude, country, salary_range and flat salary_min/salary_max/salary_currency/salary_period, salary_text, employment_type (graduate-scheme/graduate-job/internship/placement-year/apprenticeship), workplace_type, contract_type, sector, category, degree_required, start_date_type, duration_months, scheme_size, closing_date (=expires_at), description, description_full, description_html, description_md, job_url, apply_url, application_url (legacy, null), is_easy_apply, badges, posted_at, posted_at_text, posted_at_datetime, search_query, contact_emails/contact_phones/contact_urls and scalar contact_email/contact_phone (from the description), company_profile_url, company_logo_url, company_industry, company_size, company_founded_year, and with includeCompanyDetails: company_about, company_phone, company_email, company_website, company_social_urls, company_address\_\* and company_active_jobs.

# 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 = {
    "sortBy": "newest",
    "searchUrls": [
        "https://www.milkround.com/jobs/software-engineer"
    ],
    "includeJobDetails": false,
    "maxResults": 5,
    "maxResultsPerQuery": 5,
    "maxConcurrency": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("santamaria-automations/milkround-uk-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 = {
    "sortBy": "newest",
    "searchUrls": ["https://www.milkround.com/jobs/software-engineer"],
    "includeJobDetails": False,
    "maxResults": 5,
    "maxResultsPerQuery": 5,
    "maxConcurrency": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("santamaria-automations/milkround-uk-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 '{
  "sortBy": "newest",
  "searchUrls": [
    "https://www.milkround.com/jobs/software-engineer"
  ],
  "includeJobDetails": false,
  "maxResults": 5,
  "maxResultsPerQuery": 5,
  "maxConcurrency": 5
}' |
apify call santamaria-automations/milkround-uk-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,santamaria-automations/milkround-uk-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/S192M535Gf4IZGppm/builds/eqDsXvdURlozbxfMR/openapi.json
