# Gupy Jobs Scraper (`axiomworks/gupy-jobs-scraper`) Actor

Scrape public Gupy job listings and return each job's title, company, description, location, work mode, contract type, publish date, deadline and application URL. Search by keywords or filter by state, city, work mode, contract type or PcD status; results from multiple queries are deduplicated.

- **URL**: https://apify.com/axiomworks/gupy-jobs-scraper.md
- **Developed by:** [Axiom Works](https://apify.com/axiomworks) (community)
- **Categories:** Jobs
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.64 / 1,000 results

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/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

**Returns:** one row per Gupy job with `title`, `company`, `city`, `state`, `workplaceType`, `jobType`, `publishedDate`, `applicationDeadline` and `jobUrl`.
**Input:** `{"searchTerms": ["desenvolvedor"], "state": "São Paulo", "maxItems": 50}`
**Best for:** Brazilian job market research, recruiting and lead lists of hiring companies, job board aggregation.

```json
{
    "id": "12693665",
    "title": "Analista de Risco (Dados e estatística) | Cresol Confederação - CSC",
    "company": "Cresol Oficial",
    "city": "Francisco Beltrão",
    "state": "Paraná",
    "workplaceType": "on-site",
    "jobType": "vacancy_type_effective",
    "publishedDate": "2026-10-13T17:34:00.500Z"
}
```

### What does Gupy Jobs Scraper do?

Gupy Jobs Scraper collects open job listings from Gupy, the applicant tracking system behind the careers pages of thousands of Brazilian employers, through the public job search at portal.gupy.io. It works like a Gupy API: you send keywords, a portal search link or filters, and you get back a clean table of jobs with title, company, full description, city, state, work mode (remote, hybrid or on-site), contract type, publish date, application deadline, disability (PcD) flags and the link where candidates apply.

You don't need a Gupy account or any login. The Actor reads the same public search that job seekers use on portal.gupy.io, so every row is a job anyone can see. One run can combine several search terms, a list of work modes and a list of contract types; results are merged and each job appears only once.

Typical uses are tracking who is hiring in Brazil for a given role, building lead lists of companies that are recruiting, feeding a niche job board with fresh Brazilian vacancies, and measuring demand for skills by state or city over time.

### What data can you get from Gupy?

Each job comes back as one row with these fields:

| Field | Description | Example |
|---|---|---|
| `id` | Gupy job ID, as a string, unique within a run | `12693665` |
| `title` | Job title as the company posted it | `Analista de Risco (Dados e estatística)` |
| `company` | Company career page name on Gupy | `Cresol Oficial` |
| `companyLogo` | URL of the company logo image | `https://attachments.gupy.io/...logo.png` |
| `description` | Job description as plain text, as Gupy returns it | `Venha fazer a diferença com a gente!...` |
| `city` | City of the job, null for remote jobs | `Francisco Beltrão` |
| `state` | Brazilian state of the job, null for remote jobs | `Paraná` |
| `workplaceType` | Work mode: `remote`, `hybrid` or `on-site` | `on-site` |
| `jobType` | Gupy contract type code | `vacancy_type_effective` |
| `publishedDate` | When the job was published (ISO 8601) | `2026-10-13T17:34:00.500Z` |
| `applicationDeadline` | Last day to apply (ISO 8601), null when none | `2026-10-31T00:00:00.000Z` |
| `isPWD` | Gupy's PcD badge, null when the job has no badges | `true` |
| `friendlyBadge` | Gupy's "friendly" badge, null when the job has no badges | `true` |
| `disabilities` | Whether the job accepts candidates with disabilities | `true` |
| `jobUrl` | Link to the job on the company's Gupy career site | `https://cresolcarreiras.gupy.io/job/...` |
| `searchTerm` | The search term that found the job, null for filter-only searches | `analista de dados` |
| `scrapedAt` | When the Actor fetched the job (ISO 8601) | `2026-10-14T18:59:03.304Z` |
| `sourceUrl` | Page the record comes from (the job URL) | `https://cresolcarreiras.gupy.io/job/...` |

The common `jobType` codes are `vacancy_type_effective` (permanent CLT job), `vacancy_type_internship` (estágio), `vacancy_type_apprentice` (jovem aprendiz), `vacancy_type_trainee`, `vacancy_type_temporary`, `vacancy_type_talent_pool` (banco de talentos) and `vacancy_legal_entity` (PJ contract). The value is copied from Gupy unchanged so you can filter on it reliably.

### How to use Gupy Jobs Scraper

1. Open Gupy Jobs Scraper in Apify Console and go to the Input tab.
2. Type one or more keywords in **Search terms**, for example `desenvolvedor` or `analista de dados`. Portuguese terms work best; accents are fine.
3. Optionally narrow the search with **State**, **City**, **Work mode**, **Job types**, **Company name** or the PcD switch. You can also paste a search link from portal.gupy.io into **Gupy search URLs** instead of filling the filters by hand.
4. Set **Maximum results** to the number of jobs you want in total.
5. Click **Start**. When the run finishes, open the Output tab and export the jobs as JSON, CSV, Excel, XML or HTML, or read them through the API.

Some tips:

`maxItems` is a total for the whole run, shared across all search terms, URLs, work modes and job types. The run stops as soon as that many jobs are saved.

Gupy's API accepts one work mode and one contract type per request. When you pick several, the Actor runs one search per value and merges them, so a small `maxItems` may be filled by the first value before the next one is reached. Run separate searches if you need a fixed number per work mode.

One search reaches at most about 10,000 jobs. To go deeper, split the search by state, city or work mode.

Leave every target field empty to list the newest open jobs on Gupy, up to `maxItems`.

The company filter must match the company name exactly as Gupy shows it on portal.gupy.io, including capital letters. `Cresol Oficial` works; a partial name returns nothing.

Remote jobs have no city or state on Gupy, so combining `remote` with a state or city filter usually returns 0 jobs.

### Input

| Field | Type | Required | Description |
|---|---|---|---|
| `searchTerms` | array of strings | No | Keywords to search, one search per term, e.g. `["desenvolvedor"]`. Empty = all open jobs matching the filters. |
| `startUrls` | array | No | portal.gupy.io search links, as `{"url": "..."}` objects or plain strings. The filters in the link are used. |
| `companyName` | string | No | Exact Gupy company name, e.g. `Cresol Oficial`. |
| `state` | string | No | Brazilian state as Gupy writes it, e.g. `São Paulo`, `Paraná`. |
| `city` | string | No | City name, e.g. `Curitiba`, `Manaus`. |
| `workplaceTypes` | array | No | Any of `remote`, `hybrid`, `on-site`. Empty = all. |
| `jobTypes` | array | No | Gupy contract type codes, e.g. `vacancy_type_internship`. Empty = all. |
| `pwdOnly` | boolean | No | Only jobs flagged for people with disabilities (PcD). Default `false`. |
| `maxItems` | integer | No | Maximum number of jobs in total, 1-10000, default 50. |
| `proxyConfiguration` | object | No | Proxy settings. Default: no proxy; blocked requests are retried through Apify Proxy. |

The filters (`companyName`, `state`, `city`, `workplaceTypes`, `jobTypes`, `pwdOnly`) apply to every search term. A search URL keeps its own filters and takes the filter fields only for what the link leaves out.

Example input that searches two roles in São Paulo, on-site and hybrid only:

```json
{
    "searchTerms": ["desenvolvedor", "analista de dados"],
    "state": "São Paulo",
    "workplaceTypes": ["on-site", "hybrid"],
    "jobTypes": [],
    "pwdOnly": false,
    "maxItems": 200
}
```

Example input that uses a link copied from portal.gupy.io:

```json
{
    "startUrls": [
        { "url": "https://portal.gupy.io/job-search/term=vendedor&state=S%C3%A3o%20Paulo&workplaceTypes[]=on-site" }
    ],
    "maxItems": 30
}
```

### Output

Real items from a local run (descriptions shortened here):

```json
[
    {
        "id": "12708994",
        "title": "Desenvolvedor de Sistemas Front-end | Sistemas 5 - Canais IB | CSC (Remoto)",
        "company": "Cresol Oficial",
        "companyLogo": "https://attachments.gupy.io/production/companies/8089/career/20767/images/2021-08-04_19-57_logo.png",
        "description": "Venha fazer a diferença com a gente! 🧡Estamos em busca de um(a) Desenvolvedor de Sistemas para fortalecer ainda mais o nosso time!...",
        "city": null,
        "state": null,
        "workplaceType": "remote",
        "jobType": "vacancy_type_effective",
        "publishedDate": "2026-10-14T18:10:55.229Z",
        "applicationDeadline": "2026-12-31T00:00:00.000Z",
        "isPWD": true,
        "friendlyBadge": true,
        "disabilities": true,
        "jobUrl": "https://cresolcarreiras.gupy.io/job/eyJqb2JJZCI6MTI3MDg5OTQsInNvdXJjZSI6Imd1cHlfcG9ydGFsIn0=?jobBoardSource=gupy_portal",
        "searchTerm": null,
        "scrapedAt": "2026-10-14T18:58:59.026Z",
        "sourceUrl": "https://cresolcarreiras.gupy.io/job/eyJqb2JJZCI6MTI3MDg5OTQsInNvdXJjZSI6Imd1cHlfcG9ydGFsIn0=?jobBoardSource=gupy_portal"
    },
    {
        "id": "12693665",
        "title": "Analista de Risco (Dados e estatística) | Cresol Confederação - CSC",
        "company": "Cresol Oficial",
        "companyLogo": "https://attachments.gupy.io/production/companies/8089/career/20767/images/2021-08-04_19-57_logo.png",
        "description": "Venha fazer a diferença com a gente! 🧡Estamos em busca de um(a) Analista de Risco para fortalecer ainda mais o nosso time!...",
        "city": "Francisco Beltrão",
        "state": "Paraná",
        "workplaceType": "on-site",
        "jobType": "vacancy_type_effective",
        "publishedDate": "2026-10-13T17:34:00.500Z",
        "applicationDeadline": "2026-10-31T00:00:00.000Z",
        "isPWD": true,
        "friendlyBadge": true,
        "disabilities": true,
        "jobUrl": "https://cresolcarreiras.gupy.io/job/eyJqb2JJZCI6MTI2OTM2NjUsInNvdXJjZSI6Imd1cHlfcG9ydGFsIn0=?jobBoardSource=gupy_portal",
        "searchTerm": "analista de dados",
        "scrapedAt": "2026-10-14T18:59:03.304Z",
        "sourceUrl": "https://cresolcarreiras.gupy.io/job/eyJqb2JJZCI6MTI2OTM2NjUsInNvdXJjZSI6Imd1cHlfcG9ydGFsIn0=?jobBoardSource=gupy_portal"
    }
]
```

Gupy returns the description as plain text with the original line breaks removed, and some descriptions contain HTML entities such as `&nbsp;`. The Actor keeps the text exactly as Gupy sends it. Jobs are returned in Gupy's order, which puts the newest jobs first.

You can download the dataset as JSON, CSV, Excel, XML, RSS or HTML from the Output tab, or read it through the Apify API.

### How much does it cost to scrape Gupy?

Gupy Jobs Scraper is charged per result. You pay only for the jobs returned, and `maxItems` caps how many that can be. See the Pricing tab for the current price.

The Actor reads Gupy's own job search with plain HTTP requests, 100 jobs per request, without a browser, so runs are quick and light. You can also set a maximum cost per run in the run options; the Actor stops cleanly when it is reached and tells you so in the status message.

### Use with AI agents (MCP)

Connect Gupy Jobs Scraper to Claude, Cursor or any MCP client through the Apify MCP server:

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com/?tools=axiomworks/gupy-jobs-scraper"
        }
    }
}
```

Example prompts:

1. "Find 50 remote 'desenvolvedor' jobs on Gupy and list the companies hiring, with the job links."
2. "Which companies are hiring data analysts in Paraná on Gupy right now? Group the results by city."
3. "Get all open internship (estágio) jobs in Manaus on Gupy and tell me which ones close this month."

An agent should send `searchTerms` as a list, put filters in their own fields and keep `maxItems` small for quick answers. A search that matches nothing returns 0 rows and a status message, not an error.

### Integrations and API

Run Gupy Jobs Scraper from your own code with the Apify API. Set `APIFY_TOKEN` to your Apify API token (send it in the `Authorization` header, never in the URL).

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("axiomworks/gupy-jobs-scraper").call(run_input={
    "searchTerms": ["desenvolvedor"],
    "state": "São Paulo",
    "maxItems": 50,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["title"], item["company"], item["jobUrl"])
```

