Live job listings data

Hiring data you can actually compare.

Point /extract at a careers page or job board and get back title, compensation, location, and remote policy, matched to your schema and normalized across every source. Build a jobs aggregator or a hiring-signals feed from the live web with no scraper to maintain. The extraction happens inside the call.

Title, comp, location, and remote policy in one callNormalized to one schema across every boardLive web on every call, no stale crawlVerify any field against the source posting
job.ts
import Tabstack, { APIError } from '@tabstack/sdk'

const client = new Tabstack()

// Any job posting in, a structured row out.
try {
  const job = await client.extract.json({
    url: 'https://careers.example.com/jobs/eng',
    json_schema: {
      type: 'object',
      properties: {
        title: { type: 'string' },
        company: { type: 'string' },
        location: { type: 'string' },
        remote: { type: 'boolean' },
        employment_type: { type: 'string' },
        salary_min: { type: 'number' },
        salary_max: { type: 'number' },
        currency: { type: 'string' },
        skills: { type: 'array' },
        posted_at: { type: 'string' },
      },
    },
    effort: 'standard',
  })

  console.log(job) // normalized
} catch (err) {
  if (!(err instanceof APIError)) throw err
  console.error(err.status, err.message)
}

The old way

Every job board is a different shape.

Postings live on hundreds of boards and bespoke career sites, each with its own layout and its own way of writing salary and location. A DIY scraper needs a parser per source and normalization glue on top, and it breaks every time a board ships a redesign or an anti-bot wall.

A parser per board

  • Hundreds of layouts, each with its own structure
  • Comp and location written a different way every time

Constant normalization

  • Glue code to reconcile fields across sources
  • Breaks on every redesign or anti-bot wall

/extract/json

One schema across every board and careers page.

Define the job shape once (title, comp range, location, remote, skills, posted date) and point /extract at any board or company careers page. The same call normalizes fields across sources with no per-site parser, so a salary range or a remote flag comes back the same shape everywhere. Run it across a URL list to build an aggregator.

Features

  • One schema across every board and layout
  • Normalized comp, location, and remote fields
  • Skills and posted-date parsing built in
  • Run across a URL list to build a feed
job.ts
TypeScript
import Tabstack, { APIError } from '@tabstack/sdk'

const client = new Tabstack()

// Any job posting in, a structured row out.
try {
  const job = await client.extract.json({
    url: 'https://careers.example.com/jobs/eng',
    json_schema: {
      type: 'object',
      properties: {
        title: { type: 'string' },
        company: { type: 'string' },
        location: { type: 'string' },
        remote: { type: 'boolean' },
        employment_type: { type: 'string' },
        salary_min: { type: 'number' },
        salary_max: { type: 'number' },
        currency: { type: 'string' },
        skills: { type: 'array' },
        posted_at: { type: 'string' },
      },
    },
    effort: 'standard',
  })

  console.log(job) // normalized
} catch (err) {
  if (!(err instanceof APIError)) throw err
  console.error(err.status, err.message)
}
watch.ts
TypeScript
import Tabstack, { APIError } from '@tabstack/sdk'

const client = new Tabstack()

// store and notify are your own storage and alerting.
try {
  // Snapshot a careers page and diff to catch new roles.
  const page = await client.extract.markdown({
    url: 'https://careers.example.com',
    effort: 'standard',
  })

  const prev = await store.get('careers-example')
  if (page.content !== prev) {
    await store.set('careers-example', page.content)
    await notify('New activity on Example careers page')
  }
} catch (err) {
  if (!(err instanceof APIError)) throw err
  console.error(err.status, err.message)
}

/extract/markdown

Snapshot careers pages to catch new roles.

Structured rows capture each posting; a full-page snapshot captures the change. Grab a company careers page as clean markdown on a schedule, diff it against the last snapshot, and surface a new opening the day it goes live, a hiring signal for sales, recruiting, or market research.

Features

  • Clean full-page markdown for change tracking
  • Diff over time to catch new roles
  • Run on a schedule and alert on change
  • A hiring signal for sales and recruiting

Try it live

Normalize a live job posting.

Paste a job posting URL and get a schema-matched record back from a real /extract/json call. The result is cached in your browser.

Runs a live /extract/json call and normalizes the posting to one schema.

Own it vs. buy it

Own the pipeline instead of licensing a jobs feed.

A licensed jobs feed covers the boards the vendor indexes and lags the postings on the actual pages. Build the extraction step on a handful of calls, pull exactly the sources you care about, refresh whenever you want, and own the pipeline.

Jobs feed vendor

  • Only the boards the vendor indexes
  • Postings that lag the live careers page
  • A pipeline you cannot inspect or extend

Licensed feed

Build on Tabstack

owned
  • Usage-based credits across five endpoints
  • Pull exactly the sources you need, refresh anytime
  • Open every source and verify the posting yourself
usage-basedyou own it

Who builds on this

Teams that build hiring data without a jobs feed.

Job board & aggregator engineers

One schema across every board, no parser per source.

Sales & recruiting teams

A hiring signal the day a role goes live.

Market researchers

Labor-market data straight to the warehouse.

Agents

A live job lookup inside a workflow.

Mozilla-backed

Privacy, Transparency, and Control

When you build on /research, your users' questions and the data behind every answer stay yours. Tabstack is a Mozilla-backed platform, and we handle live-web research responsibly, so you can ship features your users actually trust.

Private by default.Queries and retrieved pages are used to build your answer and support you, then purged. Never sold, never used to train models.

Verifiable by design.Every answer returns source URLs and inline citations, so you and your users can confirm exactly where each claim came from.

Yours to control.You set the mode, scope, and depth of every call. No retained corpus, no lock-in, just clean, cited data you own.

See exactly how we source and handle data in the documentation.

Mozilla Manifesto

Pricing & Plans

All prices in USD.

Free Trial

Every new account includes 10,000 free credits to explore the full platform.

Starter

$10/ month

100,000 credits included

  • Access to all API endpoints
  • Fast research mode
  • Standard rate limits
  • $0.30 / 1k credits overage

For tinkerers & hobbyists who want to simply connect their systems to the internet.

Get Started

Team

$99/ month

500,000 credits included

  • Everything in Starter, plus:
  • Fast + Balanced research modes
  • Increased rate limits
  • $0.30 / 1k credits overage

Low-latency, predictable cost automation so you can focus on your core product.

Get Started

Pro

$499/ month

3,000,000 credits included

  • Everything in Team, plus:
  • Highest rate limits
  • $0.25 / 1k credits overage

For teams deploying and managing production workloads efficiently at scale.

Get Started

Enterprise Plan

Need Custom Pricing?

Custom API quotas, dedicated support, and SLAs for high-volume teams.

Contact Sales

Cost per action

Every endpoint bills in credits. Extract and Generate are a single action per call. Automate and Research run a variable number of actions per task, so cost scales with the work they do.

  • Extract (Markdown)10 credits
  • Extract (JSON)50 credits
  • Generate100 credits
  • Automate100 credits
  • Research (Fast)250 credits
  • Research (Balanced)350 credits

Add a board without writing a parser.

Start with 10,000 free credits, no card.