# Apify Bulk Job Listings Export

> Export Google Jobs listings to CSV, Excel, Sheets, or JSON in bulk with the Apify Google Jobs Scraper API Pay Per Result Actor (johnvc/google-jobs-scraper---pay-per-result). Output is already flat, one row per opening, so a dataset export drops straight into a spreadsheet or a database load with no reshaping. Covers multi-query batches, exclusion filters that shrink the file and the bill together, and job_id dedupe across runs. Use when the user wants to export google jobs to csv, download job listings as a spreadsheet, build or backfill a job board, load openings into a warehouse or ATS, or bulk export job postings for many roles and cities at a known cost. Pay-per-result billing, MCP-ready for Claude and other AI agents.

- Skill: `johnisanerd/apify-bulk-job-listings-export` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add johnisanerd/apify-bulk-job-listings-export`
- Raw SKILL.md: https://api.skillmd.com/api/skills/johnisanerd/apify-bulk-job-listings-export/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- License: MIT
- Author: johnisanerd (https://skillmd.com/u/johnisanerd)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/johnisanerd/apify-bulk-job-listings-export

---


# Bulk Job Listings Export With a Cost You Can Budget

Pull Google Jobs openings in bulk and hand back a file. The Actor writes flat rows, so CSV, Excel, Sheets, and JSON exports come out clean, and because billing is per result the invoice equals the row count.

## When to use this skill

- The user wants to export Google Jobs listings to CSV, Excel, Google Sheets, or JSON.
- They are seeding or backfilling a job board, an ATS, a warehouse table, or a research dataset.
- They need many roles or many cities in one deliverable file.
- They need to quote a data-pull cost up front, before anyone approves the run.

Not for: a live low-latency search endpoint inside an app, salary analytics (there is no numeric salary field), or LinkedIn-only listings (use the LinkedIn Jobs API).

## Why per-result billing matters for bulk work

Bulk exports are where page-based pricing gets unpredictable, because a page that returns three listings costs the same as a page that returns ten. Here you pay for delivered rows. A 500-row export costs 500 result charges whether Google served them across 50 tidy pages or 80 ragged ones, so the estimate you give before the run is the number on the invoice after it.

## What lands in the file (one flat row per listing)

Verified on a live run:

`title`, `job_title` (same string as `title`), `company_name`, `location`, `via` (hosting platform), `description` (full posting text), `job_highlights` (array of `{title, items}` blocks such as Qualifications, Responsibilities, Benefits), `extensions` (raw tags such as "22 hours ago", "Full-time"), `detected_extensions` (`posted_at` and `schedule_type` on every row, plus `work_from_home` and `qualifications` when present), `apply_options` (array of `{title, link}` direct apply links), `source_link`, `share_link`, `job_id`, and the echoed run context `query`, `country`, `language`, `google_domain`, `search_timestamp`, `total_jobs_found`, `pages_processed`.

The echoed context is what makes multi-query batches work. Concatenate 12 runs into one table and each row still says which query and market produced it.

For CSV and Excel, the nested columns (`job_highlights`, `apply_options`, `extensions`, `detected_extensions`) flatten into bracketed sub-columns. Pick a dataset view or select fields when you want a narrow, human-readable sheet. See `references/gotchas.md`.

## Prerequisites

- Apify account (sign up at https://apify.com?fpr=9n7kx3&fp_sid=skillrepo).
- Authentication via `apify login`, or an `APIFY_TOKEN` environment variable (Apify Console, Settings, Integrations).

## The Actor

- Store page: https://apify.com/johnvc/google-jobs-scraper---pay-per-result?fpr=9n7kx3&fp_sid=skillrepo
- Actor ID: `johnvc/google-jobs-scraper---pay-per-result`
- Pricing: pay per result delivered to the dataset (see `references/gotchas.md`).

## Run it with the Apify CLI

One export batch, staffing agencies and aggregators excluded:

```bash
apify actors call "johnvc/google-jobs-scraper---pay-per-result" -i '{"query":"registered nurse","location":"Dallas, TX","country":"us","language":"en","num_results":200,"via_filter_list":["ZipRecruiter","Indeed"]}' \
  --json \
  --user-agent apify-awesome-skills/apify-bulk-job-listings-export \
  2>/dev/null
