Back to blog

I scraped every top startup's jobs to find the best matches

How I used Meter to extract job listings from OpenAI, Anthropic, Sierra, and other top startups using Ashby's hidden API.

I've been job hunting recently, and like most people in tech, I have a list of dream companies I'd love to work at: OpenAI, Anthropic, Sierra, Ramp, Notion, Figma. The problem? Checking each company's job board every day is tedious, and I kept missing new postings.

I decided to automate this. Here's how I used Meter to scrape job listings from all these companies in one shot.

The Pattern: Ashby Job Boards

I noticed something interesting - most top startups use Ashby for their job boards. The URL pattern is dead simple:

  • OpenAI: jobs.ashbyhq.com/openai
  • Anthropic: jobs.ashbyhq.com/anthropic
  • Sierra: jobs.ashbyhq.com/sierra
  • Ramp: jobs.ashbyhq.com/ramp
  • Notion: jobs.ashbyhq.com/notion
  • Figma: jobs.ashbyhq.com/figma

If I could scrape one, I could scrape them all.

The Problem with Traditional Scraping

My first instinct was to write a BeautifulSoup scraper. But Ashby boards are JavaScript-heavy - the job listings are rendered dynamically. I'd need to fire up Selenium or Playwright, wait for the page to load, parse the DOM, and pray the CSS selectors don't change.

Then I remembered: JavaScript-heavy sites often have hidden APIs. The frontend has to get the data from somewhere.

Discovering the Ashby API

I opened the network tab in DevTools and refreshed the page. There it was - a clean JSON API returning all the job data. Title, department, location, application URL - everything I needed, in a structured format.

The problem? These APIs aren't documented. The endpoints change. Auth tokens expire. Writing a scraper against an undocumented API is fragile.

This is exactly what Meter is built for.

Extracting Jobs with Meter

I pointed Meter at OpenAI's job board and told it what I wanted to extract:

from meter_sdk import MeterClient
import os

client = MeterClient(api_key=os.getenv("METER_API_KEY"))

# Generate a strategy for Ashby job boards
strategy = client.generate_strategy(
    url="https://jobs.ashbyhq.com/openai",
    description="Extract all job postings with title, department, location, and application URL",
    name="Ashby Job Board",
    force_api=True  # Tell Meter to prioritize API extraction
)

strategy_id = strategy['strategy_id']
print(f"Strategy ID: {strategy_id}")

# Preview the jobs
print("\nOpenAI Jobs:")
for job in strategy['preview_data'][:5]:
    print(f"  {job['title']} - {job['location']}")

The force_api=True flag tells Meter to prioritize API extraction over HTML scraping. It automatically discovered the Ashby API, figured out the request format, and started pulling clean JSON data.

No Selenium. No CSS selectors. No fragile DOM parsing.

Here's what that looks like in action:

The Magic: Reusing the Strategy

Here's where Meter really shines. Since all Ashby job boards use the same API structure, I don't need to generate a new strategy for each company. I can reuse the same strategy and just swap out the URL.

ASHBY_COMPANIES = [
    "openai",
    "sierra",
    "anthropic",
    "ramp",
    "notion",
    "figma",
]

all_jobs = []

for company in ASHBY_COMPANIES:
    print(f"Fetching {company.title()} jobs...")

    # Reuse the same strategy with a different URL
    job_result = client.execute_job(
        strategy_id=strategy_id,
        url=f"https://jobs.ashbyhq.com/{company}"
    )

    for job in job_result['results']:
        job['company'] = company
        all_jobs.append(job)

    print(f"  Found {len(job_result['results'])} jobs")

This is the key differentiator. Traditional scrapers require you to write and maintain code for each site. With Meter, you generate a strategy once and run it everywhere the pattern applies.

The Results

After running this across all six companies, I had a consolidated list of every open position:

print(f"\nTOTAL: {len(all_jobs)} jobs across {len(ASHBY_COMPANIES)} companies\n")

for job in all_jobs:
    print(f"[{job['company'].upper()}] {job['title']} ({job['location']})")
    print(f"  Apply: {job['url']}\n")
TOTAL: 847 jobs across 6 companies

[OPENAI] Research Scientist (San Francisco)
  Apply: https://jobs.ashbyhq.com/openai/abc123

[ANTHROPIC] Software Engineer, API (San Francisco)
  Apply: https://jobs.ashbyhq.com/anthropic/def456

[SIERRA] Full Stack Engineer (San Francisco)
  Apply: https://jobs.ashbyhq.com/sierra/ghi789

...

Now I can filter by location, department, or keywords to find the roles that match what I'm looking for.

Going Further: Monitoring for New Jobs

The job search is ongoing, so I set up Meter to monitor these boards and alert me when new positions are posted:

# Set up monitoring for new jobs
for company in ASHBY_COMPANIES:
    schedule = client.create_schedule(
        strategy_id=strategy_id,
        url=f"https://jobs.ashbyhq.com/{company}",
        interval_seconds=3600  # Check every hour
    )
    print(f"Monitoring {company}: schedule {schedule['schedule_id']}")

Now Meter checks each board hourly and notifies me only when something changes. No more manual refreshing.

Takeaways

The hidden API pattern is everywhere. Any site with dynamic content is fetching data from somewhere, and that data is usually cleaner and more reliable than parsing HTML.

Meter's force_api=True flag makes this easy - point it at a page, tell it what you want, and it figures out the API extraction automatically.

The strategy reuse is what makes this scalable. Once you understand a pattern (like Ashby job boards), you can apply the same strategy across dozens of sites without regenerating anything.

Try It Yourself

Want to run this yourself? Check out the example script on GitHub or sign up for Meter at meter.sh.

Have questions? Reach out at mckinnon@meter.sh.

Happy job hunting!