All posts
Insights

How to measure remote hiring share

The query that answers it, and the ways it still lies to you: two remote fields, sparse classifiers, provenance mix, and the archive tail.

HyperJobs Team7 min read

"What share of software jobs are remote" is a two-request question. Both requests are limit=1, because you only want total:

BASH
# Numerator: remote software postings in the last 30 days.
curl -G https://api.hyperjobs.io/v1/jobs \
  -H "Authorization: Bearer $HYPERJOBS_KEY" \
  --data-urlencode "taxonomies=Software" \
  --data-urlencode "work_arrangement=Remote" \
  --data-urlencode "time_frame=30d" \
  --data-urlencode "limit=1"
 
# Denominator: all software postings in the same window.
curl -G https://api.hyperjobs.io/v1/jobs \
  -H "Authorization: Bearer $HYPERJOBS_KEY" \
  --data-urlencode "taxonomies=Software" \
  --data-urlencode "time_frame=30d" \
  --data-urlencode "limit=1"

Divide the two totals. That is the measurement. This post is not about the answer — it is about why that answer is probably wrong, and what to do about it.

Revised 2026-07-16 for the v1 launch. The original version opened with "this API never returns a 400" and spent half its length on input traps — the AND comma, remote=true doing nothing, ISO codes matching zero rows. Those described a pre-release draft that never shipped: v1 rejects bad input with a 400 naming the parameter, commas mean OR, and country=US works. What's left is the interesting half — the mistakes that are about measurement, not syntax, and that no validator can catch for you.

Trap 1: there are two remote fields#

remote=true and work_arrangement=Remote are not the same query:

FilterReadsCan express Hybrid?
?work_arrangement=Remotejob.work_arrangement, the classificationYes — Remote, Hybrid, On-site
?remote=truejob.location.remote, a boolean on the location objectNo

They are separate signals derived from separate evidence, and they return different-sized populations — the enums reference publishes both snapshot counts, and the gap between them is wide. Neither is wrong. But "remote share" means one of them, and you have to say which.

Prefer work_arrangement. It is the classification, it is the more precise of the two, and it is the only one that can express hybrid — which is usually the interesting category. Use remote=true as well only if you want the stricter intersection, and then say that is what you measured.

Casing mistakes at least fail loud now — work_arrangement=remote is a 400 listing the real values (On-site, with the hyphen and the lower-case s, is the one people miss). The measurement mistake above produces no error at all, which is why it outranks every typo.

Trap 2: your denominator is a classifier's opinion#

Broadening the denominator is one request now — commas are OR, so taxonomies=Software,Engineering,Technology is the union, and its total (or /v1/jobs/count) counts distinct postings with no overlap arithmetic on your side.

What the union cannot fix is what the taxonomy is: a classifier output with measured coverage below 100%. A posting the classifier never tagged is in neither your numerator nor your denominator — and untagged postings are not a random sample. Widen the family list and your population changes composition, not just size; your remote share can move with it, in the direction of a conclusion, without a single error. Pick one denominator expression, write it down, and never compare shares computed over different ones.

The one comma that still intersects is skillskill=python,aws means both. If your slice is skill-defined, that is usually what you want ("Rust roles" really does mean postings tagged rust), but say so in the writeup.

Trap 3: whose location is it?#

country=US, country=United States — both work, and an unknown code is a 400. The geographic trap left is not syntax; it is that a payload carries two geographies and a share calculation must pick one.

A country slice measures the posting's location, not the employer's

?country= filters the job's location; ?company_country= filters the employer's HQ. A US-headquartered company posts roles worldwide, so the two answer different questions — and for a remote share the gap is the whole subject, since a remote role's location.countries is often a remote-from restriction rather than an office. For "remote hiring in country X" you almost certainly want the job's location; remote_location on the Job object is the finer signal when it's present.

There is still no geo search — no radius, no bounding box — though postings carry location.coords for client-side distance work.

Trap 4: the window, and what is in it without one#

/v1/jobs excludes expired postings on every query. That is the good case. The trap is what remains: the dataset reaches back years, and old rows survive when nothing forces them out. A board that quietly went dark leaves postings behind with no expiry to trigger on — coverage is explicit about this. Without a time_frame, your denominator is an archive, and archives have a different remote-work composition than the current market. That is not a finding you want to accidentally publish.

So always window it:

BASH
--data-urlencode "time_frame=30d"    # ✓ 30 days
--data-urlencode "time_frame=1week"  # ✗ 400 — must be <n><m|h|d>, m = minutes

An unparseable window is a 400 rather than a silent all-time query, so the archive can no longer sneak into your denominator through a typo — only through omission. (posted_gte/posted_lt give you fixed windows when you need two measurements to share exact bounds.)

Numerator and denominator must also come from the same endpoint. /v1/jobs and /v1/jobs/feed serve the same live population as of v1, but the feed windows on when we indexed a posting and time_frame windows on when it was posted — a ratio across the two windows is not a ratio of anything.

Trap 5: provenance mixes two populations#

Every posting carries a source_typeats for boards the employer authors, jobboard for third-party boards like LinkedIn. The current pool is roughly 616k ats to 87k jobboard, and the two populations differ in exactly the ways that bias a remote share: job-board postings skew toward roles employers chose to advertise widely, and their location fields follow the board's conventions rather than the employer's.

BASH
--data-urlencode "source_type=ats"   # employer-authored postings only

Computing your share on source_type=ats — or computing it per class and reporting both — turns an invisible composition effect into a stated choice. It's one more filter, and it's the difference between "remote share of postings" and "remote share of postings, mostly wherever LinkedIn was that month".

The trap under all of them: postings are not jobs#

Even with every parameter correct, total counts advertised postings. It does not count filled roles, headcount, or people.

An employer that files one posting per city contributes N observations for one role. If that filing style correlates with work arrangement — and there is every reason to think it might, since on-site roles are the ones with a city to enumerate — then posting counts are a biased estimator of exactly the thing you are measuring. collapse=true gives you employer × title as the unit instead, which is usually the honest denominator. Collapsing explains what it costs you.

And remember work_arrangement is a classifier output, populated from what the posting said. A remote role whose posting never says so is not in your numerator.

A defensible procedure#

  1. Fix the population first

    One time_frame, one taxonomy vocabulary, one location expression. Write the denominator query before the numerator query.

  2. Test every filter's effect before you trust it

    Typos fail loud now, but a filter can still be semantically inert — add them one at a time and watch /v1/jobs/count. A filter that doesn't move the count is measuring something you didn't mean, and the response will never say so.

  3. Change one thing between numerator and denominator

    Exactly one: the work_arrangement filter. If anything else differs, you are not measuring a share.

  4. Say which field you measured

    "Share of postings classified work_arrangement=Remote" is a claim the data supports. "Remote hiring" is not — it is an inference layered on top of a classifier, a scrape, and a filing convention.

Run the same procedure on two windows and you have a trend rather than a level, which is usually the more robust thing anyway — the biases above are largely constant across windows and mostly cancel when you difference them.

The queries are the easy part. Knowing which of the four traps ate your result is the job.