Skip to content

Run in a browser

Import the same package API through a bundler. The home-page demo runs the package itself. Only Ashby, Greenhouse, Lever, SmartRecruiters and Rippling currently allow the cross-origin requests needed by browser callers.

// In a frontend app, through any bundler. Same API as Node: the registry
// lives in localStorage, and board responses in the Cache API
import {
  configureCache,
  CorsError,
  listCompanyJobs,
  time,
  UnresolvedCompanyError,
  type ListedJob,
} from '@chrisdothtml/job-scraper';

configureCache({ ttl: time.hour });

export async function loadJobs(
  company: string
): Promise<ListedJob[] | 'blocked'> {
  try {
    return await listCompanyJobs(company);
  } catch (error) {
    // only some boards allow cross-origin requests. The rest work from Node,
    // so hand those off to your server
    if (error instanceof CorsError) return 'blocked';
    if (error instanceof UnresolvedCompanyError && error.blocked) {
      return 'blocked';
    }
    throw error;
  }
}

A direct board request can raise CorsError. Browser network errors before a response are indistinguishable from a CORS refusal, so the class reports a likely cause rather than proof. During discovery, UnresolvedCompanyError exposes blocked when at least one candidate request was blocked. Hand these tasks to your server when appropriate; Node does not enforce browser CORS.

Use configureCache and configureSearch; Node environment variables do not apply. Registry/search state uses localStorage with a memory fallback. Response caching uses the Cache API, and is disabled when unavailable. Exported paths are storage identifiers here, not filesystem paths.

Homepage resolution cannot read most candidate sites across origins. It can use a board-declared website, careers-domain parents and exact-name trusted lookups, but cannot verify arbitrary guessed domains. renderScrapedPosting runs without a DOM; its Markdown is not an HTML sanitizer. Apply your frontend’s sanitization policy before rendering untrusted scraped content as HTML.