Hiring demand analysis
Measure the advertised openings observed in a defined corpus. Postings are not
completed hires, headcount growth, unique vacancies, or the entire labor market.
Setup
Set CRAWLORA_API_KEY to your key from crawlora.net.
Run the bundled scripts/crawlora.sh from this skill directory or by absolute
path. It sends x-api-key to https://api.crawlora.net/api/v1; keep the key in
the environment. Read reference/endpoints.md for
jobs search, global facets, company discovery, and posting detail.
Define the population before counting
- Specify the role/skill question, locations, providers, employment/workplace
scope, observation date, and required sample coverage. Search
/datasets/jobs/search; open roles are the default. include_closed=true
adds stored closed roles but does not reconstruct past point-in-time vacancies.
- Read
/datasets/jobs/facets?size=... for corpus context and labels. This
endpoint accepts only bucket size, not search filters. Its total_open,
remote_open, and buckets are global. Do not use them as the denominator or
skill distribution for a filtered search. Buckets are capped, not exhaustive.
- Use search fields that actually exist:
q spans title/company/description;
city, state, country, department, and job_family have their documented
matching behavior. workplace_type accepts onsite, hybrid, remote.
Skill and seniority facets are not equivalent to server-side search filters.
Inspect/classify returned rows when those dimensions define the analysis.
- Collect within the agreed bound (
page_size<=100, 10,000-result window).
Preserve posting_id, provider, employer, URL, raw location, structured fields,
posted date, open status, and available crawl timestamps. Deduplicate by posting
ID, then identify likely syndicated/reposted roles using employer, requisition,
title, location, and canonical URL. Keep ambiguous multi-location roles explicit.
- For skill demand, distinguish required, preferred, and incidental mentions;
a keyword hit in a company description is not necessarily a job requirement.
Treat
seniority_level and occupation fields as classifications, not employer
assertions. Seniority is entry, mid, or senior, with uncertain roles
assigned to mid; ambiguous occupations may lack a job_family entirely.
- For compensation, retain
compensation_min, compensation_max, currency,
period, and source wording. min_salary/max_salary require salary_currency
and match overlapping range bounds, not guaranteed pay. Currency filtering
alone does not normalize hourly/monthly/annual figures; verify period locally.
Do not annualize without explicit hours/weeks assumptions or treat base salary
as total compensation. Report pay-disclosure coverage before summaries.
- Return counts and proportions with a defined denominator: deduplicated
eligible observed postings, unique employers, or salary-disclosing rows.
Multi-skill labels can total above 100%. Label truncated samples and corpus
gaps; raw search
total is not the deduplicated population size.
scripts/crawlora.sh /datasets/jobs/facets size=10
scripts/crawlora.sh /datasets/jobs/search q="data engineer" page_size=20
Interpretation and reporting
Return query/cohort definitions, coverage and exclusions, counts by relevant
dimension, cited example postings, and limitations. A one-time snapshot describes
observed demand; trend claims require comparable dated snapshots and stable coverage.
- Structured locations can be missing while enrichment catches up. Missing is
not remote, and remote does not mean eligible from every country.
- Some providers omit employment type or posting dates. Do not equate ingestion
date with publication date or classify undated roles as newly opened.
- Historical employer visa filings, if returned, are not a role-specific promise.
Keep this contextual evidence separate from the demand analysis.
- Salary summaries describe advertised ranges among disclosing postings, not
accepted compensation or a representative wage survey. State midpoint choices.
- Back off on
429, retry transient 5xx once, stop on 401/403, and check
application code. Stop on repeated pages; research does not apply to jobs or
contact employers, and a snapshot request does not create ongoing monitoring.
1---2name: hiring-demand-analysis3description: Compare advertised hiring demand across roles, skills, locations, and seniority using Crawlora's jobs dataset. Use for labor-market snapshots, employer concentration, remote-work comparisons, and salary analyses with explicit coverage and compensation-unit controls.4---56# Hiring demand analysis78Measure the advertised openings observed in a defined corpus. Postings are not9completed hires, headcount growth, unique vacancies, or the entire labor market.1011## Setup1213Set `CRAWLORA_API_KEY` to your key from [crawlora.net](https://crawlora.net).14Run the bundled `scripts/crawlora.sh` from this skill directory or by absolute15path. It sends `x-api-key` to `https://api.crawlora.net/api/v1`; keep the key in16the environment. Read [reference/endpoints.md](reference/endpoints.md) for17jobs search, global facets, company discovery, and posting detail.1819## Define the population before counting20211. Specify the role/skill question, locations, providers, employment/workplace22 scope, observation date, and required sample coverage. Search23 `/datasets/jobs/search`; open roles are the default. `include_closed=true`24 adds stored closed roles but does not reconstruct past point-in-time vacancies.252. Read `/datasets/jobs/facets?size=...` for corpus context and labels. **This26 endpoint accepts only bucket size, not search filters.** Its `total_open`,27 `remote_open`, and buckets are global. Do not use them as the denominator or28 skill distribution for a filtered search. Buckets are capped, not exhaustive.293. Use search fields that actually exist: `q` spans title/company/description;30 `city`, `state`, `country`, `department`, and `job_family` have their documented31 matching behavior. `workplace_type` accepts `onsite`, `hybrid`, `remote`.32 Skill and seniority facets are not equivalent to server-side search filters.33 Inspect/classify returned rows when those dimensions define the analysis.344. Collect within the agreed bound (`page_size<=100`, 10,000-result window).35 Preserve `posting_id`, provider, employer, URL, raw location, structured fields,36 posted date, open status, and available crawl timestamps. Deduplicate by posting37 ID, then identify likely syndicated/reposted roles using employer, requisition,38 title, location, and canonical URL. Keep ambiguous multi-location roles explicit.395. For skill demand, distinguish required, preferred, and incidental mentions;40 a keyword hit in a company description is not necessarily a job requirement.41 Treat `seniority_level` and occupation fields as classifications, not employer42 assertions. Seniority is `entry`, `mid`, or `senior`, with uncertain roles43 assigned to `mid`; ambiguous occupations may lack a `job_family` entirely.446. For compensation, retain `compensation_min`, `compensation_max`, currency,45 period, and source wording. `min_salary`/`max_salary` require `salary_currency`46 and match overlapping range bounds, not guaranteed pay. Currency filtering47 alone does not normalize hourly/monthly/annual figures; verify period locally.48 Do not annualize without explicit hours/weeks assumptions or treat base salary49 as total compensation. Report pay-disclosure coverage before summaries.507. Return counts and proportions with a defined denominator: deduplicated51 eligible observed postings, unique employers, or salary-disclosing rows.52 Multi-skill labels can total above 100%. Label truncated samples and corpus53 gaps; raw search `total` is not the deduplicated population size.5455```sh56scripts/crawlora.sh /datasets/jobs/facets size=1057scripts/crawlora.sh /datasets/jobs/search q="data engineer" page_size=2058```5960## Interpretation and reporting6162Return query/cohort definitions, coverage and exclusions, counts by relevant63dimension, cited example postings, and limitations. A one-time snapshot describes64observed demand; trend claims require comparable dated snapshots and stable coverage.6566- Structured locations can be missing while enrichment catches up. Missing is67 not remote, and remote does not mean eligible from every country.68- Some providers omit employment type or posting dates. Do not equate ingestion69 date with publication date or classify undated roles as newly opened.70- Historical employer visa filings, if returned, are not a role-specific promise.71 Keep this contextual evidence separate from the demand analysis.72- Salary summaries describe advertised ranges among disclosing postings, not73 accepted compensation or a representative wage survey. State midpoint choices.74- Back off on `429`, retry transient `5xx` once, stop on `401`/`403`, and check75 application `code`. Stop on repeated pages; research does not apply to jobs or76 contact employers, and a snapshot request does not create ongoing monitoring.