ScrapeField
A company that posts a role has a need, and money set aside for it. If you sell to the team that role joins, a job posting is the clearest signal you will get. This guide turns a LinkedIn job search into a list of companies, ranked by how many roles each one has open, with each company’s size, industry and website.
The search
GET /v1/linkedin/jobs takes a query and a location, and returns up to 25 postings a page. Each has a title, a location, a listed_at and a company with its name and the url of its LinkedIn page. A page costs 3 credits. Pass meta.next_cursor back as cursor for the next one.
const headers = { Authorization: `Bearer ${process.env.SCRAPEFIELD_KEY}` };
const companies = new Map(); // each company's LinkedIn page, and the roles it posted
let cursor = null;
for (let page = 0; page < 4; page++) { // up to 100 postings
const params = new URLSearchParams({ query: 'data engineer', location: 'Berlin' });
if (cursor) params.set('cursor', cursor);
const res = await fetch(`https://api.scrapefield.com/v1/linkedin/jobs?${params}`, { headers });
const body = await res.json();
if (!res.ok) { console.error(body.error.code); break; } // a failed call is not charged
for (const job of body.data) {
if (!job.company.url) continue; // posted by a company with no LinkedIn page
// one company can come with a country's own host and with www's: the path is the same
const page = new URL(job.company.url).pathname.replace(//$/, '');
const seen = companies.get(page) ?? { name: job.company.name, url: job.company.url, postedRoles: [] };
seen.postedRoles.push(job.title ?? 'untitled');
companies.set(page, seen);
}
cursor = body.meta.next_cursor;
if (!cursor) break;
}Who they are
GET /v1/linkedin/company takes the company page’s url and returns the page: its industry, its company_size as LinkedIn prints the band, how many members list it as their employer in employees_on_linkedin, its website and its headquarters. A company costs 3 credits.
const rows = [];
for (const c of companies.values()) {
const res = await fetch(`https://api.scrapefield.com/v1/linkedin/company?url=${encodeURIComponent(c.url)}`, { headers });
const body = await res.json();
if (!res.ok) { console.error(c.name, body.error.code); continue; }
const { industry, company_size, employees_on_linkedin, website } = body.data;
rows.push({ company: c.name, openRoles: c.postedRoles.length, postedRoles: c.postedRoles.join('; '), industry, company_size, employees_on_linkedin, website });
}
rows.sort((a, b) => b.openRoles - a.openRoles);
for (const r of rows) console.log(`${r.company}: ${r.openRoles} open (${r.postedRoles}), ${r.company_size ?? 'size unknown'}, ${r.website ?? 'no website'}`);Reading the list
Three open roles of the same kind often mean a team is being built. One posting may only replace someone who left. Size changes the conversation too: a company of 30 hiring its first data engineer needs different things from a company of 5,000 hiring its fortieth.
A posting stays up for weeks, so the same companies come back each time. Run the search once a week and keep each job_id you have seen: a company with a job_id you have not seen is news. The search cannot yet filter by when a role was posted, so the ids are the way to tell.
What it costs
Four pages of search are 12 credits. If they name 50 companies, their pages are 150 credits, so 162 credits in all, about $0.13 on the smallest pack. A company page is cached for a day: asked for again the same day, it comes back at once, at the same price. For a whole list of companies, run several calls side by side, up to your limit of calls at once.
For the salary and the full text of a role, fetch the posting itself: LinkedIn job postings with full descriptions shows how.