# Jobs.ge Georgia Jobs Scraper (`zinin/jobs-ge`) Actor

Search Jobs.ge (Georgia, the country's oldest job board) and get public job listings: title, employer, published date, application deadline, URL. Unofficial, independent tool — not affiliated with, endorsed by, or sponsored by Jobs.ge.

- **URL**: https://apify.com/zinin/jobs-ge.md
- **Developed by:** [Tim Zinin](https://apify.com/zinin) (community)
- **Categories:** Jobs, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 job founds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Jobs.ge Georgia Jobs Scraper

Jobs.ge is Georgia's oldest and largest job board. This Actor pulls its entire current listing — every open role live on the site right now — and returns one row per posting: title, employer, published date, application deadline and a direct link. No login, no browser, no proxies.

### What you get

- **The whole current listing in one call.** Jobs.ge keeps its full live batch (roughly 300 open roles) on a single page — this Actor fetches it once per run, then filters and caps it for you.
- **Keyword matching against real titles.** Give it one or more search terms and it returns only the postings whose title matches — each matched row also tells you which of your terms it matched.
- **Application deadlines, not just posting dates.** Jobs.ge publishes both a "Published" and a "Deadline" date for every posting; this Actor resolves both into proper ISO timestamps (the source itself never prints a year — this Actor works it out from its own clock).
- **Optional full description.** Turn on one setting and this Actor also visits each matched job's own page for the free-text posting body — off by default so a run stays fast.
- **Honest "no results."** A search whose keyword matched nothing pushes a `found: false` row with no error — a search the source failed to answer pushes `found: false` with a real error message. The two never look the same.
- Runs on Apify: schedule it, monitor it, call it from the API or the MCP server, export to JSON, CSV or Excel, or push results straight into your own pipeline.

### How to run it

1. Click **Try for free** — no card needed on the free plan.
2. Paste your search terms into **Search keywords**, one per line — e.g. `manager`, `driver`. Leave it empty to get the current listing unfiltered.
3. Press **Start**. Results appear in the dataset — read them in the UI, pull them from the API, or have a webhook push them onward.

### Pricing

Pay-per-event: $0.005 per run start plus $0.002 per job row found.

A keyword that matched nothing, or a request the source failed to answer, is still logged with `found: false` and the reason — and it is **not** charged for. You pay for jobs actually delivered, not for attempts.

### Input

| Field | Required | What it does |
|---|---|---|
| `keywords` | no | Search terms matched against job titles, e.g. `manager`, `driver`. Up to 10 per run. Matching happens against the already-downloaded full listing — leave empty to get the current listing unfiltered. |
| `language` | no | Which Jobs.ge interface to read — English (`en`) or Georgian (`ge`). Most postings are written in Georgian regardless of interface language, which is a fact of the source, not something this Actor translates. |
| `max_items` | no | Job rows to return at most, after keyword filtering (default 30, max 320 — the entire live listing is roughly 300 rows, so there is nothing more to cap toward). |
| `fetch_full_description` | no | Visit each matched job's own page for the full description text (slower — one extra request per job). Off by default; without it, `description` is `null` — Jobs.ge's listing page carries no snippet at all, not even a teaser. |

```json
{
    "keywords": [],
    "language": "en",
    "max_items": 5,
    "fetch_full_description": false
}
```

### Output

One dataset row per job found. This is a real row from a real run (`ZuASCyem8yCiRPjZ1`, 2026-08-01, default settings, no keyword filter):

```json
{
    "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,
    "country": null,
    "employment_type": null,
    "posted_date": "2026-07-30T00:00:00.000Z",
    "salary_raw": null,
    "description": null,
    "description_is_teaser": null,
    "source_board": "jobs-ge",
    "scraped_at": "2026-08-01T05:07:38.919Z",
    "deadline_date": "2026-08-30T00:00:00.000Z",
    "matched_keywords": []
}
```

| Field | What it means |
|---|---|
| `found` | Whether this row is a real job (`true`) or a notice/error row (`false`) |
| `url` | Direct link to the job posting — the unique key for this row |
| `job_id` | Jobs.ge's own job identifier |
| `title` | Job title |
| `company` | Hiring company name, or `null` — some posters hide the company name entirely |
| `company_url` | Link to the company's own profile page on Jobs.ge, or `null` when the poster is anonymous |
| `location` | Always `null` — Jobs.ge does not publish a structured location field anywhere on this source |
| `country` | Always `null` — same reason |
| `employment_type` | Always `null` — same reason |
| `posted_date` | ISO 8601 timestamp. Jobs.ge never prints a year on this date — this Actor reconstructs it from the run's own clock, so it is never off by more than the wrap of a single year boundary |
| `salary_raw` | Almost always `null` — Jobs.ge essentially never publishes a structured salary field (it occasionally appears buried inside free-text description, which this field does not read); this Actor never estimates or invents a figure |
| `description` | Free-text posting body, up to 600 characters — only populated when `fetch_full_description` is on, otherwise `null` (the listing page itself carries no snippet, not even a teaser) |
| `description_is_teaser` | Always `false` when `description` is set — Jobs.ge's own detail page gives the real posting text directly, no teaser step |
| `source_board` | Always `"jobs-ge"` |
| `scraped_at` | When this Actor fetched the row |
| `deadline_date` | ISO 8601 timestamp of the posting's application deadline, or `null` if unparseable. Jobs.ge prints this alongside the posted date with the same no-year quirk |
| `matched_keywords` | Array of your search keywords that matched this row's title — empty when you searched with no keyword filter at all |
| `partial` / `partial_reason` | Only present when `fetch_full_description` is on and that one job's own page failed to load, or loaded with no recognizable posting body (some ads on the English interface are Georgian-only, and Jobs.ge's own detail page says so rather than showing text) — the row is still delivered and billed with the listing-page data, just flagged as incomplete |

A keyword that matched nothing pushes:

```json
{ "input": ["zzznonexistentjobtitle999xyz"], "found": false, "error": "", "source_board": "jobs-ge", "scraped_at": "..." }
```

A request Jobs.ge failed to answer (verified live: an excessively long keyword trips the source's own request-line length limit) pushes an error row with a non-empty `error` (e.g. `"http 414"`) — never the same shape as "no matches."

### API

Start a run with a bearer token and explicit JSON input:

```bash
curl -sS -X POST 'https://api.apify.com/v2/acts/zinin~jobs-ge/runs?waitForFinish=60' \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"keywords":[],"language":"en","max_items":5,"fetch_full_description":false}'
```

Read Dataset rows using the returned `defaultDatasetId`:

```bash
curl -sS "https://api.apify.com/v2/datasets/$DEFAULT_DATASET_ID/items?clean=true&format=json" \
  -H "Authorization: Bearer $APIFY_TOKEN"
```

### MCP

For an Apify MCP client exposing the standard `call-actor` tool, send this exact payload:

```json
{
  "name": "call-actor",
  "arguments": {
    "actor": "zinin/jobs-ge",
    "input": {
      "keywords": [],
      "language": "en",
      "max_items": 5,
      "fetch_full_description": false
    }
  }
}
```

### Related Actors

Tools for the same "moving to or hiring in Georgia" workflow — the housing side of a
relocation, or a company that hires globally through a standard ATS instead of Jobs.ge.

| Actor | Use it when |
|---|---|
| [SS.ge Georgia Real Estate Listings](https://apify.com/zinin/ss-ge-tbilisi) | Someone job-hunting on Jobs.ge is also apartment-hunting for the move — SS.ge is Georgia's equivalent listings site for that half of relocation research. |
| [Job Postings Aggregator](https://apify.com/zinin/job-postings-aggregator) | A multinational's Tbilisi office is more likely to post openings on its global Greenhouse/Lever/Ashby board than on Jobs.ge — check there too. |
| [Company Hiring Radar](https://apify.com/zinin/company-hiring-radar) | You have one specific employer in mind and want a scored hiring signal, not a keyword search across the whole listing. |

### FAQ

**Does it need an API key / login?** No — it reads Jobs.ge's public, server-rendered listing page.

**Why is `location` / `country` / `employment_type` / `salary_raw` always `null`?** Because Jobs.ge does not publish structured fields for any of them, on either the list or the detail page — verified across the live listing. This Actor never guesses a value from free text inside the description.

**Why does `keywords` sometimes return 0 rows when Jobs.ge shows ~300 live postings?** Jobs.ge's own `keywords=` URL parameter does not filter server-side (verified live) — this Actor downloads the full current listing once, then matches your keyword against job titles client-side. A term that doesn't appear in any current title genuinely returns nothing; it is not a fetch failure.

**Are postings in English?** Interface language (`en`/`ge`) only changes which language Jobs.ge's own labels and dates are shown in — the postings themselves are predominantly written in Georgian either way. That is Jobs.ge's own behavior, not a translation gap in this Actor.

**How fresh is the data?** Live at run time — every call fetches Jobs.ge's current listing page.

**Can I call it from an AI agent?** Yes — standard Apify Actor, callable from the Apify API, the SDK, or the Apify MCP server.

**What this is NOT.** It does not apply to jobs on your behalf, does not cover job boards outside Jobs.ge, and does not invent a salary figure when the source has none.

Found a wrong result, or need a check we don't run? Open an issue on this Actor's page.

### Machine use

The Actor is callable through the Apify API, SDK, and Apify MCP server. The input and Dataset row are the machine-facing contract; `location`/`country`/`employment_type`/`salary_raw` are always `null` because Jobs.ge itself never publishes structured values for them — an agent should not read `null` here as a fetch failure.

***

Built by [zinin](https://apify.com/zinin). Questions? Telegram [@timzinin](https://t.me/timzinin).

# Actor input Schema

## `keywords` (type: `array`):

Words/phrases to match against job titles, filtered CLIENT-SIDE after downloading the full listing (Jobs.ge's own `keywords=` URL parameter does NOT filter server-side — verified live). Leave empty to get the whole current listing, capped by "Max items". Runtime cap: 10 keywords.

## `language` (type: `string`):

Which Jobs.ge interface to read: English (/en/) or Georgian (/ge/). Most postings are written in Georgian regardless of interface language — that is a fact of the source, not a translation this Actor performs.

## `max_items` (type: `integer`):

How many job rows to return at most (after keyword filtering, if any).

## `fetch_full_description` (type: `boolean`):

Visit each matched job's detail page for the full description text (slower — one extra request per job). When off, description is null (Jobs.ge's listing page carries no description snippet at all, not even a teaser).

## Actor input object example

```json
{
  "keywords": [],
  "language": "en",
  "max_items": 5,
  "fetch_full_description": false
}
```

# Actor output Schema

## `results` (type: `string`):

API URL for the default dataset items produced by this run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [],
    "language": "en",
    "max_items": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/jobs-ge").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keywords": [],
    "language": "en",
    "max_items": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("zinin/jobs-ge").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [],
  "language": "en",
  "max_items": 5
}' |
apify call zinin/jobs-ge --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=zinin/jobs-ge",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/VtmKAvJwKUr1xawm3/builds/3cJHJviGU4yqppGOd/openapi.json
