🏆 AI Powered Indeed Job Scraper ⚡ Advanced Data, Best Value 🏆 avatar

🏆 AI Powered Indeed Job Scraper ⚡ Advanced Data, Best Value 🏆

Pricing

Pay per usage

Go to Apify Store
🏆 AI Powered Indeed Job Scraper ⚡ Advanced Data, Best Value 🏆

🏆 AI Powered Indeed Job Scraper ⚡ Advanced Data, Best Value 🏆

Scrape job postings from Indeed by keyword, location, and country. Structured output with title, company, location, salary, job type, and apply link.

Pricing

Pay per usage

Rating

5.0

(1)

Developer

Muhammad Shamshad Aslam

Muhammad Shamshad Aslam

Maintained by Community

Actor stats

8

Bookmarked

1

Total users

1

Monthly active users

16 hours ago

Last modified

Share

Indeed Jobs Scraper

Extract job postings from Indeed at scale — by keyword, location and country across 15 country sites. Every record arrives complete and structured, with the full job description included — no browser, no login wall, no page-1 limit.

Then it goes further than a scraper: pull an employer's other open roles, strip out recruitment agencies, and push each job straight into your workflow as it's found.

Features

Core scraping

  • Unlimited pagination — ~100 jobs per request. No "page 2 requires login" wall
  • 15 country sites — US, Germany, UK, Canada, Australia, France, Spain, Italy, Netherlands, Austria, Switzerland, India, Pakistan, UAE, Singapore
  • 64 fields per job — grouped into job details, job location, salary and company details so related columns sit together
  • 📍 Complete addresses, kept apartjobLocationFull for where the job is, companyAddressFull for the employer's head office. Never conflated
  • 💰 Readable salarysalaryFormatted gives you $70,000 - $90,000 per year at a glance, plus annualised salaryMinPerYear / salaryMaxPerYear so hourly, monthly and yearly jobs sort against each other
  • Deep company data — full "about" text, CEO name and photo, website, domain, industry, size, revenue, logo, and social links
  • Stable attribute keys — every attribute and occupation carries Indeed's own key alongside the label, so you can match across countries where the labels are translated
  • Company ratings (optional) — star rating, review count, CEO approval and headquarters, off by default
  • Duplicate-free — every job deduplicated by Indeed job key across the search, the per-company cap and the company expansion alike

Beyond a plain scraper

  • 🔑 Multi-keyword & multi-location search — Indeed caps every search at 1,000 results. Run several keywords and locations in one go, each with its own 1,000 allowance, aggregated into a single deduplicated dataset
  • 🏢 More jobs from the same company — for every employer in your results, pull their other open roles. Matched on Indeed's company ID, so "Delta" never drags in Delta Dental or Delta Defense
  • 🤖 Recruitment-agency filter — flag or remove staffing firms and headhunters, so you keep only companies hiring for themselves. Free keyword screen plus optional AI on the company description
  • Per-job webhook — each job POSTed to your endpoint the moment it's found, one request per job, ready for Clay, n8n, Make or Zapier. No dataset fetch afterwards
  • 🧹 Clean output — industry labels normalised from Indeed's internal enums, nested extras kept out of your main results

Why this one

If you're comparing Indeed scrapers, these are the things worth checking:

This actorWhat to watch for elsewhere
PaginationUnlimitedMany stop at page 1 — Indeed's web search demands a login for page 2
DescriptionsFull text on every jobOften needs a second request per job, or is dropped entirely
Speed & costNo headless browser; cheap datacenter proxyBrowser-based scrapers burn compute; residential-proxy ones bill per gigabyte
Company matchingExact Indeed company IDName matching silently merges Delta Dental, Delta Defense and Delta College
Agency filteringBuilt in, free screen + optional AIUsually absent — you filter recruiters out by hand afterwards
DeliveryPer-job webhook into your workflowDataset only; you write the fetch-and-poll glue yourself

Accuracy is measured, not asserted. Company expansion was tested across 56 rows spanning 28 employers, including two separate MasTec entities, with zero wrong-company rows. The agency screen was tested against 26 companies with zero false positives — Staffordshire, Cheshire, Hampshire, Berkshire and Jobst Medical all correctly pass, where a naive keyword filter deletes them.

Nothing is dropped on a guess. Employers with no Indeed description, and any company the AI could not judge, are kept and labelled rather than silently removed.

Input

