DEV Community

Cover image for How to Scrape jobs.ge Postings in Georgia Without a Paid API
Tim Zinin
Tim Zinin

Posted on Originally published at apify.com

How to Scrape jobs.ge Postings in Georgia Without a Paid API

The problem

Jobs.ge is Georgia's oldest job board, and for anyone tracking the Georgian labor market — a recruiter sourcing candidates, an analyst watching hiring trends, an aggregator building a job feed — it is the primary public source. But there is no API. The manual alternative is opening listing pages in a browser, clicking into every posting, and copying titles, employers and dates into a spreadsheet, re-doing the whole thing the next day to catch new postings.

Two details make hand-collection worse than it looks. Jobs.ge prints its "Published" and "Deadline" dates without a year — a human has to infer it, and gets it wrong around year boundaries. And the board mixes Georgian and English interface labels with predominantly Georgian posting text, so ad-hoc parsing scripts silently misread dates and filters. A scraper that handles the site's quirks correctly is a small project of its own.

What the actor does

The Jobs.ge Georgia Jobs Scraper searches Jobs.ge's public, server-rendered listing pages — no login, no API key — and returns one structured row per job found. You can narrow the search with:

  • Category and location filters using Jobs.ge's own classification — categories such as it_programming, sales_procurement or medicine_pharmacy, and location groups including Tbilisi, regions, remote and abroad;
  • Title keywords (up to 10 per run) matched against real posting titles — each row reports which of your terms matched;
  • Publication date window (posted_within_days, 1–365 UTC calendar dates), applied before the result cap.

For every job the row carries title, company and company_url (null when the poster hides them), the direct posting url and job_id, location as the explicit source label beside the title (never inferred from description text), and both timestamps — posted_date and deadline_date — resolved into proper ISO 8601. That last point matters: the source never prints a year, and the actor reconstructs it from its own clock rather than leaving you to guess.

The actor follows pagination up to a 20-page safety limit, deduplicates job IDs, and confirms your selected filters on every scanned page. Each result states listing_pages_fetched, listing_pages_available, listing_scan_complete and listing_stop_reason, so you can tell a complete scan from a partial one. If a later page fails or filters are lost, useful rows are marked partial and a free diagnostic row explains the incomplete search.

An optional fetch_full_description setting visits each matched job's own page for the free-text posting body (off by default — the listing page itself carries no snippet, not even a teaser, so description is null without it). An optional fetch_job_category lookup confirms category membership against Jobs.ge's own category listings within bounded extra requests.

"Nothing found" is honest: a keyword that matched nothing pushes a found: false row with an empty error, while a request the source failed to answer pushes found: false with a real error message — the two never look the same, and neither carries a result fee.

Example: input and output

{
    "keywords": [],
    "language": "en",
    "max_items": 5,
    "fetch_full_description": false
}
Enter fullscreen mode Exit fullscreen mode

A real row from a real run with default settings:

{
    "found": true,
    "url": "https://www.jobs.ge/en/?view=jobs&id=741288",
    "job_id": "741288",
    "title": "Cashier-Consultant",
    "company": "Way Mart",
    "company_url": "https://www.jobs.ge/en/?view=client&client=way-mart",
    "location": null,
    "posted_date": "2026-07-30T00:00:00.000Z",
    "salary_raw": null,
    "description": null,
    "source_board": "jobs-ge",
    "scraped_at": "2026-07-30T14:22:28.264Z",
    "deadline_date": "2026-08-30T00:00:00.000Z",
    "matched_keywords": []
}
Enter fullscreen mode Exit fullscreen mode

Note salary_raw: null — Jobs.ge essentially never publishes a structured salary field, and the actor never estimates or invents a figure.

Pricing and the free limit

Pay per event: $0.005 per run start plus $0.002 per job found. No-match notices, source errors and unconfirmed filter diagnostics produce found: false rows with no result fee; only the separate start fee applies.

Apify's free plan gives $5 of usage credits per month. At this tariff, $5 covers up to 2,497 job rows in a single run (0.005 + 0.002 × 2,497 ≈ $5.00) — or about 24 runs of 100 jobs each at $0.205 per run.

Try it

Pick a category or just press Start with the prefilled input: Jobs.ge Georgia Jobs Scraper

For AI agents and MCP

The actor takes JSON in and returns structured JSON dataset rows via the Apify API, so an agent can start a run, read the dataset, and branch on the found flag and scan metadata (listing_scan_complete, listing_stop_reason) before trusting a zero-result answer. The README notes it is a standard Apify Actor callable from the Apify API, the SDK, or the Apify MCP server, and documents the MCP server setup alongside JavaScript, Python and CLI examples.

Top comments (0)