NewLaunching String Web Access APIRead the manifesto →

How to scrape job listings from job boards

The String Web Access API is the best way to scrape job boards. It returns any job board page, or just its listings as JSON with title, company, location and pay. In our September 2026 benchmark it fetched Indeed, Glassdoor and ZipRecruiter on every attempt, and returned 97% of requests across 100 bot-protected sites, the most of 16 providers.

The first 5,000 requests are free. Set it up in one step with the quickstart.

Why scrape job boards?

Job postings are the earliest public record of what a company plans to do. A role goes up before the team exists, and the pay range goes up with it in states that require one. A job scraper collects postings from boards and career pages on a schedule, and tells you what's new and what closed. It answers the questions most teams care about:

  • Who is hiring, and for what? A company that posts ten sales roles in a new city is about to sell there. Recruiters, sales teams and investors all watch for this.
  • What does the job pay? Posted pay ranges show the market rate for a role in a city, often before salary surveys do.
  • Which jobs are new, and which closed? A posting that comes down usually means the role was filled or cut. Job aggregators and alert products depend on knowing both.

What you can collect

Job listings

Title, company, location, remote or hybrid, job type, the full description and the apply link.

Pay

Pay ranges the employer posts, kept apart from the board's own salary estimates.

Company hiring

Open roles per company, team and city, and how that count changes week to week.

Market trends

Demand for a skill or title across a region, and how fast postings for it fill.

The problem

Why does job board scraping break?

  • Job boards block scrapers. In our September 2026 benchmark, 12 of the 15 other scraping APIs couldn't fetch indeed.com on every attempt, including Bright Data (3 of 5), Oxylabs (2 of 5) and Zyte (4 of 5). Browserbase got 0 of 5 on Indeed, Glassdoor and ZipRecruiter. String got all 5 on each. A script that works once usually breaks when it runs every day.
  • Estimates look like real pay. Glassdoor marks each range "Employer provided" or "Glassdoor est.", and ZipRecruiter marks its guesses "Estimated pay". A scraper that drops the label saves the board's guess as the employer's offer.
  • The same job is on many boards. The Farmer's Dog posted its Data Engineer 2 role on its Greenhouse board and on Indeed on the same day, at $130K to $145K on both. Count by URL and you count it twice.

Job boards and career pages

StringOne API
FetchSearch SitemapsBrowser
Your job database

The solution

Why do teams choose String?

  • It works where others fail. String returned 97% of requests across 100 bot-protected sites in our September 2026 benchmark, the most of 16 providers, and all 25 attempts on the 5 job sites in it.
  • You pay only for pages that come back. Blocks and errors are free.
  • There's nothing to maintain. No proxies, fingerprints or captcha solvers on your side.
  • Blank pages don't become data. Mark the fields you need as required in your schema, and a page that comes back without them is flagged instead of saved as an empty result.

How do I scrape job boards?

  1. Pick your sources

    Search boards like Indeed, Glassdoor and ZipRecruiter cover many employers in one place. Company career pages on applicant tracking systems (ATS) like Greenhouse, Lever and Workday are the employer's own postings. Most projects need both.

    With String: The /search endpoint finds a company's career page, and the sitemap endpoint lists every URL on a domain.

  2. Read the ATS feed when there is one

    Many ATS boards serve their jobs as JSON. Greenhouse serves every board at boards-api.greenhouse.io/v1/boards/<company>/jobs, and one request returned all 31 open roles at The Farmer's Dog. Use first_published as the posting date, not updated_at.

    With String: Fetch the feed URL like any page and you get the JSON back as-is.

  3. Page through search results

    Search boards split results into pages. Indeed pages with a start parameter in steps of 10. Run the same queries with the same settings every time, so a change in the data means a change on the board.

    With String: Blocked requests are retried, and you don't pay for the ones that fail. Set countryCode to search a board's local site.

  4. Keep posted pay apart from estimates

    Save the pay range together with where it came from. On Greenhouse, the pay range sits inside the description HTML, not in its own field. On Glassdoor and ZipRecruiter, keep the estimate label with the number.

  5. Treat a blank page as a failure

    A search page with no job cards was probably blocked or changed. Flag it and keep the last good run, so its jobs aren't marked closed because one page failed.

  6. Match the same job across boards

    Within one board, use its own job ID, like Indeed's jk or the Greenhouse id. Across boards, match on company, title and location. Board URLs carry tracking parameters that change on every visit.

  7. Track new and closed jobs on a schedule

    Store the first and last date you saw each job. A job that's missing from two runs in a row has probably closed. Daily suits most boards.

Quickstart

From your agent

Add the hosted MCP server to Claude, Cursor, ChatGPT or any MCP client. Then give your agent a job search URL. It calls the web_access_fetch tool and reads the listings.

https://mcp.usestring.ai/v1/mcp

From the API

One call returns the jobs on an Indeed search page as JSON. If extraction can't fill the required fields, you get "extracted": false back instead of a guess.