FieldTypeDefaultDescription
countryselectusIndeed country site
keywordsarrayrequiredOne or more job titles, skills or companies — at least one. Each is searched separately and the results merged, deduplicated by job key
locationsarray[]One or more cities, states or postal codes. Every keyword is searched in every location. Empty = country-wide
radiusinteger25Search radius (km/miles by country); used with location
postedWithinDaysinteger0Only jobs from the last N days (0 = all time)
maxItemsinteger50Total number of records to scrape
maxJobsPerKeywordinteger0Cap how many jobs each keyword contributes, so a broad term can't eat the whole budget. 0 = no limit
fetchCompanyRatingsbooleanfalseStar rating, reviews, CEO approval, HQ. Needs residential proxy
maxJobsPerCompanyinteger0Keep at most N jobs per employer (2–10, max 10). 0 (default) = no limit
fetchMoreCompanyJobsbooleanfalseOff by default. Turn on to also collect other open roles from each company found
moreJobsPerCompanyinteger5How many other jobs to pull per company (up to 25). Only used when the switch is on
expandedJobsOutputselectnestednested = extras hang off each search row; separateRows = extras become their own rows
recruitmentAgencyHandlingselectoffoff / flag (label them) / exclude (drop them). Needs an OpenAI key
openaiApiKeystringYour OpenAI API key, used only for the filter above
openaiModelselectgpt-4o-miniFixed — the nano models gave unreliable verdicts and were removed
webhookUrlstringOptional. POST each job to your URL as it's found, one request per job
proxyConfigproxyoffOptional — the Actor enables a datacenter proxy itself when a run needs one. Only set Residential if you turned on employer ratings

Searching several keywords and locations

Indeed caps every individual search at 1,000 results — that ceiling is theirs, not this Actor's, and no amount of pagination gets past it. The way through is to run several narrower searches instead of one broad one, because each gets its own 1,000-result allowance.

{
"country": "nl",
"keywords": ["monteur", "hovenier", "uitvoerder"],
"locations": ["Amsterdam", "Rotterdam", "Utrecht"],
"maxItems": 500,
"maxJobsPerKeyword": 200
}

That runs 9 searches (3 keywords x 3 locations), each with its own allowance, and returns one clean dataset.

Overlap is handled for you. A job that shows up under both "monteur" and "uitvoerder" is deduplicated by Indeed's job key, so it appears once — never twice. The keyword and location fields on each row tell you which search first surfaced it.

The older keyword / extraKeywords / location / extraLocations fields still work, so saved tasks and existing API calls keep running unchanged.

maxJobsPerKeyword keeps one term from starving the others. Without it, a broad keyword is scraped first and can consume the entire Max Items budget before the rest ever run. With 3 keywords, Max Items 60 and this set to 20, each keyword contributes at most 20.

What runs when

Everything is scraped and aggregated before any filtering or delivery happens. This ordering matters if you use the AI filter or a webhook:

  1. Scrape every keyword/location combination, deduplicating by job key as it goes
  2. Aggregate all searches into one result set
  3. Expand by company, if that option is on
  4. Apply the per-company cap across the aggregated set
  5. Classify companies — the unique employers are collected first, and each is judged once, no matter how many keywords or how many jobs it appeared under
  6. Deliver to the dataset and to your webhook

So a company found under three different keywords costs one AI call, not three. And your webhook never receives a row before its classification is settled, nor twice for the same job.

Max jobs per company

One employer can swamp a search — a single "nurse" search returned 26 of its 60 jobs from one company. maxJobsPerCompany caps how many rows any one employer contributes, so you see the market instead of one company's careers page.

SettingResult on the same 60-job search
241 companies, none above 2
335 companies, none above 3
0 (default) = no limit18 companies, one contributing 26 jobs

0 means unlimited, not "one per company". There is no cap at all: whatever a company has that matches your search, you get, up to maxItems. If an employer has 200 matching jobs and you ask for 200 rows, all 200 rows can come from that single employer. Use 0 only when you want everything from a narrow search — for example when you have already searched a specific company by name.

Defaults to 0 (no limit), so you get everything Indeed returns. Set 2–10 when you would rather have breadth across employers than depth on one; 10 is the maximum.

Skipped jobs do not count towards maxItems — you still get the full number you asked for, just spread across more employers. Employers are grouped by their Indeed company ID, falling back to the normalised company name so smaller firms with no company page are capped too. Every job is still deduplicated by job key, and a job dropped by the cap is remembered so the company expansion cannot add it back.