```

Pull the dataset down as JSON for a database load:

```bash
apify datasets get-items DATASET_ID --format json --user-agent apify-awesome-skills/apify-bulk-job-listings-export 2>/dev/null > job_listings.json
```

For a spreadsheet handoff, ask the dataset export endpoint for CSV directly:

```bash
curl -sG "https://api.apify.com/v2/datasets/DATASET_ID/items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  --data-urlencode "format=csv" \
  > job_listings.csv
```

Swap `format=csv` for `format=xlsx` when the user wants Excel.

Every call carries the three flags this repo expects: `--json` (or `--format json`), `--user-agent apify-awesome-skills/apify-bulk-job-listings-export`, and `2>/dev/null`.

## Run it from Claude or another AI agent (MCP)

The Actor is MCP-ready. Add the hosted server URL:

`https://mcp.apify.com/?tools=actors,docs,johnvc/google-jobs-scraper---pay-per-result`

Then ask, for example: "Export 300 medical assistant openings across Phoenix, Tucson, and Mesa to one CSV, and skip listings from staffing agencies." MCP setup docs: https://docs.apify.com/platform/integrations/mcp

## Workflow

1. Scope the deliverable with the user. Which roles, which markets, how many rows per combination, and what file format at the end.
2. Turn that into one input per query and market pair. `query` plus `location` plus `country` plus `language`. Send `country` and `language` explicitly, since Google Jobs returns nothing when neither is supplied.
3. Price the batch before running. Total rows times the live per-result price. Present the number and get approval when it is large. See `references/gotchas.md`.
4. Trim the file and the bill together. `company_filter_list` and `via_filter_list` exclude rows during collection, so they never reach the dataset and never get charged.
5. Run the batch. Keep runs separate per query and market so a failure costs you one slice instead of the whole export.
6. Export and merge. Pull each dataset as CSV or JSON, concatenate, then dedupe on `job_id`. The same posting can appear in overlapping city searches.
7. Deliver. Hand over the file, or load it into the job board, warehouse, or ATS. For a recurring refresh, wrap the same inputs in an Apify Schedule.

## Inputs

- `query` (string, required): role, skill, or company
- `location` (string): city, state, or country
- `country` (enum: None, us, ca, uk, de, fr, au, jp, in, br, mx) and `language` (enum, 100 plus codes)
- `google_domain` (enum, default `google.com`)
- `num_results` (integer 10 to 1000, default 100): rows per run, and the cost lever
- `max_pagination` (integer 0 to 100, default 0 = unlimited)
- `company_filter` or `company_filter_list`: exclude employers
- `company_filter_regex` (boolean, default false): treat company filters as regular expressions
- `via_filter` or `via_filter_list`: exclude source platforms
- `include_lrad` (boolean) plus `lrad_value` (string, miles): radius search
- `output_file` (string): custom filename for the saved results file

## Cost

Billing is per result in the default dataset, so a bulk export costs rows times the per-result price. A 1,000-row export is 1,000 charges. Multi-query batches add up across runs, so total the whole batch before you start. Live prices are in `references/gotchas.md`.

## Honest limits

- Hard ceiling of 1,000 results per run. Larger exports mean several runs, split by query or market.
- No numeric salary field and no experience-level field. Compensation sometimes sits in free text inside a `job_highlights` Benefits block.
- `posted_at` is a relative string such as "22 hours ago", so convert it to timestamps after export if the file needs real dates.
- `pages_processed` came back as 0 on the verified run. Do not put it in a report; count rows.
- Overlapping city or radius searches return duplicate postings. Dedupe on `job_id` before delivering.
- This is a batch export, not a streaming feed. Freshness is the age of your last run.

## Troubleshooting

- Empty export: confirm `country` and `language` were sent, then broaden the query or widen the location.
- Row count below `num_results`: expected, Google had fewer listings. You were billed only for delivered rows.
- CSV columns look exploded: the nested fields expand into sub-columns. Select a narrower field set or use a dataset view.
- A single row describing insufficient funds: account balance was below the estimated row count. Add funds or lower `num_results`.

See `references/gotchas.md` for cost guardrails, export formats, and error recovery, and `references/actor-index.md` for the Actor routing table.

## Related job-data Actors

- Google Jobs Scraper, pay per page edition: https://apify.com/johnvc/Google-Jobs-Scraper?fpr=9n7kx3&fp_sid=skillrepo
- LinkedIn Jobs API: https://apify.com/johnvc/linkedin-jobs-api?fpr=9n7kx3&fp_sid=skillrepo
- Glassdoor Reviews API: https://apify.com/johnvc/glassdoor-reviews-api?fpr=9n7kx3&fp_sid=skillrepo