curl https://request.usestring.ai/v1/fetch \
  -H "Authorization: Bearer $STRING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.indeed.com/jobs?q=data+engineer&l=New+York%2C+NY",
    "countryCode": "US",
    "jsonSchema": {
      "type": "object",
      "properties": {
        "jobs": {
          "type": "array",
          "minItems": 1,
          "items": {
            "type": "object",
            "properties": {
              "title": { "type": "string" },
              "company": { "type": "string" },
              "location": { "type": "string" },
              "pay": { "type": ["string", "null"] }
            },
            "required": ["title", "company", "location"]
          }
        }
      },
      "required": ["jobs"]
    }
  }'

Response (first 3 of 15 jobs)

{
  "jobs": [
    {
      "title": "Data Engineer",
      "company": "BDG",
      "location": "New York, NY",
      "pay": "$105,000 - $145,000 a year"
    },
    {
      "title": "Associate Data Engineer",
      "company": "Aretove",
      "location": "New York, NY",
      "pay": "$75,000 - $90,000 a year"
    },
    {
      "title": "Data Engineer",
      "company": "David Yurman Enterprises LLC",
      "location": "New York, NY 10013",
      "pay": "$140,000 - $150,000 a year"
    }
  ]
}

Get a free sample of job data

Tell us which boards, companies or roles you track. We'll run String on them and email you a sample of the job data, free.

Request a free sample job data
What a sample looks like
BoardJobCompanyPay
IndeedData EngineerBDG$105K to $145K
IndeedData Engineer 2The Farmer's Dog$130K to $145K
GreenhouseData Engineer 2The Farmer's Dog$130K to $145K
GlassdoorData EngineerTapestry$140K to $160K
GlassdoorSenior Data EngineerBank of America$136K to $182K est.
ZipRecruiterAssociate, Data EngineeringEvergreen Trading$65K to $75K

Frequently asked questions

What's the best way to scrape job boards?

Fetch the board's search pages on a schedule, read the ATS feed where a company has one, and match the same job across boards. The hard part is getting the pages at all, because job boards block most scrapers. The String Web Access API fetched Indeed, Glassdoor and ZipRecruiter on every attempt in our September 2026 benchmark, and returned 97% of requests across 100 bot-protected sites, the most of 16 providers.

How do I scrape Indeed job listings?

Fetch the search URL (/jobs?q=<keywords>&l=<location>) with String and page through it with start=10, start=20 and so on. Each job card has the title, company, location and the pay the employer posted, when there is one. Use the jk value in each job link as the job's ID. In our benchmark, String got all 5 attempts on indeed.com. Browserbase got 0 of 5, and Bright Data got 3 of 5.

How much does it cost to scrape job postings every day?

Checking 100 search pages daily is about 3,000 requests a month. At the standard rate on the Starter plan ($20 a month, $0.30 per 1,000) that's $0.90 in usage. Some job board fetches in our tests were billed at the premium proxy rate ($3.00 per 1,000), which would make it $9. Structured extraction adds a fee per request. See pricing. Failed requests aren't billed.

Is it legal to scrape job boards?

Job postings are public pages that employers publish to be seen. In hiQ v. LinkedIn, the court held that scraping public pages isn't unauthorized access under the CFAA, but hiQ still lost because it had accepted LinkedIn's user agreement. Collect public pages while logged out, leave personal data like recruiter names out, keep your request rate reasonable, and check with your counsel. We go through the case in What is the hiQ vs LinkedIn ruling?

How do I avoid getting blocked when scraping job boards?

Send each request to String instead of the site. Proxy rotation, browser fingerprints, captcha solving and retries happen behind the endpoint, and JavaScript rendering is switched on per request for pages that need it. Requests that still fail aren't billed.

Can I get salary data from job postings?

Yes, when the employer posts it. Indeed shows the posted range on the job card, and Greenhouse puts it in the job description. Glassdoor and ZipRecruiter also show their own estimates, labeled as such. Keep the label with the number, so you can tell an offer from a guess.

How do I scrape jobs from Greenhouse, Lever or Workday career pages?

Greenhouse and Lever serve public job feeds as JSON, so one fetch returns a company's whole board. Workday career sites load their jobs with JavaScript. Set executeJS, or use XHR capture to get the JSON the page requests.

Can I scrape jobs that need a login?

Yes, on accounts you're allowed to use. Save the login in a browser context and connect Playwright or Puppeteer to String's remote browser over CDP. Logging in means accepting the site's terms, so read them first.

Does String work on the job boards I need?

Send us the URLs and we'll run them and show you what comes back before you commit. Ask for a free sample of job data, or test them yourself with your first 5,000 free requests.

Send us the sites you can't get.

We'll show you what comes back.

© 2026 StringEU and UK GDPR Article 27 representative — appointment verified by EuverifyBuilt in New York City 🗽 🍎