Caterer.com Scraper - UK Hospitality Jobs, Salaries & Details avatar

Caterer.com Scraper - UK Hospitality Jobs, Salaries & Details

Pricing

from $1.00 / 1,000 job results

Go to Apify Store
Caterer.com Scraper - UK Hospitality Jobs, Salaries & Details

Caterer.com Scraper - UK Hospitality Jobs, Salaries & Details

Scrape UK hospitality jobs from Caterer.com, including chef, hotel, restaurant, bar, and events roles. Search by keyword, location, filters, or URLs. Returns salary, employer, logo, location, skills, and 35+ fields, with optional full description, GPS, and company profile.

Pricing

from $1.00 / 1,000 job results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

5 days ago

Last modified

Share

Caterer.com Scraper: UK Hospitality Job Listings

Caterer.com Scraper turns Caterer.com into a structured UK hospitality jobs feed. Get chef, restaurant, hotel, bar, and events roles with 35+ fields straight from the listing, including a parsed salary (min, max, currency, period), employer, location, and skills. Search by keyword and location with real server-side filters, or paste any Caterer.com search URL and walk it forward. Switch on an optional detail pass for the full description, GPS coordinates, employment type, and company profile, then export to JSON, CSV, or Excel, or pull results straight into your app through the API.

Why This Scraper?

  • 35+ fields per job from the listing page alone. No detail fetch required for title, parsed salary, employer, logo, location, posting source, skills, and snippet.
  • Two ways to run. Build a search from keyword, location, and filters, or paste any Caterer.com search URL and walk it forward.
  • Real server-side filters. Job type, advertiser type (direct employer vs agency), minimum salary by period (year, day, or hour), posted-within window, and sort order.
  • Parsed salary. The free-text salary string is split into min, max, currency, and period, including the hourly rates common in hospitality.
  • Optional full details. GPS coordinates, structured address, full description, employment type, valid-through date, and company profile, plus any contact number or email the posting itself publishes.
  • Cost control built in. A single job cap, an optional page cap, and a residential request budget to bound what each run collects and spends.
  • Resume and incremental modes. Continue an interrupted run without re-collecting jobs, or schedule the same search daily and get back only what changed.

Use Cases

  • Recruitment and staffing agencies: benchmark competitor postings, salary bands, and hiring volume across chef, front-of-house, and management roles.
  • Job board and career site operators: mirror UK hospitality vacancies with structured salary, location, and employer data for your own listings.
  • Compensation and labour-market research: track parsed hourly and annual pay ranges by role, region, and posting date to study wage trends in hospitality.
  • Employer brand and competitor monitoring: watch specific companies' hiring activity, job counts, and posting frequency over time.
  • Sales lead generation: find companies actively hiring chefs, managers, or bar staff as leads for recruitment or hospitality-supply sales.

Data You Get

Sample shape: values are illustrative placeholders, not from a live listing.

FieldExample
jobId100000001
title"Head Chef"
jobUrlCaterer.com link to the job (also used as applyUrl)
sourceSite"Caterer.com"
datePosted"2026-01-01T00:00:00.000Z"
employer.name"Sample Restaurant Group"
employer.logoUrllink to the employer's logo image
employer.isAnonymousfalse
location.text"Soho, Central London (W1)"
location.postalCode"W1"
location.latitude / location.longitude (detail)51.5000 / -0.1300
salary.rawText"From £14 to £18 per hour"
salary.min / salary.max14 / 18
salary.currency / salary.period"GBP" / "hour"
skills["Menu planning", "Food safety"]
textSnippet"We are looking for an experienced head chef..."
isSponsoredfalse
crossPostedCount1
description (detail)full job description text, when fetchDetails is on
employmentType (detail)["FULL_TIME"]
validThrough (detail)"2026-02-01T00:00:00.000Z"
contactPhones / contactEmails (detail)best-effort numbers/addresses the posting itself publishes, often empty
company (detail)employer profile: size, founded, industries, benefits, when available

Other detail-only fields also come back once fetchDetails is on: structured address (location.locality, location.region, location.country, location.streetAddress), industry, directApply, applyType, jobLocationType, contractType, and workType. externalId is filled from the listing and refined from the detail page when available.

How to Use

  1. Pick a mode: search (build from keyword, location, and filters) or url (paste Caterer.com search links).
  2. For search mode, set Locations and any filters you need (keywords, job type, advertiser type, minimum salary, posted-within window, sort order). For URL mode, paste one or more search-result URLs; filter fields are ignored.
  3. Turn on Fetch full job details if you need the full description, GPS, employment type, and company profile. Set Max jobs (and, optionally, Max pages) to control run size and cost.
  4. Click Start. Download the dataset as JSON, CSV, or Excel, or read it through the API.

