# Jobvite Jobs API: Get Jobvite Job Listings from JSON-LD

> Jobvite has no public jobs API, but its career pages list every job link and each job page has JobPosting JSON-LD. How to collect and parse both.

Source: https://cleanjobdata.com/articles/how-to-scrape-jobvite-job-listings
Published: 2026-11-01

TL;DR: Jobvite has no public JSON jobs API. Its hosted career page at jobs.jobvite.com lists every open job's link on one HTML page, with no pagination, and each job page carries a schema.org JobPosting JSON-LD block with the title, description, date, locations and sometimes salary. The listing has no dates, so you can only filter by age after fetching job pages. Watch for empty baseSalary placeholders, full country names, and old dates on evergreen postings.

Jobvite has no public JSON jobs API, so to get a company's Jobvite jobs, fetch `https://jobs.jobvite.com/{company}/jobs` to collect the job links, then read the schema.org `JobPosting` JSON-LD on each `https://jobs.jobvite.com/{company}/job/{id}` page. Neither request needs a key, and one listing page holds every open job.

That's the DIY route, and it works for a handful of companies you already know. If you'd rather not build and maintain a Jobvite scraper, CleanJobData already ingests ATS platforms and company career sites and serves the jobs normalized through one REST API — see the [Jobs API docs](https://cleanjobdata.com/docs/api/jobs).

## At a Glance

| | |
|---|---|
| Endpoint | `GET https://jobs.jobvite.com/{company}/jobs` (HTML) |
| Job page | `GET https://jobs.jobvite.com/{company}/job/{id}` (JSON-LD) |
| API key | None |
| Pagination | None; one page lists every job |
| Full description | JSON-LD `description` on each job page |
| Salary field | JSON-LD `baseSalary`, often empty |
| Remote | No flag; infer from title and location |

## Finding the Company Slug

Hosted Jobvite career pages live at `https://jobs.jobvite.com/{company}/jobs`, so a company at `jobs.jobvite.com/acme/jobs` has the slug `acme`. If a company's careers page sits on its own domain, look for links or requests to `jobs.jobvite.com` in the page source or the Network tab.

## Listing Jobs

```bash
curl "https://jobs.jobvite.com/acme/jobs"
```

The response is server-rendered HTML. Every job is a link of the form `href="/acme/job/o4SaAfwq"`, and the part after `/job/` is the job ID: a short alphanumeric string, not a number. Collect the IDs with a regex and dedupe them as you go.

The listing has no dates or descriptions, so everything else comes from the job pages. The page title reads "Acme Careers", which is a usable fallback for the company name.

## The Job Page and Its JSON-LD

```bash
curl "https://jobs.jobvite.com/acme/job/o4SaAfwq"
```

Each job page has a `script type="application/ld+json"` block with a `JobPosting` object. Trimmed:

```json
{
  "@context": "http://schema.org",
  "@type": "JobPosting",
  "title": "Production Partner",
  "identifier": "o4SaAfwq",
  "datePosted": "2026-05-22",
  "hiringOrganization": "Acme Mortgage",
  "employmentType": "Full-Time",
  "industry": "Branch Operations",
  "description": "<h1 style=\"margin: 0.0in;\">...</h1><p>...</p>",
  "jobLocation": [
    {
      "@type": "Place",
      "address": {
        "@type": "PostalAddress",
        "addressLocality": "Johnson City",
        "addressRegion": "Tennessee",
        "addressCountry": "United States"
      }
    }
  ],
  "baseSalary": {
    "@type": "MonetaryAmount",
    "currency": "",
    "value": { "@type": "QuantitativeValue", "minValue": "", "maxValue": "", "unitText": "Annually" }
  }
}
```

| Field | What it is |
|---|---|
| `title` | Job title |
| `identifier` | Job ID; usually the same as the URL ID |
| `datePosted` | Posting date, sometimes date only |
| `description` | Full description, HTML |
| `jobLocation` | One or more `Place` objects with `addressLocality`, `addressRegion`, `addressCountry` |
| `hiringOrganization` | Company name, as a string or an object with `name` |
| `employmentType` | For example "Full-Time" |
| `baseSalary` | Pay range with `currency`, `minValue`, `maxValue`, `unitText`, when filled in |

For the full field reference, see our [JobPosting schema guide](https://cleanjobdata.com/articles/jobposting-schema-guide). The apply page is the job URL with `/apply` added.

## Fetching Jobs (Python)

```python
import json
import re
import requests

LD_JSON = re.compile(r'<script[^>]+type="application/ld\+json"[^>]*>(.*?)</script>', re.S | re.I)

def list_jobvite_ids(company: str) -> list[str]:
    html = requests.get(f"https://jobs.jobvite.com/{company}/jobs", timeout=20).text
    ids = re.findall(rf'href="/{re.escape(company)}/job/([^"?]+)', html)
    return list(dict.fromkeys(ids))  # dedupe, keep order

def parse_job_posting(html: str) -> dict | None:
    for block in LD_JSON.findall(html):
        try:
            ld = json.loads(block)
        except json.JSONDecodeError:
            continue
        if ld.get("@type") == "JobPosting":
            return ld
    return None

def fetch_jobvite_jobs(company: str) -> list[dict]:
    jobs = []
    for job_id in list_jobvite_ids(company):
        html = requests.get(f"https://jobs.jobvite.com/{company}/job/{job_id}", timeout=20).text
        ld = parse_job_posting(html)
        if not ld:
            continue
        org = ld.get("hiringOrganization")
        places = ld.get("jobLocation") or []
        if isinstance(places, dict):
            places = [places]
        salary = ld.get("baseSalary") or {}
        value = salary.get("value") or {}
        jobs.append({
            "id": ld.get("identifier") or job_id,
            "url_id": job_id,
            "title": ld.get("title"),
            "company": org.get("name") if isinstance(org, dict) else org,
            "posted": ld.get("datePosted"),
            "description_html": ld.get("description"),
            "locations": [
                ", ".join(filter(None, [a.get("addressLocality"), a.get("addressRegion"), a.get("addressCountry")]))
                for a in ((p or {}).get("address") or {} for p in places)
            ],
            "salary_min": value.get("minValue") or None,  # "" means not set
            "salary_max": value.get("maxValue") or None,
            "salary_currency": salary.get("currency") or None,
            "salary_unit": value.get("unitText") or None,
            "url": f"https://jobs.jobvite.com/{company}/job/{job_id}",
        })
    return jobs
```

Fetch job pages a few at a time, not all at once. A board with a few hundred jobs means a few hundred page requests.

## Gotchas

**Empty salary placeholders.** `baseSalary` can be present with empty strings for `currency`, `minValue` and `maxValue`. Treat empty strings as "not published" rather than zero.

**`unitText` isn't always a schema.org value.** The format suggests `HOUR`, `DAY`, `WEEK`, `MONTH` or `YEAR`, but we've seen words like `"Annually"` on Jobvite pages. Match loosely ("hour", "annual", "year", "month") before you annualize. See the [salary extraction guide](https://cleanjobdata.com/guides/salary-data-extraction).

**`hiringOrganization` changes shape.** It can be a plain string or an object with a `name`. Handle both.

**Old dates on evergreen postings.** `datePosted` can be date-only, and reposted "General Application" style postings carry dates that are years old. Decide whether to keep jobs past a certain age; you can only check after fetching the job page, because the listing has no dates.

**Full names, not codes.** `addressCountry` is a full country name like "United States" and `addressRegion` a full state name like "Tennessee". Convert them if you store ISO codes. A job can have several `jobLocation` entries, each with its own country, so keep them all. The [location normalization guide](https://cleanjobdata.com/guides/job-location-normalization) covers the matching.

**The ID can differ between the URL and the JSON-LD.** On most boards `identifier` equals the ID in the job URL, but not on every one. Store both, or you'll match the wrong key when you compare the listing with what you've stored.

**Descriptions carry inline styles.** Descriptions can arrive with inline `style` attributes and fonts from whatever editor the recruiter used. Strip or sanitize them before you render.

**No remote flag.** Check the title and location for "remote" or "hybrid".

## Career Pages vs Jobvite's Official API

Jobvite offers APIs to its customers, with credentials issued through the employer's Jobvite account. They cover the employer's own recruiting data. For published jobs at companies you don't have that relationship with, the public career pages and their JSON-LD are the source, which is the approach above.

## When This Is Enough

For one company, a listing request plus one job page per new ID is simple, and the JSON-LD gives you clean fields without parsing the visible page.

## When It Isn't

Across many companies, you're fetching one page per job and handling empty salaries, mixed field shapes and full country names, before you add other HTML-based platforms like [iCIMS](https://cleanjobdata.com/articles/how-to-scrape-icims-job-listings) and [Taleo](https://cleanjobdata.com/articles/how-to-scrape-taleo-job-listings). See [which ATS have a public job postings API](https://cleanjobdata.com/articles/ats-public-job-postings-api-list) for how they compare.

CleanJobData reads Jobvite career pages alongside other platforms and returns one schema, with parsed salary when it's published, locations resolved to cities, states and countries, and a remote type. Try it in the [Playground](https://cleanjobdata.com/playground) or see the [API Documentation](https://cleanjobdata.com/docs).

## Skip the scraper: get this data from the CleanJobData API

If you'd rather not maintain a Jobvite collector, you can query normalized jobs from ATS platforms and company career sites with a single request. The response has structured city/state/country locations, parsed salary when the employer publishes one, a remote type, and company metadata, and you page through results with the cursor in `pagination.next_page`.

```bash
curl "https://api.cleanjobdata.com/jobs?title=engineer&domain=jobs.jobvite.com&limit=20" \
  -H "Authorization: Bearer $CLEANJOBDATA_API_KEY"
```

The `domain` filter is an exact match on the host of each job's `application_url`, so it only returns jobs whose apply link resolves to `jobs.jobvite.com`; use `company_website_url` or `employer_id` to scope to one employer instead. Coverage depends on which employers are in the dataset, so check that the companies you care about appear before you rely on it.

- [Jobs API reference](https://cleanjobdata.com/docs/api/jobs) for every filter and response field
- [Playground](https://cleanjobdata.com/playground) to run queries without writing code
- [Pricing](https://cleanjobdata.com/pricing) — the Trial is free with no card required

## FAQ

### Does Jobvite have a public jobs API?

No public JSON one. The hosted career page at `https://jobs.jobvite.com/{company}/jobs` lists every job link, and each job page has a schema.org `JobPosting` JSON-LD block you can parse. Jobvite's own APIs need credentials from the employer's account.

### Do I need to paginate the Jobvite job list?

No. The `/jobs` page lists every open job on one page, so you collect all the IDs from a single request and then fetch each job page.

### Does Jobvite include salary?

Sometimes. The JSON-LD can have a `baseSalary` with a range, currency and `unitText`, but it's often present with empty values, so check that the numbers are filled in before you use them.

### How do I get the posting date for a Jobvite job?

Read `datePosted` from the job page's JSON-LD. The listing page has no dates, and some evergreen postings carry dates that are years old.
