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

Job openings (vagas) from Gupy's Brazilian job portal with company, location, contract type such as CLT or PJ and the full description. Search by job title, state and city; searches above Gupy's limit of 10,000 results are split by state.

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

## Pricing

from $1.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.
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

## Gupy Jobs Scraper

Gupy is the recruiting software behind the career sites of many Brazilian employers, and its portal at portal.gupy.io searches their openings (vagas) in one place. Each row is one opening: title, company, city and state, on-site, hybrid or remote, contract type such as CLT or PJ, publication date, application deadline and the full description in Portuguese. Type a job title such as `desenvolvedor` and click **Start**. Gupy's search has no salary field, so pay appears only where the employer wrote it into the description. It costs $2.00 per 1,000 jobs on the Free plan ($1.00 on Business), and the $5 of monthly credit in Apify's Free plan covers about 2,500 jobs.

### Output fields

| Field | Description |
|---|---|
| `title`, `url` | Job title as the employer wrote it, e.g. `Desenvolvedor(a) .NET Sênior`, and the job page on the company's Gupy career site. |
| `company`, `companyPage`, `companyId` | Name of the employer's career page, its address such as `https://vetta.gupy.io` and Gupy's company number, which the actor reads from the logo address. All three are empty for confidential openings. |
| `companyLogo` | Link to the employer's logo on Gupy. |
| `confidentialCompany` | `true` when the employer hides behind a placeholder name such as `Confidencial` or `Vagas Sigilosas`. |
| `city`, `state` | City and full state name, e.g. `Campinas` and `São Paulo`. Most remote openings have neither. |
| `workplace`, `remote` | `On-site`, `Hybrid` or `Remote`, and `true` for remote openings. |
| `jobType`, `jobTypeCode` | Contract in English with Gupy's code: `Permanent (CLT)` is `vacancy_type_effective`, then `Contractor (PJ)`, `Internship`, `Apprentice`, `Temporary`, `Talent pool` and others. |
| `disabilityFriendly` | `true` when the opening carries Gupy's label Vaga também para PcD, meaning it is also open to people with disabilities. |
| `publishedAt`, `applicationDeadline` | Publication time in UTC and the last day to apply as YYYY-MM-DD. |
| `description` | The full job text as Gupy's search returns it: about the company, responsibilities, requirements and benefits. |
| `country`, `skills` | Always empty: the search Gupy has used since 1 October 2026 returns neither. The fields stay so that existing integrations keep working. |
| `key`, `jobId` | Gupy's job number and a stable key built from it, `gupy:12700651`. |
| `searchQuery`, `scrapedAt` | The search that found the opening and when it was read. |

### How to scrape Gupy jobs

1. Enter **Keywords** in Portuguese, one per line: `vendedor`, `analista de dados`, `enfermeiro`. Gupy matches them against job titles and ignores accents and gender endings, so `enfermeiro` also finds `Enfermeira`. Leave the field empty to search all openings.
2. Pick **States** from the list or type **Cities** such as `Curitiba` or `Belo Horizonte`. Each keyword runs once for every state and every city you add.
3. Narrow the results with **Workplace**, **Contract types** (CLT, PJ, internship, apprenticeship and eight more) and **Only jobs open to people with disabilities**. **Exclude keywords** drops openings whose title or company contains a word you list.
4. Set **Maximum jobs** and click **Start**. The openings collect in the **Output** tab, and you can download them as CSV, Excel or JSON or read them through the API.

The same through the API, for remote and hybrid data jobs on CLT or PJ contracts in two states:

```json
{
  "keywords": ["analista de dados", "engenheiro de dados"],
  "states": ["São Paulo", "Minas Gerais"],
  "workplace": ["remote", "hybrid"],
  "jobTypes": ["vacancy_type_effective", "vacancy_legal_entity"],
  "maxItems": 500
}
```

### Example output

One opening from a run on 11 October 2026, with `description` cut after its first paragraphs.

```json
{
  "key": "gupy:12700651",
  "jobId": "12700651",
  "title": "Desenvolvedor(a) .NET Sênior",
  "url": "https://vetta.gupy.io/job/eyJqb2JJZCI6MTI3MDA2NTEsInNvdXJjZSI6Imd1cHlfcG9ydGFsIn0=",
  "company": "Vetta Tecnologia",
  "companyId": "1687",
  "companyPage": "https://vetta.gupy.io",
  "companyLogo": "https://attachments.gupy.io/production/companies/1687/career/2691/images/2020-10-22_21-45_logo.jpg",
  "confidentialCompany": false,
  "city": "São Paulo",
  "state": "São Paulo",
  "country": null,
  "workplace": "Hybrid",
  "remote": false,
  "jobType": "Permanent (CLT)",
  "jobTypeCode": "vacancy_type_effective",
  "disabilityFriendly": true,
  "skills": [],
  "publishedAt": "2026-10-09T22:09:06.417Z",
  "applicationDeadline": "2027-04-06",
  "description": "Estamos buscando uma pessoa Desenvolvedor (a) .NET Sênior para o Time Vetta!\n\nVOCÊ JÁ CONHECE A VETTA? Na Vetta, acreditamos que a tecnologia e a inovação são essenciais para criar um futuro mais sustentável e eficiente para todos. ...",
  "searchQuery": "\"desenvolvedor\"",
  "scrapedAt": "2026-10-11T12:55:36.141Z"
}
```

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

| | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| 1,000 jobs | $2.00 | $1.60 | $1.30 | $1.00 |

You pay only for the events in the table. There is no start fee, and compute time and proxies are included.

Exporting 20,000 openings costs $40.00 on the Free plan and $20.00 on Business. An opening that several of your searches find is billed once, and openings removed by a filter or skipped by the new-only mode are not billed.

### Limits

- Gupy listed 83,238 open jobs on 11 October 2026, but it returns at most 10,000 for one search. When **Maximum jobs** asks for more, a search without a state or city is split into the 27 states. A state above 10,000 still stops there, and São Paulo alone had 33,503 openings. Openings without a state, most of the remote ones, are not part of the split.
- Descriptions come from Gupy's search as plain text. Where the employer used headings, Gupy often runs them into the next sentence without a space, as in `Responsabilidades e atribuiçõesNesse time`.
- Confidential openings were 22 of 2,000 read on 11 October 2026. The actor recognises them by the placeholder name, so a confidential page that uses an ordinary name stays a normal company.
- The PcD label is common: 1,587 of those 2,000 openings carried it, so **Only jobs open to people with disabilities** keeps most of a search. Openings reserved for a group (vagas afirmativas) are marked only in the title, e.g. `Analista de Compliance Sr (Vaga afirmativa PCD)`. As keywords, `pcd` matched 2,171 titles and `afirmativa` 1,233 that day.
- A few small employers post through vaga-ja.com instead of a Gupy career site. Such a company can be an individual entrepreneur (MEI) whose business name is the owner's full name, and the job link contains the same name.
- If Gupy does not answer after four tries, that search is skipped. A run in which more than half of the requests fail ends with the status Failed.

### What changed on 1 October 2026

Gupy replaced the search behind its portal that day, and the previous address stopped answering. The actor reads the new one. It no longer returns the country, the company number, the career site address or a confidential flag, so the actor now takes the company number from the logo address, the career site from the job link and the confidential status from the placeholder name. `country` and `skills` stay empty. The new search also ignores a filter that is sent twice, so several workplace or contract types are sent as one list.

### FAQ

#### Is it legal to scrape Gupy?

The openings are public: Gupy's portal shows them to anyone without an account, and the actor reads the same search that the portal uses. It collects job ads and company names and nothing about candidates. How you store and republish the ads is your responsibility.

#### How do I get only new openings every day?

Turn on **Return only jobs new since the last run**, give the run a **Watch name** such as `vendas-sp` or save it as a task, and schedule it daily. An opening you have received is not sent again for 120 days.

### Related scrapers

- [Career Site Jobs Search](https://apify.com/deriverge/career-site-jobs-search)
- [Career Site Jobs Scraper](https://apify.com/deriverge/greenhouse-lever-workday-jobs-scraper)
- [Remote Jobs Scraper](https://apify.com/deriverge/remote-jobs-scraper)

### Support

This actor is built and maintained by deriverge s.r.o., a software company based in the Czech Republic. If a run fails or a field you need is missing, please open an issue in the **Issues** tab or write to us at info@deriverge.com. We respond in English and Czech. Runs can be scheduled in Apify Console or started from the **API** tab, which has examples for Python, JavaScript and cURL and works with Make, Zapier, n8n and the Apify MCP server. If the actor saves you time, a short review helps other people find it.

# Changelog

This Actor's version history is a separate document: https://apify.com/deriverge/gupy-jobs-scraper/changelog.md

# Actor input Schema

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

What to search for, in Portuguese, as in the Gupy search box: a job title or skill, for example "vendedor", "analista de dados" or "enfermeiro". Gupy matches it against job titles. Each keyword is its own search. Leave empty for all jobs.

## `states` (type: `array`):

Only jobs in these Brazilian states. Each state is its own search. Leave empty for all of Brazil.

## `cities` (type: `array`):

Only jobs in these cities, for example São Paulo, Rio de Janeiro, Belo Horizonte or Curitiba. Each city is its own search.

## `workplace` (type: `array`):

Only jobs with these workplace types. Leave empty for all.

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

Only jobs with these contract types, for example CLT, PJ, internships or apprenticeships. Leave empty for all.

## `disabilityFriendlyOnly` (type: `boolean`):

Keep only jobs that Gupy labels Vaga também para PcD (also open to people with disabilities). In October 2026 about 4 in 5 Gupy jobs carried the label.

## `excludeKeywords` (type: `array`):

Drop jobs whose title or company contains any of these.

## `newOnly` (type: `boolean`):

Keeps a snapshot per watch name (or per saved task) and returns only jobs that were not there before. Schedule it daily for a job alert.

## `watchName` (type: `string`):

Name of the snapshot used by the new-only mode, for example "vendas-sp". Runs from a saved task get one automatically.

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

Hard cap on returned jobs. Gupy lists more than 80,000 jobs; searches larger than 10,000 are split by state automatically when you ask for more. When the cap is smaller than the results, every search gets an equal share.

## Actor input object example

```json
{
  "keywords": [
    "desenvolvedor"
  ],
  "disabilityFriendlyOnly": false,
  "newOnly": false,
  "maxItems": 20
}
```

# Actor output Schema

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

One row per job opening with company, city, state, workplace, contract type, dates and full description.

## `summary` (type: `string`):

Jobs matching and returned per search, dropped rows and warnings.

# 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": [
        "desenvolvedor"
    ],
    "maxItems": 20
};

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

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

```

## MCP server setup

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