Basic search in one city:

{
"mode": "search",
"locations": ["London"],
"keywords": "chef",
"maxListings": 20
}

Search with filters (permanent chef roles, at least £30,000 a year, posted in the last 7 days, newest first):

{
"mode": "search",
"locations": ["Manchester", "Leeds"],
"keywords": "chef",
"jobType": "permanent",
"minSalary": 30000,
"salaryType": "annual",
"postedWithin": "7",
"sortBy": "date",
"maxListings": 100
}

Full details (adds description, GPS, employment type, company profile):

{
"mode": "search",
"locations": ["London"],
"keywords": "restaurant manager",
"fetchDetails": true,
"maxListings": 50
}

Paginate pasted URLs (filter fields are ignored in URL mode):

{
"mode": "url",
"urls": [
"https://www.caterer.com/jobs/chef/in-london",
"https://www.caterer.com/jobs/in-edinburgh"
],
"maxPages": 5,
"maxListings": 200
}

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/caterer-com-scraper").call(
run_input={"mode": "search", "locations": ["London"], "keywords": "chef", "maxListings": 20}
)
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
print(job["title"], job["employer"]["name"], job["salary"]["rawText"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/caterer-com-scraper').call({
mode: 'search', locations: ['London'], keywords: 'chef', maxListings: 20,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets, or webhooks from the Integrations tab.

How Max jobs and Max pages shape a run

Max jobs (maxListings, default 20) is the sole cap on total jobs collected across every location or URL in a run; set it to 0 for unlimited. Max pages (maxPages, default 0) walks the whole catalogue by default: the run stops on its own once the site's reported page count is reached, a page comes back empty, or a page holds only jobs already collected earlier in this run, never an artificial page-number ceiling. Give Max pages a finite value only as an extra safety limit; Max jobs is the cost control you actually want.

If a run is interrupted by a platform migration and continues from its automatic checkpoint, the continued part starts a fresh Max jobs count, so that one run's dataset can end up holding more than Max jobs jobs (never duplicates).

All locations and URLs in one run share a single run-wide dedup set, which matters when two of them genuinely overlap (for example "London" and "Greater London"):

  • The second search can stop early. A page of the second search made up entirely of jobs the first search already collected counts as a repeat page, so the second search stops there and its later pages, even ones full of jobs the first search never saw, are not fetched.
  • Jobs past the cap are also marked seen. When Max jobs is split across several searches and cuts a page short, the leftover job ids on that page are still marked as seen for the rest of this run (including a checkpoint-continued part of it), so the second search skips them too.

Run genuinely overlapping locations as separate runs if you need every job from each of them.

Resume and recurring updates

There are two different things here; pick the one that matches what you're doing.

NeedUse
A run stopped and should continueresumeFromRunId, or the automatic checkpoint recovery
Run the same search every day and receive only changesincrementalMode
Keep separate daily campaigns for similar searchesdistinct stateKey values
Run a normal full snapshotleave both off

Resume (resumeFromRunId) continues one specific interrupted or previous large run: paste a run id or dataset id and this run skips jobs already collected there, returning only the remaining new jobs. An automatic same-run checkpoint also protects against platform migrations without any input needed.

Incremental mode (incrementalMode) is for a schedule, for example daily: the actor remembers the previous run of the same search by itself, so you never paste a run id. The first run returns everything as NEW. Later runs return only NEW, UPDATED, and REAPPEARED jobs by default; unchanged jobs are suppressed and not billed. Turn on emitUnchanged or emitExpired only when you also want those rows returned, and billed for. State is isolated automatically per mode, locations, keywords, job type, advertiser type, minimum salary, salary period, posted-within window, sort order, URLs, and fetchDetails; maxListings, maxPages, and maxResidentialRequests are caps, not filters, and deliberately do not affect the state key.

When incrementalMode is on, every returned record also carries changeType (NEW, UPDATED, UNCHANGED, REAPPEARED, or EXPIRED), changedFields (populated only for UPDATED), firstSeenAt, and lastSeenAt.

Max jobs is spent on jobs scanned, not jobs returned. Outside incremental mode the two are the same. Under incremental mode, most jobs on a quiet recurring run are UNCHANGED and suppressed; if the cap instead counted returned rows, a quiet run would keep paging deeper trying to "backfill" the quota with fresh jobs every day, and cost would never actually drop. The tradeoff: on a small Max jobs value, if the first jobs scanned all happen to be unchanged (the default sort is relevance, which can keep the same jobs on page one day after day), a run can scan its whole cap and return nothing new even though newer jobs exist further into the catalogue. If a small, capped incremental run keeps returning nothing, raise Max jobs, or sort by date so newer postings surface first.

Combining Resume with Incremental mode to bootstrap a monitoring campaign from an earlier large run works, but the jobs it seeds are known only by id, not by content: the very next incremental run reclassifies each of them as UPDATED (and bills them as such) even if nothing about the job actually changed, because there is nothing stored yet to compare against. Expect and disregard that one-off UPDATED batch the first time a resume-seeded campaign runs again.

EXPIRED is only synthesized once a run fully scans every search/URL target: not capped by Max jobs or Max pages, not a resume run, and not a checkpoint-interrupted run. If any one search stops early (a refused page, or the overlapping-search repeat-page stop described above), EXPIRED is skipped for the whole run, not just for that search. A URL that starts at a later page (?page=3) counts as fully scanned from that page on, so a tracked job that moves up to an earlier page reads as EXPIRED. Once that condition is met, though, every tracked job absent this run is returned as EXPIRED and billed, with no cap of its own: Max jobs bounds this run's scan, not the size of the EXPIRED batch a large, long-running monitoring campaign can produce. If a stateKey is deliberately shared across two differently configured searches, a completed run of the narrower one can mark the other search's entire tracked set EXPIRED, since state comparison has no notion of which search actually ran. Share a stateKey only between searches that genuinely cover the same jobs.

Send results into your apps (MCP connectors)

Optionally pipe results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape; the Apify dataset is never changed.

  1. Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field.
  3. For Notion, also set notionParentPageUrl to the page where items should be created.

Each connector receives a condensed, human-readable summary per item (title plus key fields), not the full JSON; the complete record always stays in the Apify dataset. The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch builds URLs from filters; url paginates URLs you paste.
locationsarray["London"]Towns, cities, counties, or regions (search mode). One search runs per location. Leave empty for all of the UK.
keywordsstring(empty)Hospitality role, skill, or employer to search for. Leave empty to list all hospitality jobs in the location.
jobTypestringanyany / permanent / contract / temporary / part-time / work-from-home.
companyTypestringanyany / employer (direct) / agency.
minSalaryinteger(empty)Lowest salary to include, paired with the salary period below. Leave empty for no minimum.
salaryTypestringannualannual / daily / hourly. Unit for the minimum-salary filter.
postedWithinstring00 (any time) / 1 / 3 / 7 / 14 days.
sortBystringrelevancerelevance / date / salary-desc / salary-asc / distance.
urlsarraysampleCaterer.com search-result URLs to scrape (URL mode). Filter fields above are ignored. A page number in the URL is honoured as the starting point.
fetchDetailsbooleanfalseFetch detail pages to add the full description, GPS coordinates, structured address, employment type, valid-through date, and company profile.
maxListingsinteger20Total jobs to collect across all searches. The main limit. 0 = unlimited (bounded by Max pages).
maxPagesinteger0Optional safety limit on pages walked per location/URL (25 jobs per page). 0 = walk the whole catalogue: stops at Max jobs, the site's own last page, or a repeat-page guard, never an artificial page cap.
maxResidentialRequestsinteger0Safety cap on residential-tier requests this run may use (listing pages and detail pages). 0 = unlimited. When reached, listing falls back to a lighter connection tier and detail enrichment stops.
resumeFromRunIdstring(none)ID of a previous run of this actor (or a dataset ID). Jobs already in that dataset are skipped, so this run returns only new jobs (a delta). For recurring daily monitoring of the same search, use Incremental mode instead.
incrementalModebooleanfalseTurn on for daily or recurring monitoring. The first run returns everything as NEW. Later runs return only NEW, UPDATED, and REAPPEARED jobs by default.
stateKeystring(none)Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently configured runs. Leave empty for an automatically derived key.
emitUnchangedbooleanfalseAlso return jobs unchanged since the last run, marked UNCHANGED (extra billed rows).
emitExpiredbooleanfalseAlso return jobs no longer found, marked EXPIRED. Only produced once a run fully scans the tracked search (not capped, not resumed).
proxyobjectResidential GBConnection settings.
mcpConnectorsarray(none)Optional: send a summary of each record to apps you authorized under Integrations.
notionParentPageUrlstring(none)Notion connector only: page under which records are created.
maxNotifyListingsinteger50Cap on items written to each connector per run.

Output Example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"rowType": "job",
"scrapedAt": "2026-01-01T00:00:00.000Z",
"jobId": 100000001,
"jobUrl": "https://www.caterer.com/job/head-chef/sample-agency-job100000001",
"applyUrl": "https://www.caterer.com/job/head-chef/sample-agency-job100000001",
"sourceSite": "Caterer.com",
"title": "Head Chef",
"datePosted": "2026-01-01T00:00:00.000Z",
"employer": {
"id": 1000000,
"name": "Sample Restaurant Group",
"url": "https://www.caterer.com/jobs/sample-restaurant-group?cmpId=1000000",
"logoUrl": "https://www.caterer.com/CompanyLogos/00000000000000000000000000000000.png",
"isAnonymous": false
},
"location": {
"text": "Soho, Central London (W1)",
"postalCode": "W1",
"locality": "Soho",
"region": "London",
"country": "GB",
"latitude": 51.5000,
"longitude": -0.1300
},
"salary": { "rawText": "From £14 to £18 per hour", "min": 14, "max": 18, "currency": "GBP", "period": "hour" },
"skills": ["Menu planning", "Food safety"],
"textSnippet": "We are looking for an experienced head chef to lead our kitchen team.",
"isSponsored": false,
"crossPostedCount": 1,
"description": "Full job description text appears here when fetchDetails is enabled.",
"employmentType": ["FULL_TIME"],
"industry": "Catering, Catering-Chef",
"validThrough": "2026-02-01T00:00:00.000Z",
"directApply": true,
"applyType": "DirectApply",
"contactPhones": [],
"contactEmails": [],
"company": { "name": "Sample Restaurant Group", "size": "51-200", "founded": "2005", "industries": ["Hospitality"] },
"detailFetched": true
}

Plan Requirement

Caterer.com accepts Apify Residential with country GB most reliably, which is the prefilled default. Listing pages occasionally work on Datacenter but are frequently refused, and full job details (fetchDetails) always need Residential GB. Apify Residential is available on the Starter plan and above. On the free plan a run may return few or no results; set proxy.apifyProxyGroups to ["RESIDENTIAL"] with apifyProxyCountry "GB" after upgrading.

FAQ

How much does it cost?

You pay per job returned, plus a small per-run start fee, and an optional surcharge for jobs whose detail page was fetched. The Pricing tab shows the current rates. Use Max jobs to cap the cost of any run.

This actor collects only publicly available job listings. You are responsible for how you use it: follow Caterer.com's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.

Can I get only new jobs on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated jobs, and unchanged ones are not billed. Turn on Emit expired jobs only if you also want to know when a tracked job disappears, and note that an EXPIRED batch on a large campaign is not capped by Max jobs.

Why did my run return few or no results?

Check that your filters aren't too narrow, and that the connection settings match the Plan Requirement section above. A run that could not read any pages at all fails with a clear message instead of returning an empty dataset, so "no jobs match" is never confused with "nothing could be read".

Does this actor collect personal candidate information?

No. It collects job postings, which employers and agencies publish to attract applicants, not candidate or worker data. With Fetch full job details on, it also best-effort harvests any contact number or email the posting itself publishes (a tel:/mailto: link on the job page, or a number or address typed into the description), and it is frequently empty. This is usually a company or agency line, but it can be a named recruiter's direct number or email, which may count as personal data under UK GDPR, so handle these two fields accordingly.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear, or Airtable.

🔗 Want more travel data?

Pair this actor with these related scrapers from the same team:

💼 Totaljobs Scraper
Scrape UK job listings from Totaljobs.com by keyword, location, filters, or URL. Extract...
🏨 Comparably
From $1/1K. Extract rich company data from comparably.com using company names or profile...
🏨 Rakuten Travel Scraper
Scrape Rakuten Travel, Japan's largest domestic hotel-booking site, by prefecture...
🏨 Wego Scraper
Scrape Wego hotels by city or search URL. Get rates, providers, booking links...
🏨 Traveloka Hotel Scraper
Scrape Traveloka hotels across Singapore, Malaysia, Indonesia, Thailand, Vietnam and the...
🏨 Hipflat Scraper [
Scrape hipflat.co.th property listings and new-project data across Thailand: price, price...

👉 Browse all abotapi scrapers

💬 Support & custom scrapers

  • 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • 🛠️ Need another site, extra fields or a private build? Email abotapi@proton.me or message Telegram @abotapi.
  • ⭐ Enjoying it? A quick review on the actor page helps other users find it.