Careful — 0 means opposite things on the two company settings. On maxJobsPerCompany it means no limit. On moreJobsPerCompany (below) it means off.

This setting is the mirror image of the next one: maxJobsPerCompany limits how many of a company's jobs matched your search, while fetchMoreCompanyJobs deliberately adds more of them. They combine well — cap the search for breadth, then attach each employer's other openings to every row.

The cap is applied to the aggregated results, after every search has finished and duplicates are gone — so which jobs survive doesn't depend on the order your keywords happened to run in. Jobs dropped by the cap don't count against Max Items: ask for 40 with a cap of 2 and you get 40 jobs spread across more employers, not 24.

Company ratings & reviews (optional)

fetchCompanyRatings adds each employer's public reputation data:

FieldMeaning
companyRating / companyReviewCountStar rating and how many reviews it is based on
companyCeoApprovalPercentShare of reviewers approving of the CEO
companyHeadquartersHead-office address
companySectorsBusiness sectors, in the site's language

Fetched once per company and cached, so an employer with 30 jobs costs one request.

This one field group needs a residential proxy. Everything else in this Actor talks to an endpoint that does not block datacenter IPs. Ratings come from Indeed's company pages, which are Cloudflare-protected — on datacenter proxy they return HTTP 403 and the fields stay empty. Blocking is IP-reputation based, so it is best-effort even on residential: the same page can return data on a fresh IP and 403 on a heavily used one. The run log states exactly what happened (Reasons: 3x HTTP 403) rather than failing silently.

Coverage is partial regardless of proxy — many smaller employers have no Indeed company page at all. Those keep the fields empty rather than being guessed at.

It is off by default, so the standard path stays on cheap datacenter proxy. Turn it on only when you specifically need reputation data.

More jobs from the same company

A keyword search only shows you the one role that matched. Turn on fetchMoreCompanyJobs and the actor goes back to each employer it found and pulls the rest of their open positions — so a search for java developer at a company also surfaces their Staff Data Engineer, IT Engineering Manager and Associate Project Manager postings.

Useful when the employer matters more than the exact job title: sizing up how much a company is hiring, finding the right opening at a company you already care about, or spotting teams that are scaling.

Companies are matched on Indeed's company ID (the /cmp/… page), never on the name. A search for "Delta" would otherwise return Delta Dental, Delta Defense and Delta College as if they were one company; matching on the ID means every expanded row is provably the same employer. Every employer in your results is expanded, so enrichment is consistent across the whole dataset.

Output shape

expandedJobsOutput controls how the extras reach you.

nested (default) — your dataset stays one row per search result. Ask for 25 software engineer jobs and you get 25 rows, every title relevant to what you searched. Each row gains:

FieldMeaning
otherJobsAtCompanyList of that employer's other openings
otherJobsAtCompanyCountHow many are in the list

Nested entries are compact — jobKey, title, location, salary, datePosted, url — so rows stay readable rather than repeating a full record inside every one:

{
"title": "Lead SFDC Developer",
"company": "Qualys",
"otherJobsAtCompanyCount": 3,
"otherJobsAtCompany": [
{ "title": "Public Sector Channel Manager", "location": "Washington, DC", "url": "https://www.indeed.com/viewjob?jk=daabae56cef01692" },
{ "title": "ETM Sales Specialist", "location": "North Carolina", "url": "https://www.indeed.com/viewjob?jk=83a94ca802c5279f" }
]
}

separateRows — every extra job becomes its own full row, tagged foundVia: "company-expansion" and expandedFromCompany. Better for feeding a job board, but your dataset will contain titles unrelated to your search, and these rows are additional to maxItems — asking for 5 with 2 per company returns 11 rows. In nested mode the row count always equals maxItems.

Results are deduplicated across both phases, so a job already returned by your search is never repeated. Employers with no Indeed company page (some third-party postings) can't be verified by ID and are skipped rather than guessed at.

Expansion finds jobs that are in Indeed's search index. An employer's /cmp/ page can occasionally list a posting that the search index does not carry, and that job cannot be reached through the API. otherJobsAtCompanyCount: 0 therefore means "no others the API can see", not necessarily "no others exist".

Recruitment agencies (AI)

recruitmentAgencyHandling reads each employer's company description with an LLM and decides whether they're a staffing agency, headhunter or temp firm hiring on behalf of others — as opposed to a company hiring for itself. Three settings:

ModeBehaviour
off (default)No classification, no AI calls, no cost
flagClassify and label every job, but keep them all
excludeClassify and drop agency jobs from the dataset and the webhook