**JavaScript**

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

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('axiomworks/gupy-jobs-scraper').call({
    searchTerms: ['desenvolvedor'],
    workplaceTypes: ['remote'],
    maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**cURL**

```bash
curl -X POST "https://api.apify.com/v2/acts/axiomworks~gupy-jobs-scraper/run-sync-get-dataset-items" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"searchTerms": ["desenvolvedor"], "maxItems": 50}'
```

On the Integrations tab you can connect the Actor to Make, Zapier, n8n, Google Sheets, Slack or your own webhooks, for example to post new jobs to a channel after each scheduled run.

### FAQ

**Do I need a Gupy account?**
No. The Actor reads the public job search on portal.gupy.io, the same one job seekers use without logging in.

**How fresh is the data?**
Every run queries Gupy live, so you get the jobs that are open at that moment. Schedule the Actor (for example daily) to track new postings; compare `id` values between runs to find the new ones.

**Why did my run return 0 results?**
Usually the search matches nothing: a misspelled term, a company name that is not written exactly as on portal.gupy.io, or a filter combination with no jobs, such as `remote` plus a city. The run still finishes successfully and the status message says what to change.

**Why is city or state empty?**
Gupy stores no location for remote jobs, so `city` and `state` are null for them.

**Why are `isPWD` and `friendlyBadge` sometimes null?**
Gupy shows those badges only on part of the jobs. When a job has no badges, both fields are null. The `disabilities` field is filled for every job.

**Can I scrape a company's own Gupy careers site (company.gupy.io)?**
Use the `companyName` filter with the company's name as shown on portal.gupy.io. That returns the same jobs that are listed on the company's careers site.

**Can I get more than 10,000 jobs?**
Gupy's search stops around 10,000 results per query. Split the job into several runs or searches by state, city, work mode or job type.

**Do I need a proxy?**
Normally not. If Gupy rate-limits or blocks a request, the Actor waits and retries through Apify Proxy on a new IP automatically.

### Is it legal to scrape Gupy?

Gupy Jobs Scraper collects only job postings that companies publish openly on portal.gupy.io. It does not log in, and it collects no data about candidates. Job descriptions can mention names or contact details of recruiters; if you store or reuse such data, you are responsible for following the laws that apply to you, such as Brazil's LGPD or the GDPR. If you are unsure, ask a lawyer.

Gupy Jobs Scraper is an independent tool. It is not affiliated with, endorsed by or sponsored by Gupy.

### Related Actors

| Actor | What it does |
|---|---|
| [LinkedIn Jobs Scraper](https://apify.com/axiomworks/linkedin-jobs-scraper) | Job listings from LinkedIn job search |
| [Google Jobs Scraper](https://apify.com/axiomworks/google-jobs-scraper) | Job listings collected by Google Jobs |
| [Remote Job Listings Scraper](https://apify.com/axiomworks/remote-jobs-scraper) | Remote job listings from job boards |

### Feedback

Found a bug or need a field that isn't here? Open an issue on the Issues tab and we'll look at it.

# Actor input Schema

## `searchTerms` (type: `array`):

Job keywords to search on Gupy, one per line, e.g. 'desenvolvedor' or 'analista de dados' (Portuguese works best, accents allowed). Each term is a separate search filtered by the fields below. Leave empty to list all open jobs that match the filters. A term with no matches returns 0 items, not an error.

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

portal.gupy.io search links copied from the browser, e.g. \[{"url": "https://portal.gupy.io/job-search/term=vendedor\&state=São Paulo\&workplaceTypes\[]=on-site"}]. Plain URL strings also work. The term, state, city, work-mode, job-type, company and PwD filters in the link are used; fields below fill in only what the link leaves out. Company career sites (\*.gupy.io) are not supported.

## `companyName` (type: `string`):

Only jobs from this company, written exactly as Gupy shows it (case-sensitive), e.g. 'Cresol Oficial'. A partial or misspelled name returns 0 items.

## `state` (type: `string`):

Brazilian state, full name as Gupy writes it, e.g. 'São Paulo', 'Paraná', 'Minas Gerais'. Remote jobs have no state, so combining this with work mode 'remote' usually returns nothing.

## `city` (type: `string`):

City name, e.g. 'Curitiba' or 'Manaus'. Works alone or together with state.

## `workplaceTypes` (type: `array`):

Work modes to include: 'remote', 'hybrid', 'on-site'. Empty = all. Each value is searched separately and merged, so maxItems may be filled by the first value before the next one is reached.

## `jobTypes` (type: `array`):

Contract types to include, e.g. 'vacancy_type_effective' (CLT), 'vacancy_type_internship' (estágio), 'vacancy_type_apprentice', 'vacancy_type_trainee', 'vacancy_type_temporary', 'vacancy_legal_entity' (PJ). Empty = all. Each value is a separate search, merged and de-duplicated.

## `pwdOnly` (type: `boolean`):

If true, return only jobs Gupy flags for people with disabilities (PcD / isPWD). Default false returns all jobs.

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

Maximum number of jobs to return in total, shared across all search terms, URLs and filter values, 1-10000, default 50. The run stops as soon as this many are saved, and you are charged only for results returned. One search can reach about 10,000 jobs; narrow by state, city or work mode to go deeper.

## `proxyConfiguration` (type: `object`):

Proxy for requests, default none (direct). Rate-limited or blocked requests are retried through Apify Proxy anyway; turn it on here only if runs keep getting blocked.

## Actor input object example

```json
{
  "searchTerms": [
    "desenvolvedor"
  ],
  "startUrls": [],
  "workplaceTypes": [],
  "jobTypes": [],
  "pwdOnly": false,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Dataset with one item per result, in the order found.

# 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 = {
    "searchTerms": [
        "desenvolvedor"
    ],
    "startUrls": [],
    "maxItems": 20,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("axiomworks/gupy-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 = {
    "searchTerms": ["desenvolvedor"],
    "startUrls": [],
    "maxItems": 20,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("axiomworks/gupy-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 '{
  "searchTerms": [
    "desenvolvedor"
  ],
  "startUrls": [],
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call axiomworks/gupy-jobs-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,axiomworks/gupy-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/iwmW0x6SWaGR3YISh/builds/iYd7VJ0bBqGQXmceJ/openapi.json
