# Google Jobs Scraper: Salaries, Apply Links & Full Descriptions (`roomy_tweet/google-jobs-scraper`) Actor

Scrape Google Jobs in 30 countries: title, company, salary (also read from the job text), date, job type, full description and direct apply links. Up to ~90 jobs per search, filters, multiple locations and an only-new-jobs mode for schedules.

- **URL**: https://apify.com/roomy_tweet/google-jobs-scraper.md
- **Developed by:** [roomy_tweet](https://apify.com/roomy_tweet) (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 $3.00 / 1,000 jobs

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Google Jobs Scraper: Salaries, Apply Links & Full Descriptions

Scrape **Google Jobs** (Google for Jobs, the jobs panel of Google Search) and get structured **job postings** for any search in 30 countries: title, company, location, posting date, job type, the **full job description**, the **direct apply links** (LinkedIn, Indeed, Glassdoor, the company's own careers page) and the **salary as numbers**. It works like a Google Jobs API: no login and no proxies to set up, results in JSON, CSV or Excel.

Google Jobs collects listings from thousands of job boards and career sites, so one search here covers what would otherwise take a dozen scrapers.

### Why this Google Jobs scraper

- **Up to ~90 jobs per search, not just the first 10.** A real browser scrolls Google's list the way a person does, until it has what you asked for or Google stops adding jobs.
- **Salary on more jobs.** When Google shows no salary, the pay stated in the posting is read from its text. On US test searches that raised salary coverage from 40% to 63% of jobs.
- **Direct apply links** to every site Google lists for the job, with Google's tracking removed. No Google redirects.
- **Full description and highlights**: qualifications, benefits and responsibilities as lists.
- **Google's own filters** (date posted, job type, remote) plus filters Google doesn't have: **only or exclude companies**, and **only or exclude source sites**. Jobs your filters remove are not charged.
- **Only new jobs** for daily or hourly schedules: you receive and pay for each job once.
- **Many locations at once**, Google Jobs URLs pasted from your browser, 30 countries, and labels read in English, Portuguese and Spanish.
- **Run report and daily quality check**, so a change on Google's side shows up as a warning, not as silently empty results.

### What you can use it for

- **Recruiting and sourcing**: follow new openings for a role, a city or your competitors' companies.
- **Job boards and aggregators**: fill a niche board with fresh postings and their original apply links.
- **Salary benchmarking**: compare pay ranges by role, city and job type with numeric `salaryMin` / `salaryMax`.
- **Labor-market research**: demand for skills, remote share, which companies are hiring where.
- **Lead generation**: companies that are hiring are companies that are growing; filter by company or job type.
- **Job alerts**: a scheduled run with Only new jobs sends you just what appeared since last time.
- **AI agents and RAG**: the compact output keeps rows small enough for an LLM.

### Quick start

1. Type your searches in **Search queries**, one per line, the way you would type them into Google: `registered nurse`, `python developer`, `warehouse associate`.
2. Optionally add **Locations** (every query runs in every location) and pick the **Country**.
3. Set **Maximum jobs per query**: 10 is fastest; more is loaded by scrolling, up to ~90.
4. Run it, then export the dataset as JSON, CSV or Excel, or read it through the API.

```json
{
  "queries": ["registered nurse", "software engineer"],
  "locations": ["Chicago, IL", "Houston, TX"],
  "country": "us",
  "maxJobsPerQuery": 50
}
```

### What you get

| Field | Example |
|---|---|
| `title`, `companyName`, `location` | Registered Nurse – ICU · Northwestern Medicine · Chicago, IL |
| `via` | Where Google found it: LinkedIn, Indeed, the employer's careers page… |
| `postedText`, `postedDaysAgo`, `postedAtApprox` | "2 days ago", 2, 2026-10-21 |
| `salaryText`, `salaryMin`, `salaryMax`, `salaryCurrency`, `salaryPeriod` | "$38.20–$57.30 an hour", 38.2, 57.3, USD, HOUR |
| `salarySource` | `google` (Google's salary label) or `description` (read from the posting text) |
| `employmentType`, `employmentTypes` | "Full-time and Part-time", \[FULL_TIME, PART_TIME] |
| `workFromHome`, `tags` | true · Health insurance, Dental insurance, No degree mentioned |
| `qualifications`, `benefits`, `responsibilities`, `highlights` | Bullet lists as Google shows them |
| `description` | The whole posting, line breaks kept |
| `applyLinks` | `[{ "title": "Apply on LinkedIn", "url": "https://www.linkedin.com/jobs/view/…", "domain": "linkedin.com" }, …]` |
| `companyLogoUrl`, `googleJobsUrl`, `jobId` | Google's posting ID, used to skip duplicates |
| `query`, `searchLocation`, `country`, `position`, `source`, `scrapedAt` | Search context and rank in Google's list |

Measured on test runs (October 2026, Google US, UK and Brazil): title, company, location, source, full description and apply links on 100% of jobs, and every apply link with its direct URL (2,313 of 2,313). Employment type on about 95% and posting date on 59–74%. Highlights on 94% of US jobs; Google did not show them for the UK and Brazilian searches tested. Salary: see [Salary](#salary-also-when-google-doesnt-show-one).

### Pricing

**$3.00 per 1,000 jobs** ($0.003 per job saved to the dataset), plus $0.00005 per GB of memory when a run starts ($0.0002 at the default 4 GB). Proxies and compute are included: you pay nothing else.

| You get | You pay |
|---|---:|
| 100 jobs | $0.30 |
| 1,000 jobs | $3.00 |
| 200 new jobs every day for a month (Only new jobs) | about $18 |

You are **not charged** for:

- a job that two of your queries both find (it is saved once);
- jobs your filters remove (company, source, job type, date, remote);
- with Only new jobs, jobs that earlier runs already delivered.

Apify's free plan includes $5 of monthly credit, enough for about 1,600 jobs. Set a maximum cost per run and the run stops by itself when it gets there.

### Search options and filters

```json
{
  "queries": ["registered nurse", "warehouse"],
  "locations": ["Houston"],
  "datePosted": "week",
  "employmentType": "PART_TIME",
  "excludeCompanies": ["Example Staffing"],
  "sources": ["LinkedIn", "Indeed"],
  "maxJobsPerQuery": 30
}
```

- **Locations**: every query is searched in every location (2 queries × 3 cities = 6 searches). A job found in two of them is saved once; `searchLocation` says where it was found.
- **Google Jobs URLs**: paste searches straight from your browser (`google.com/search?q=…&udm=8`, or a shared job link). Each keeps its own search text, Google domain and language, including filters you picked on Google. They can be mixed with queries; locations are not added to them.
- **Country** picks the Google domain (google.com, google.co.uk, google.com.br, google.de…), so jobs are local to that country. **Interface language** only changes Google's labels ("2 days ago" / "há 2 dias"); job texts stay as the employer wrote them.
- **Date posted, job type and remote** are Google's own filters. Google applies them by adding words to the search (`… part time in the last week`), in the right language for the country, and the run report shows the exact text used. Google's filters are loose (its "contract" filter also returned full-time jobs in our tests), so jobs whose labels contradict your filter are dropped. Jobs without a label are kept.
- **Only these companies / Exclude companies** match the company name as whole words, ignoring case and accents. "Amazon" matches "Amazon.com Services LLC" but not "Amazonia Foods". With an include list the whole Google list is read, since matches can be anywhere in it.
- **Only these sources** keeps jobs Google shows via that site or with an apply link to it. **Exclude sources** drops jobs Google shows via that site, e.g. aggregators you don't want.
- **Output: compact** leaves out the bullet lists and cuts the description to 500 characters (`descriptionTruncated: true`). Rows got about 77% smaller in tests (9.7 KB to 2.2 KB), handy for spreadsheets and AI agents. Salary is still read from the full text first.
- **Maximum jobs in total** caps the whole run.

What the filters returned in test runs:

- **Part-time jobs from the last week** (Houston): 33 jobs, all part-time and 7 days old or less. 9 jobs labelled full-time only were dropped and not charged.
- **Full-time jobs from the last week** (Mexico City, Spanish filters): 25 of 25 matched.
- **Remote jobs from the last 3 days**: 60 of 60 matched.
- **Three Chicago hospitals as "Only these companies"**: the whole list of 81 nursing jobs was read and the 6 from those employers were saved.

### Only new jobs, for daily schedules

Turn on **Only new jobs** and schedule the Actor. Each run remembers the jobs it saved and later runs skip them.

```json
{
  "queries": ["registered nurse"],
  "locations": ["Dallas"],
  "datePosted": "3days",
  "maxJobsPerQuery": 150,
  "onlyNewJobs": true
}
```

- The memory is a key-value store in your own Apify account (`google-jobs-history-…`), one per set of queries and filters. Give several schedules the same **History name** to share one memory. Jobs are remembered for a year; **Forget saved jobs** starts over.
- The browser keeps scrolling past jobs you already have, until it finds `maxJobsPerQuery` new ones or Google's list ends. A recent **Date posted** filter keeps that list short.
- Don't run two schedules with the same memory at the same time: the one that finishes last would overwrite what the other remembered.

In a test, two runs of the search above half an hour apart saved 89 jobs, then skipped the 71 already delivered and saved 15. Google's list is not identical from one search to the next, so "new" means **new to you**: some of those 15 had been posted 3 days earlier and simply weren't in the first run's list.

### How it works, and how many jobs per search

Google shows Jobs results 10 at a time and loads more as you scroll; there are no numbered pages.

1. **The first 10 jobs** of each query come from a single request through Apify's Google SERP proxy.
2. **More than 10**: a real Chrome browser opens Google, searches, opens the Jobs tab and scrolls until it has what you asked for or Google stops adding jobs. If Google blocks it, it tries up to two more times from other IPs; if those fail too, the query keeps its first 10 jobs and is marked `PARTIAL`.

Measured in test runs (October 2026):

| Search | Asked for | Got | Note |
|---|---:|---:|---|
| registered nurse + software engineer, Chicago | 50 each | 100 | 57 s for both |
| desenvolvedor + analista de dados, São Paulo | 40 each | 80 | 84 s for both |
| nurse, London | 150 | 91 | Google's list ended at 91 |
| data analyst, London | 150 | 94 | Google's list ended at 94 |

A volume test of 40 US searches (10 occupations × 4 cities, 20 jobs each) took 15 minutes. The first 10 jobs came back for all 40 on the first try (median 23 s, slowest 64 s). Scrolling got everything asked for, or everything Google listed, for 36 of the 39 searches that needed it; the other 3 kept their first 10. Since then a second retry from another IP was added, and the 5 searches tested afterwards all completed.

Expect **about 90–100 jobs at most per search**, because that is where Google stops adding to the list, and 20 seconds to 2 minutes of scrolling per query.

### Salary, also when Google doesn't show one

Google labels a salary on only part of the postings, while many others state the pay in their text ("Pay Range $110,000.00 - $135,000.00", "Salary: £30.80 - £35.20 per hour"). When Google shows no salary, the Actor reads it from the posting and marks it `salarySource: "description"`. It only takes an amount with a currency and a pay word or period next to it. It skips money that is something else (company revenue, bonuses, allowances, budgets, tips), and checks that the size fits the period.

Measured on 1,385 jobs from the test runs:

| Google | Salary from Google alone | With salaries read from the text |
|---|---:|---:|
| US | 40% | **63%** |
| UK | 55% | **68%** |
| Brazil, Mexico | 13%, 36% | unchanged: those postings rarely state an amount |

As an accuracy check, the same reader ran on jobs that **do** have a Google salary. Where it found an amount (310 jobs), 284 (92%) matched Google's: same period, overlapping range. Most of the others are Google converting an hourly rate to a yearly one, or showing a different band than the text. Filter on `salarySource` if you only want Google's.

### Output example

Values below are illustrative, not a real posting.

```json
{
  "jobId": "AbCdEfGhIjKlMnOpAAAAAA==",
  "title": "Registered Nurse - Medical/Surgical",
  "companyName": "Example Health",
  "location": "Chicago, IL",
  "via": "LinkedIn",
  "postedText": "3 days ago",
  "postedDaysAgo": 3,
  "postedAtApprox": "2026-10-20",
  "salaryText": "$38.20–$57.30 an hour",
  "salaryMin": 38.2,
  "salaryMax": 57.3,
  "salaryCurrency": "USD",
  "salaryPeriod": "HOUR",
  "salarySource": "google",
  "employmentType": "Full-time",
  "employmentTypes": ["FULL_TIME"],
  "workFromHome": false,
  "tags": ["Health insurance", "Dental insurance", "Paid time off"],
  "qualifications": ["Current RN license in Illinois", "BLS certification"],
  "benefits": ["Tuition reimbursement", "403(b) with match"],
  "responsibilities": ["Assess and monitor patients", "Administer medications"],
  "highlights": [{ "title": "Qualifications", "items": ["Current RN license in Illinois", "BLS certification"] }],
  "description": "Example Health is hiring a Registered Nurse for our Medical/Surgical unit…\n\nWhat you will do\n• Assess and monitor patients…",
  "applyLinks": [
    { "title": "Apply on LinkedIn", "url": "https://www.linkedin.com/jobs/view/example-4400000000", "domain": "linkedin.com" },
    { "title": "Apply on Example Health Careers", "url": "https://careers.example-health.org/jobs/12345", "domain": "careers.example-health.org" }
  ],
  "companyLogoUrl": "https://encrypted-tbn0.gstatic.com/images?q=tbn:…",
  "googleJobsUrl": "https://www.google.com/search?ibp=htl;jobs&q=registered%20nurse&htidocid=AbCdEfGhIjKlMnOpAAAAAA%3D%3D",
  "query": "registered nurse",
  "searchLocation": "Chicago, IL",
  "country": "us",
  "language": "en",
  "position": 4,
  "source": "browser",
  "scrapedAt": "2026-10-23T12:00:00.000Z"
}
```

The dataset's **Overview** view shows the main columns side by side.

### Use it from the API, schedules and AI agents

Call the Actor from your code with Apify's client libraries. In Python:

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("roomy_tweet/google-jobs-scraper").call(run_input={
    "queries": ["data analyst"],
    "locations": ["Austin, TX"],
    "datePosted": "week",
    "maxJobsPerQuery": 30,
})
for job in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(job["title"], job["companyName"], job["salaryMin"], job["applyLinks"][0]["url"])
```

In JavaScript:

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('roomy_tweet/google-jobs-scraper').call({ queries: ['data analyst'], locations: ['Austin, TX'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

- **Schedules**: run it daily or hourly from Apify Console with Only new jobs on.
- **Integrations**: send results to Google Sheets, Slack, Zapier, Make or your own webhook when a run finishes.
- **AI agents**: available through Apify's MCP server like any Apify Actor; use the compact output to keep responses small.

### Run report and quality check

Each run saves a `REPORT` record in its key-value store with one line per query: jobs wanted and saved, how the first page and the scrolling went, the exact search text used, and a status:

| Status | Meaning |
|---|---|
| `OK` | Got the number of jobs you asked for |
| `ALL_AVAILABLE` | Google listed fewer jobs than you asked for, and you got all of them |
| `PARTIAL` | Scrolling was blocked or ran out of time; you got what was loaded (at least the first 10 when the first request worked) |
| `NO_NEW_JOBS` | With Only new jobs: every job Google listed was already delivered by an earlier run |
| `NO_MATCHES` | Google listed jobs, but none passed your filters; nothing is charged |
| `NO_RESULTS` | Google has no jobs for this query |
| `FAILED` | Nothing could be loaded |
| `SKIPPED` | A run limit (total jobs, duration or your spending limit) was reached first |

Every run also checks its own quality (`REPORT.health`, `REPORT.qualityProblems`, and a warning in the status line). It flags job listings Google showed but that could not be read, the usual sign of a Google layout change. A page like that is never reported as "no results". It also flags more than 20% of saved jobs missing a core field, every search failing, and scrolling stuck at 10 jobs everywhere. Turn on **Fail the run if quality drops** for scheduled runs, so Apify's failed-run notification tells you. The Actor is checked this way every day by its author.

### Good to know

- **Maximum per search** is about 90–100 jobs, Google's own limit. For more, split a broad search into narrower ones (by city, seniority or specialty); duplicates between them are removed and not charged.
- **Salary** fields: `salaryMin` and `salaryMax` are equal for a single amount. "Up to £48,000" leaves `salaryMin` empty, and "from $20/hour" leaves `salaryMax` empty.
- **`postedAtApprox`** is the scrape date minus Google's "N days ago"; Google gives no exact timestamp.
- **Bare queries**: Google answers some queries without the word "jobs" (just "pharmacist") with no job results. The Actor then searches again with "jobs" ("vagas", "empleo") added, and the report shows the text it used.
- **Countries**: full runs tested on Google US, UK, Brazil and Mexico; Spain's result page was checked too. The other countries use the same page format but have not been checked one by one.
- **No login, no cookies.** Only public Google pages are read.

### FAQ

**How much does it cost?** $3.00 per 1,000 jobs, proxies included. Repeats, filtered-out jobs and (with Only new jobs) jobs already delivered are free. See [Pricing](#pricing).

**How fast is it?** The first 10 jobs of a query take 1 to 65 seconds, typically about 20. Scrolling for more takes 20 seconds to 2 minutes per query, and two queries scroll at the same time with the default 4 GB of memory. 40 queries of 20 jobs took 15 minutes.

**Do I need proxies or a Google account?** No. Proxies are included and no login is used.

**Which countries and languages?** 30 countries, including the US, UK, Canada, Australia, India, Germany, France, Brazil, Mexico and Spain. Google's labels are read in English, Portuguese and Spanish; other countries are searched locally with the English interface.

**Why do some jobs have no salary?** Neither Google nor the posting text states one. See [Salary](#salary-also-when-google-doesnt-show-one) for how often each does.

**Does it return recruiter e-mails or phone numbers?** No. It returns what Google Jobs shows: the posting, the company and the apply links.

**Why did a query return exactly 10 jobs?** Either you asked for 10, or scrolling was blocked twice: its status in `REPORT` is then `PARTIAL`.

**Can I monitor new postings every day?** Yes: turn on Only new jobs and schedule the Actor. Jobs already delivered are skipped and not charged.

**Is it legal to scrape Google Jobs?** The Actor reads publicly available job postings only. Postings can still contain personal data, such as a recruiter's name, so check that your use complies with the laws that apply to you, such as the GDPR, and consult a lawyer if in doubt.

# Actor input Schema

## `queries` (type: `array`):

What you would type into Google, one search per line: a job title, skill or company, optionally with a place ("registered nurse chicago", "python developer remote"). Needed unless you paste Google Jobs URLs below.

## `startUrls` (type: `array`):

Optional. Paste searches straight from Google (google.com/search?q=…\&udm=8, or a shared job link). Their own search text, Google domain and language are used, including any filters you picked on Google; Locations are not added to them.

## `locations` (type: `array`):

Optional. Cities or regions; every query is searched in every location ("registered nurse Chicago, IL", "registered nurse Houston, TX"...). Leave empty to put the place in the query itself. A job found in two locations is saved once.

## `country` (type: `string`):

Which Google is searched (google.com, google.co.uk, google.com.br, ...). Jobs are local to this country.

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

Optional. Language of Google's labels, such as "2 days ago". By default Portuguese for Brazil and Portugal, Spanish for Spanish-speaking countries and English elsewhere. Job texts stay as the employer wrote them.

## `datePosted` (type: `string`):

Google's own "Date posted" filter. Jobs whose age Google shows as older are also dropped and not charged.

## `employmentType` (type: `string`):

Jobs that Google labels with a different type are dropped and not charged; jobs without a label are kept.

## `remoteOnly` (type: `boolean`):

Adds "remote" to the search and keeps only jobs Google marks as work from home or with a remote location.

## `companies` (type: `array`):

Keep only jobs whose company name contains one of these as whole words ("Amazon" matches "Amazon.com Services LLC", not "Amazonia"). Case and accents are ignored. Other jobs are not saved or charged, and the browser reads the whole list to find matches.

## `excludeCompanies` (type: `array`):

Drop jobs from these companies (same matching), e.g. staffing agencies.

## `sources` (type: `array`):

Keep only jobs Google shows via one of these sites or that have an apply link to one of them, e.g. "LinkedIn", "Indeed", "Glassdoor".

## `excludeSources` (type: `array`):

Drop jobs that Google shows via one of these sites, e.g. job aggregators you don't want.

## `onlyNewJobs` (type: `boolean`):

Remember the jobs this search has saved and, on later runs, skip them: you get and pay for new postings only. Works per set of queries and filters, or per history name below.

## `historyName` (type: `string`):

Optional. Runs with the same name share one memory of saved jobs, even when their queries differ. By default each set of queries and filters has its own. Stored in your account as the key-value store google-jobs-history-<name>.

## `resetHistory` (type: `boolean`):

Start this run with an empty memory: every job counts as new again. The memory is then rebuilt from this run.

## `outputMode` (type: `string`):

Compact keeps every field except the bullet lists (qualifications, benefits, responsibilities, highlights) and cuts the description to its first 500 characters: about 77% smaller, handy for spreadsheets and AI agents.

## `maxJobsPerQuery` (type: `integer`):

Up to 10 comes from one fast request. More are loaded by scrolling Google's list in a browser, which takes about 2–3 minutes per query; Google usually lists up to around 90–100 jobs per search.

## `scrollWithBrowser` (type: `boolean`):

Turn off to get only the first 10 jobs per query, faster.

## `maxItems` (type: `integer`):

Across all queries. A job found by two queries is saved and charged once.

## `maxConcurrency` (type: `integer`):

Browsers are also limited by memory: one per ~1.5 GB.

## `failOnQualityDrop` (type: `boolean`):

Mark the run as failed when its quality check finds a problem (listings Google showed but that could not be read, many jobs missing core fields, every search failing). Useful for scheduled runs: a failed run triggers Apify's failure notification. The check itself always runs and is in REPORT.qualityProblems.

## `maxDurationSecs` (type: `integer`):

No new query or scroll is started after this time.

## Actor input object example

```json
{
  "queries": [
    "registered nurse",
    "software engineer"
  ],
  "locations": [
    "Chicago, IL"
  ],
  "country": "us",
  "datePosted": "any",
  "employmentType": "ANY",
  "remoteOnly": false,
  "onlyNewJobs": false,
  "resetHistory": false,
  "outputMode": "full",
  "maxJobsPerQuery": 30,
  "scrollWithBrowser": true,
  "maxItems": 1000,
  "maxConcurrency": 3,
  "failOnQualityDrop": false,
  "maxDurationSecs": 1800
}
```

# Actor output Schema

## `jobs` (type: `string`):

Job postings with company, location, salary when available, full descriptions and direct apply links.

## `report` (type: `string`):

Per-query results, counts, statuses and quality checks.

# 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 = {
    "queries": [
        "registered nurse",
        "software engineer"
    ],
    "locations": [
        "Chicago, IL"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("roomy_tweet/google-jobs-scraper").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 = {
    "queries": [
        "registered nurse",
        "software engineer",
    ],
    "locations": ["Chicago, IL"],
}

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

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

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

```

## CLI example

```bash
echo '{
  "queries": [
    "registered nurse",
    "software engineer"
  ],
  "locations": [
    "Chicago, IL"
  ]
}' |
apify call roomy_tweet/google-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,roomy_tweet/google-jobs-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/HSOYaOQpHof228hjp/builds/qx5XGhgSdgjqvhP0z/openapi.json