Use flag when you'd rather filter downstream (in Clay, a spreadsheet, your own code), and exclude when you want a clean dataset of direct employers only.

A free name / domain / industry screen runs first. Before any AI call, the employer's name, domain and industry are checked against staffing keywords (staffing, recruit*, talent, personnel, manpower, workforce, placement, employment, hire, job, staff, temp) plus an explicit list of the large agencies whose names give nothing away — Robert Half, Aerotek, TEKsystems, Randstad, Adecco, Insight Global, Kforce, Apex Systems, Vaco and others. A hit costs zero tokens, and the screen works without an OpenAI key at all: leave the key blank and you get keyword filtering for free, with a warning that ordinary-looking agencies will slip through.

Every token is matched as a separate word, never as a fragment inside another word — that distinction is the whole game. Jobst is not job, Cheshire is not hire, Staffordshire is not staff; all three are real employers that fragment matching wrongly excluded in testing. Domain labels have no spaces, so hyphens are treated as the separator (bright-hire.io → standalone hire, cheshire.org → not a match). Long unambiguous tokens like staffing and recruitment may still match inside a concatenated label, so acmestaffing.com is caught. recruitmentAgencyMatchedBy records which rule fired — name, domain, known-agency or ai — so you can audit real runs and tune the lists.

One call per company, not per job. Verdicts are cached against the employer's Indeed company ID — the same /cmp/ key the company expansion uses — so an employer with 30 postings costs one call and all 30 rows get the same verdict. A 20-job run used 6 calls across 7 unique companies, with 11 cache hits.

Every classified row carries:

FieldMeaning
isRecruitmentAgencytrue / false, or null when it couldn't be judged
recruitmentAgencyMatchedByWhich rule decided: name, domain, industry, known-agency or ai
recruitmentAgencyReasonThe model's short justification

Where the line is drawn. The model is asked about a company's primary business, not whether staffing is mentioned anywhere. Pure agencies go out — Robert Half's profile reads "talent solutions… contract talent and permanent placement". Consultancies, system integrators and outsourcing firms stay in, even when they list staffing among their services — Stefanini's profile says "managed services, systems integration, consulting and strategic staffing", and it is kept as a direct employer. Use flag mode first if you want to see how these borderline firms are being judged before you let exclude remove them.

The AI is only as good as the description. This filter reads the company description on Indeed — nothing else. It works well when a company states plainly what it does ("we connect job seekers with employers", "permanent placement and contract talent"). It is unreliable when the description is vague, marketing-heavy, or silent about the business model, and it cannot classify at all when there is no description, which is the case for a large share of smaller employers. Run flag mode first and read the verdicts before you let exclude delete anything.

Nothing is dropped on a guess. Employers with no company description on Indeed — often a quarter of them, mostly smaller firms — are kept with isRecruitmentAgency: null, as are companies whose API call failed after 3 retries. In exclude mode a row is only ever removed on a positive verdict, so the filter may let an agency through but will not delete a real employer.

Requires your own openaiApiKey, billed to your OpenAI account. Default model is gpt-5-nano at $0.05 / 1M input tokens — the cheapest OpenAI offers and ample for a yes/no call. gpt-4.1-nano ($0.10) and gpt-4o-mini ($0.15) are selectable. Setting a mode other than off without a key fails the run immediately rather than silently returning unclassified data.

Webhook delivery

Set webhookUrl and every job is POSTed to you the moment it's scraped — one HTTP request per job, with that job as the entire JSON body. Nothing to unwrap, no array to split, and no need to fetch the dataset afterwards. That is the shape Clay, n8n, Make and Zapier expect: each call fires one workflow run with the job fields already at the top level.

POST https://your-endpoint.example/hook
Content-Type: application/json
{ "jobKey": "4896c534ed0b3699", "title": "Web Developer", "company": "...", ... }

The dataset is always written first, so a webhook can never cost you data. Failed calls retry 3 times with backoff; if they still fail the job is logged and the run carries on, with a summary at the end (Webhook: 12 item(s) delivered, 2 failed…). A dead endpoint never fails the run.

One request per job means a 1,000-job run makes 1,000 calls. If your endpoint rate-limits, keep maxItems modest or make sure it responds quickly — the actor waits for each call.

Example input

{
"country": "us",
"keywords": ["software engineer"],
"locations": ["New York"],
"radius": 25,
"maxItems": 200
}

With company expansion — 200 rows, each carrying up to 5 of that employer's other openings:

{
"country": "us",
"keywords": ["software engineer"],
"locations": ["New York"],
"maxItems": 200,
"fetchMoreCompanyJobs": true,
"moreJobsPerCompany": 5,
"expandedJobsOutput": "nested"
}

Output

One row per job — 64 fields, grouped so related columns sit together: job details, job location, salary, company details, then search metadata.

{
"jobKey": "51658413c5757f03",
"title": "Manager, Back-End Engineer",
"url": "https://www.indeed.com/viewjob?jk=51658413c5757f03",
"originalApplyUrl": "https://jobs.publicisgroupe.com/job/...",
"refNum": "R439939",
"datePublishedClean": "13-06-2026",
"dateOnIndeedClean": "13-06-2026",
"expirationDateClean": null,
"datePublished": 1781672400000,
"datePublishedFormatted": "2026-06-13T09:00:00.000Z",
"dateOnIndeed": 1781672400000,
"dateOnIndeedFormatted": "2026-06-13T09:00:00.000Z",
"expirationDate": null,
"expirationDateFormatted": null,
"daysToAppearOnIndeed": 0.2,
"expired": false,
"urgentlyHiring": false,
"highVolumeHiring": false,
"language": "en",
"attributes": ["Azure", "Systems integration", "AI models"],
"attributesWithKeys": [{ "key": "75GKK", "label": "Part-time" }],
"occupations": ["Software Engineers"],
"occupationsWithKeys": [{ "key": "5HC3Z", "label": "Software Engineers" }],
"description": "Full plain-text job description...",
"descriptionHtml": "<div>Full HTML description...</div>",
"jobLocationFull": "16430 East Hughes Drive, 10014 New York, NY, United States",
"jobLocationShort": "New York, NY",
"jobLocationStreet": "16430 East Hughes Drive",
"jobLocationCity": "New York",
"jobLocationState": "NY",
"jobLocationPostalCode": "10014",
"jobLocationCountry": "United States",
"jobLocationCountryCode": "US",
"jobLocationLatitude": 40.72,
"jobLocationLongitude": -74.0,
"salaryFormatted": "$125,424 - $158,067 per year",
"salaryMin": 125424,
"salaryMax": 158067,
"salaryMinPerYear": 125424,
"salaryMaxPerYear": 158067,
"salaryPeriod": "per year",
"salaryUnit": "YEAR",
"salaryCurrency": "USD",
"company": "Publicis Groupe",
"companyIndeedUrl": "https://www.indeed.com/cmp/Publicis-Groupe",
"companyWebsite": "https://www.publicisgroupe.com",
"companyDomain": "publicisgroupe.com",
"companyAddressFull": "Graafsebaan 65, 5248 JT Rosmalen",
"companyRating": 3.8,
"companyReviewCount": 178,
"companyCeoApprovalPercent": 59,
"companySectors": ["Advertising and Marketing"],
"companyIndustry": "Internet and Software",
"companyIndustryRaw": "Iv1_INTERNET_AND_SOFTWARE",
"companyEmployeeRange": "10,000+",
"companyRevenue": "$1B+ (USD)",
"companyCeoName": "Arthur Sadoun",
"companyCeoPhoto": "https://.../ceophoto.png",
"companyBriefDescription": "Short one-line pitch from the employer's Indeed profile.",
"companyDescription": "The employer's full 'about' text — typically several times longer.",
"companyLogo": "https://.../logo.png",
"companyHeaderImage": "https://.../header.png",
"companyLinks": {
"corporateWebsite": "https://www.publicisgroupe.com",
"facebook": "https://www.facebook.com/publicisgroupe",
"twitter": "https://twitter.com/PublicisGroupe",
"instagram": "https://www.instagram.com/publicisgroupe"
},
"keyword": "software engineer",
"country": "us",
"foundVia": "search",
"expandedFromCompany": null,
"otherJobsAtCompany": [],
"otherJobsAtCompanyCount": 0
}

Field notes

