Obscura

Job Postings

Open job-posting counts for a curated set of companies, captured over time.

job_postings — the dataset name to pass to the Obscura API.

Category Corporate Columns 6 Refresh Daily Entity key ticker Point-in-time available_date

What one row means

One curated public company's open-requisition count on its public Applicant Tracking System (ATS) board (Greenhouse or Lever), as scraped on a given calendar day — the row IS the snapshot, not a report of an event that happened earlier.

One row per (ticker, captured_date).

Point-in-time availability

Every Obscura dataset carries available_date: the calendar day the publisher made the row available, day-of, with no session rounding. It is the one column a backtest filters on, and it means the same thing on every dataset in the catalog.

For job_postings: snapshot: available_date = captured_date, a STORED GENERATED column. WHY THAT IS THE DAY IT BECAME AVAILABLE: the Greenhouse/Lever board APIs serve the CURRENT requisition list and keep no history, so the open-jobs count for a past day cannot be fetched — the day the collector scraped the board is the day that count was obtainable. The column was called `posted_on` until migration 000205: it never held the day a vacancy was posted, it held the day WE looked, and the name made an availability audit classify it as a source date.

Refresh cadence

Obscura refreshes job_postings daily — the most frequent scheduled job that re-collects or re-exports it. This is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when a row became public is recorded per row in available_date.

Schema — 6 columns

The full public column list for job_postings, with the meaning of every field. The same schema is served unauthenticated at https://api.obscura.trade/v1/catalog/job_postings.

ColumnTypeDescription
tickertext · not nullStock ticker of the curated public company whose ATS board was scraped (e.g. COIN, DASH, ABNB, GTLB, DDOG, NET, AFRM, NFLX). Sourced from the hardcoded BOARDS list in job_postings.rs, not looked up dynamically; half of the primary key with captured_date.
captured_datedate · not nullThe calendar day the collector SCRAPED the board and captured the open_jobs count, set to `Utc::now().date_naive()` once per task run. Other half of the primary key with ticker; the ON CONFLICT target for upsert, and the column available_date is generated from — the ATS APIs serve only the current requisition list, so the day we looked is the day the count was obtainable. NOT the day any vacancy was posted, which the column's old name (`posted_on`, until migration 000205) wrongly implied.
sourcetext · not nullWhich ATS platform's API served this board's job list: 'greenhouse' (boards-api.greenhouse.io) or 'lever' (api.lever.co). Set from Source::label() in job_postings.rs; determines the parsing shape used (Greenhouse returns an object with a `jobs` array, Lever returns a bare array).
board_tokentext · not nullThe company's slug/token on its ATS platform, used to build the API URL (e.g. 'coinbase' -> boards-api.greenhouse.io/v1/boards/coinbase/jobs, 'netflix' -> api.lever.co/v0/postings/netflix). Hardcoded per-ticker in the BOARDS const in job_postings.rs; a renamed or retired token causes a 404 which is logged and skipped rather than failing the whole run.
open_jobsinteger · not nullCount of currently open requisitions on the company's public ATS board at scrape time — the length of the `jobs` array (Greenhouse) or the top-level array (Lever) returned by the API with `content=false`/`mode=json` (job listing metadata only, no descriptions fetched). This is the hiring-intensity signal itself, not a rate or delta; comparing open_jobs across consecutive captured_date rows for the same ticker is how a caller derives net-hiring trend.
available_datedatePUBLIC-availability date = the scrape day, generated directly from `captured_date`. DB-generated, read-only; a live snapshot has no separate 'period' it describes — the point-in-time column to filter/join on.

Access job_postings

Two delivery paths, one identifier. Both require an Obscura account and an active subscription; the catalog entry and the schema above are public.

import obscura

client = obscura.Client("obs_live_…")

df = client.query(
    dataset="job_postings",
    symbols=["NVDA", "AAPL"],
    start="2024-01-01",
)

Create a free account Browse all 95 datasets

Frequently asked questions

What is in the job_postings dataset?

Open job-posting counts for a curated set of companies, captured over time. One curated public company's open-requisition count on its public Applicant Tracking System (ATS) board (Greenhouse or Lever), as scraped on a given calendar day — the row IS the snapshot, not a report of an event that happened earlier.

How do I avoid look-ahead bias with job_postings?

Filter on job_postings.available_date, the day the publisher made the row public. For this dataset that date is derived as follows — snapshot: available_date = captured_date, a STORED GENERATED column. WHY THAT IS THE DAY IT BECAME AVAILABLE: the Greenhouse/Lever board APIs serve the CURRENT requisition list and keep no history, so the open-jobs count for a past day cannot be fetched — the day the collector scraped the board is the day that count was obtainable. The column was called `posted_on` until migration 000205: it never held the day a vacancy was posted, it held the day WE looked, and the name made an availability audit classify it as a source date. A query of the form WHERE available_date <= '<as-of date>' never sees a row before it existed.

In what formats can I get job_postings?

As a Parquet bulk export (POST https://api.obscura.trade/v1/download) or as JSON from the typed query API (POST https://api.obscura.trade/v1/query), both with dataset="job_postings". The column schema is public at https://api.obscura.trade/v1/catalog/job_postings.

Can I filter job_postings by company or symbol?

Yes. job_postings carries ticker, the column the API's symbols filter resolves against.

How often is job_postings updated?

Obscura refreshes job_postings on a daily schedule — that is the most frequent scheduled job that re-collects or re-exports the table. It is Obscura's own pipeline cadence, not the upstream publisher's release schedule; when the publisher makes a row available is described by the availability rule above, and is recorded per row in available_date.

Related datasets

Board InterlocksPairs of public companies that share a director, reconstructed from SEC insider filings: one row per (director, company … Company SubsidiariesParent-and-subsidiary lists taken from the Exhibit 21 that public companies attach to their annual report. Domain SubdomainsSubdomains discovered for each public company's domains through Certificate Transparency logs (crt.sh). Employee CountsEmployee headcount as stated in the text of 10-K annual reports. Executive CompensationExecutive pay from the Pay-versus-Performance table in proxy statements: reported and 'actually paid' compensation for t… Governance EventsGovernance events distilled from company 8-K filings and tagged by type: executive changes, auditor changes, restatement… Insider SentimentMonthly insider buying and selling per company, netted from Form 4 open-market trades: shares and dollars bought versus … O*NET Occupation DataThe O*NET database of occupations: the tasks, skills and requirements that define each job, by release version.