FieldNotes
jobLocationFullWhere the job is, as one complete address — street, postcode, city, state, country
companyAddressFullThe employer's head office, which is often nowhere near the job. Needs fetchCompanyRatings
salaryFormattedRead-at-a-glance pay, e.g. $70,000 - $90,000 per year, €18.50 per hour. null when the listing states no salary
salaryMinPerYear / salaryMaxPerYearAnnualised, so hourly and monthly jobs sort against yearly ones. Assumes 40h/week, 52 weeks
companyIndeedUrlThe employer's Indeed company page (/cmp/…). Stable unique company ID
companyIndustryReadable industry label, normalised from Indeed's internal enum
attributesWithKeys / occupationsWithKeysIndeed's stable keys plus labels. Labels are translated per country ("Part-time" / "Parttime") so only keys match reliably across your 15 sites
languageLanguage the listing is written in, e.g. nl
expirationDateWhen the posting expires — often null, as Indeed rarely publishes it
companyRatingcompanySectors, companyAddressFullOnly when fetchCompanyRatings is on; see the caveat above
companyIndustryRawThe untouched enum (Iv1_INTERNET_AND_SOFTWARE), kept for exact matching
*Clean datesPlain calendar date, DD-MM-YYYY, in UTC — datePublishedClean, dateOnIndeedClean, expirationDateClean
datePublished / dateOnIndeedEpoch milliseconds; the *Formatted twins are ISO 8601
daysToAppearOnIndeedDays between the employer publishing the job and it appearing on Indeed. Under 1 = posted fresh; several days = an older listing re-surfacing. See below
originalApplyUrlThe employer's own apply link when they have one — Indeed-hosted when they use Indeed Apply
foundVia"search" (matched your keyword) or "company-expansion"
expandedFromCompanyWhich employer a row was expanded from; null for search rows
otherJobsAtCompanyOther openings at this employer — populated only when company expansion is on
highVolumeHiring / urgentlyHiringIndeed's own hiring-demand flags

Telling fresh jobs from recycled ones. Indeed's API has an isRepost field, but it returns null on every job in every country tested (150 jobs across NL and US), so it is not included — a permanently empty column is worse than none. Instead you get daysToAppearOnIndeed, the measured gap between the employer publishing the role and Indeed listing it. In a 60-job US sample, 56 appeared the same day and 4 took between 1.9 and 9.1 days. Filter on it yourself: < 1 for genuinely fresh postings, > 1 for listings that were already sitting elsewhere. It is deliberately not labelled "repost", because a long gap can also mean Indeed simply indexed the job late.

Renamed fields. Job location columns are now prefixed jobLocation* so they can never be mistaken for the employer's own address. If you map these downstream, update: locationjobLocationFull, cityjobLocationCity, statejobLocationState, postalCodejobLocationPostalCode, countryNamejobLocationCountry, latitudejobLocationLatitude, longitudejobLocationLongitude.

Rich company + application data — every listing includes the employer's CEO (name + photo), social links (website, Facebook, Twitter, Instagram), the full company description (companyDescription, alongside the shorter companyBriefDescription), and the direct employer apply URL (originalApplyUrl), not just the Indeed page.

Company fields (companyIndustry, companyRevenue, companyEmployeeRange, both descriptions, CEO, logo) come from the employer's own Indeed profile and are null when they haven't filled one in. Smaller employers frequently have none of them.

Use cases

  • Recruiting & sourcing — monitor open roles by market, skill and company, with agencies filtered out so you only see employers hiring directly
  • Lead generation — company domains, websites, CEO names, full descriptions and social profiles, pushed straight into Clay or your CRM by webhook
  • Account mapping — find one job at a target company, then pull every other role they have open to see which teams are growing
  • Market research — salary ranges, demand trends, hiring volume by industry and region
  • Job boards — feed fresh, fully-detailed listings into your product with descriptions already included

Reliability

An invalid or unauthorised OpenAI key stops the AI filter immediately rather than retrying — the cause is reported once, the free name/domain screen carries on, and every job is kept rather than dropped, so a bad key costs you nothing but the filtering.

Companies are classified five at a time rather than one by one — on a 37-company run that is 8.9s instead of 27.8s, and it stays well inside OpenAI's rate limits. Every API call retries up to 6 times with a fresh proxy IP and increasing backoff, covering both HTTP errors and transport-level failures (dropped sockets, proxy ECONNRESET, timeouts). If one search still can't complete, that keyword is abandoned and the run delivers everything the other searches collected, listing what failed in the log. A run only fails outright when every search was unreachable.

Notes

  • Apify Proxy must be enabled, but only the cheap datacenter tier. Apify blocks direct outbound network access for Actors running under limited permissions, so requests have to route through the proxy. The endpoint this Actor uses does not block datacenter IPs, so there is no reason to pay residential rates.
  • Some fields (industry, revenue, website) are only present when Indeed has them on the employer's profile.
  • Export as CSV, Excel, or JSON from the dataset tab, or via the Apify API.