Gupy Jobs Scraper - Jobs, Companies, Locations & Deadlines
Pricing
from $1.00 / 1,000 job results
Gupy Jobs Scraper - Jobs, Companies, Locations & Deadlines
Scrape public jobs from Gupy.io by keyword, state, city, workplace type, job type, company, PWD, and feedback badge. Extract rich job details, company information, locations, application deadlines, and badge data.
Pricing
from $1.00 / 1,000 job results
Rating
0.0
(0)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
1
Monthly active users
7 days ago
Last modified
Categories
Share
Gupy.io Jobs Scraper: Job Listings, Companies & Application Deadlines
Gupy.io Jobs Scraper turns Gupy.io, a Brazilian job board and recruitment platform, into a clean jobs data feed. Search by keyword, Brazilian state, city, workplace type, job type, exact company career page, PWD accessible jobs, or feedback badge companies, or paste portal search links and direct Gupy job links. Turn on full detail enrichment for the complete per job record, sort results newest, oldest, or by company, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.
Why This Scraper?
- Two ways to find jobs. Run a filtered search (keyword, state, city, workplace type, job type, company, PWD only, feedback badge only) or paste portal search links and direct Gupy job links. Direct job links are always fetched in full, whatever the detail toggle is set to.
- Optional full detail enrichment. Turn on Fetch details to add the complete per job record. The detail enrichment charge only applies to a job that actually reaches the dataset, not to every detail page fetched. Jobs from direct Gupy job links are always fully fetched, so they carry the detail enrichment charge even with Fetch details off.
- Sort after collection. Order saved jobs newest, oldest, or by company name, A to Z.
- Full catalogue pagination by default. The walk covers every result page unless you cap it, and leading pages that were all collected before are skipped past rather than ending the walk. See the pagination notes below for the cases where a walk can still end early.
- Survives interruptions. A run that gets migrated or restarted mid walk reloads its already collected jobs and ids, so they are not saved twice, detail fetched again, or charged again.
- Resume across separate runs. Paste a previous run or dataset ID to keep pulling a large catalogue over several runs without re saving jobs you already have.
- Built for schedules. Incremental mode classifies every job as NEW, UPDATED, UNCHANGED, REAPPEARED, or EXPIRED against the last run of the same search, so a recurring schedule returns only what changed.
Use Cases
- Recruiters and talent teams: watch a set of companies' Gupy career pages for new openings by keyword, state, or workplace type.
- Job boards and aggregators: mirror Gupy listings for a state, city, or workplace type into your own catalogue.
- Workforce and HR analytics: run the same search on a schedule with Incremental mode and track how postings and requirements change over time.
- Accessibility focused services: filter for PWD marked listings across many companies at once.
- Automation and agent builders: pipe new listings straight into Notion, Linear, or Airtable through the MCP connector field.
Data You Get
Sample shape: values are illustrative placeholders, not from a live record.
| Field | Example |
|---|---|
id | 3050001 |
name | "Analista de Sistemas Pleno" |
jobUrl | "https://sample-company.gupy.io/job/eyJqb2JJZCI6MzA1MDAwMX0=" |
description | "<p>Full HTML job description as published.</p>" |
descriptionPlainText | "Full job description, converted to plain text." |
city | "São Paulo" |
state | "São Paulo" |
stateCode | "SP" |
country | "Brasil" (filled when the job's state is Brazilian, or always with Fetch details on; empty when the listing does not say, since jobs from other Latin American countries are listed too) |
jobType | "vacancy_type_effective" |
workplaceType | "hybrid" |
isRemoteWork | false |
publishedAt | "2026-08-01T12:00:00.000Z" |
applicationDeadline | "2026-09-15T23:59:59.000Z" |
expireDays | 17 |
careerPageName | "Sample Company" |
careerPageDisplayName | "Sample Company" (same value as careerPageName) |
careerPageUrl | "https://sample-company.gupy.io" |
hasFriendlyBadge | true |
badgeIsPWD | false |
skills | ["Comunicação", "Excel"] |
detailFetched | true (only when Fetch details was on, or the job came from a direct job link) |
source | the complete source record as returned by the API |
scrapedAt | "2026-09-29T09:00:00.000Z" |
With the full record fetched, each job also carries applicationQuestions, requiredApplicationFields, companyIntegrations and relevantExperiences (otherwise null).
Every record also carries a long list of schema compatibility fields shared with other job board actors. benefits, addressComplements, addressDistrict and jobRatingCriterias are not published in Gupy's public data, so they are always null. The company social links (companyLinkedin, companyFacebook, companyTwitter, companyInstagram, companyGithub, companyGlassdoor), the job images (jobImage, jobSocialImage, jobSmartphoneImage), the video (videoUrl, videoSectionTitle), careerPageWebsite, careerPageKnowMoreTitle and prerequisites are filled when Fetch details is on and the company publishes them, and are otherwise null.
How to Use
- Pick a mode:
search(use the filters below) orurl(paste portal search links or direct Gupy job links). - In search mode, set the keyword, state, city, workplace type, job type, company, PWD, and feedback badge filters you need, and turn on Fetch details if you want the full per job record.
- Set Max items (and Max pages or Page size if needed) to control run size and cost, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it through the API.
Search by keyword, state, and workplace type:
{"searchTerm": "developer","state": "São Paulo","workplaceTypes": ["remote"],"sortBy": "newest","maxItems": 20}
One company's career page, with full detail per job:
{"companies": ["Sample Company"],"fetchDetails": true,"maxItems": 50}
Supported link types (URL mode):
| Link type | Example |
|---|---|
| Portal search, term in the path | https://portal.gupy.io/job-search/term=developer |
| Portal search with filters (state, workplaceTypes[]) | https://portal.gupy.io/job-search/term=developer&state=S%C3%A3o%20Paulo&workplaceTypes[]=remote |
Portal search with sortBy and page (starts at that page of 10; a partial scan, so never produces EXPIRED) | https://portal.gupy.io/job-search/term=developer&sortBy=publishedDate&page=2 |
| Company career page (lists that company's jobs) | https://tfcarreira.gupy.io/ |
| Portal search by location only (state and city, no term) | https://portal.gupy.io/job-search/state=S%C3%A3o%20Paulo&city=S%C3%A3o%20Paulo |
| Portal search filtered to one company | https://portal.gupy.io/job-search/careerPageName[]=FARM |
| Job detail with the base64 job token | https://tfcarreira.gupy.io/job/eyJqb2JJZCI6MTI3NDg4MzIsInNvdXJjZSI6Imd1cHlfcG9ydGFsIn0=?jobBoardSource=gupy_portal |
Any other company-site link (for example a bare numeric /job/12748832) is skipped with a warning in the log instead of silently widening to all jobs.
Behaviour change: URL mode with the urls field left out now scrapes these 7 examples instead of nothing. Companies and cities typed by hand are matched ignoring case and accents (company names also by part of the name); a name that matches nothing fails the run with a clear message.
Paste links (portal search and a direct job page):
{"mode": "url","urls": ["https://portal.gupy.io/job-search/term=developer&state=Bahia","https://sample-company.gupy.io/job/eyJqb2JJZCI6MzA1MDAwMX0="],"maxItems": 10}
Recurring monitoring of the same search, including jobs that disappear:
{"searchTerm": "developer","incrementalMode": true,"emitExpired": true,"maxItems": 0}
Run it from your code
Python:
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("abotapi/gupy-io-scraper").call(run_input={"searchTerm": "developer", "state": "São Paulo"})for job in client.dataset(run["defaultDatasetId"]).iterate_items():print(job["name"], job["careerPageDisplayName"])
JavaScript:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });const run = await client.actor('abotapi/gupy-io-scraper').call({ searchTerm: 'developer', state: 'São Paulo' });const { items } = await client.dataset(run.defaultDatasetId).listItems();
Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.
How Max items and Max pages shape a run
Max items is a soft cap on saved rows (default 20, 0 means unlimited). Max pages defaults to 0, meaning the walk covers every result page; a positive number stops the walk after that many API pages, whichever limit is reached first. Gupy's own reported result total is not a reliable stop signal once a search has many matches, so the walk instead relies on a page coming back empty, coming back shorter than requested, or containing no job the run has not already collected (after earlier pages of that same search did add new jobs). Fewer rows than Max items may still come back when the chosen source and filters simply match fewer live jobs.
A known limitation of that last stop rule. "Already collected" is judged against everything this run holds, not just the current search: jobs from earlier links in the same run, and jobs reloaded by Resume. So a search can stop before its real last page, with no error, in two cases:
- Several overlapping search links in one run (URL mode). If a later link finds some new jobs, then hits a full page of jobs an earlier link already returned, that later link stops there and its deeper pages are skipped. Search mode builds a single search and is not affected by this case. Run overlapping links as separate runs.
- Resume after new jobs were posted. When
resumeFromRunId(or an automatic restart after a platform migration) replays a search whose first pages now hold a few newly posted jobs ahead of the ones already collected, the next page of already collected jobs ends the walk, so jobs beyond the earlier stopping point are not reached. If a resumed run returns far fewer jobs than expected, run the search again without Resume instead.
Resume and recurring updates
- Resume (
resumeFromRunId) continues a catalogue walk from an earlier run that finished and saved its jobs, for example one stopped by Max items: paste its run or dataset ID and jobs already collected there (matched by job ID) are skipped, so this run only appends new ones. Jobs are written to the dataset only when a run finishes, so a run that was aborted or failed partway has nothing to resume from; resurrect that run instead, and it reloads its own saved progress. An unreadable run or dataset ID fails the run immediately, before any scraping starts. - Incremental mode (
incrementalMode) is for scheduling this same search again and again. Each run classifies every job against the last run's state for that search (kept automatically, or under your ownstateKey) and adds achangeType:NEW(not seen before),UPDATED(a field changed, listed inchangedFields),UNCHANGED(nothing changed, suppressed unlessemitUnchangedis on),REAPPEARED(was marked EXPIRED, found again), orEXPIRED(tracked before, not found in a run that fully scanned this search, only produced whenemitExpiredis on). A job counts asUPDATEDwhen any saved field differs from the last tracked run;scrapedAtandexpireDays(a day count that drifts daily) are always left out of the comparison, and you can add more withignoreFieldsForChanges. Ignored fields stay in the output. Nested fields use dotted paths such assource.salary. The first incremental run after this release does not mark tracked jobsUPDATEDjust because the new fields appeared (applicationQuestions,requiredApplicationFields,companyIntegrations,relevantExperiences), because company, career page, image, video and state code fields that used to be empty are now filled when the full record is fetched, or becausesourceQuerynow records the start page of a pastedpage=Nlink and the career page of a pasted company link (https://<company>.gupy.io/, which is now scoped to that company instead of searching all jobs). After that first run, a real change in any of them counts asUPDATEDas usual. A pasted single job link is a partial scan, so it never producesEXPIRED. The first complete run of a tracked company career page link after this release does not mark the unrelated jobs that the earlier unscoped search collected asEXPIRED(they are outside the new scope, so they are dropped from the saved state quietly and are not saved or billed); use a freshstateKeyif you prefer a clean start. Every job also carriesfirstSeenAtandlastSeenAt.EXPIREDis only ever computed when the run reaches the natural end of the walk; a run capped by Max items or Max pages, or one started withresumeFromRunId, skips it for that run and keeps the previous state as is. One exception to watch for: an early stop caused by overlapping search links (described above) still counts as reaching the natural end, so withemitExpiredon, a URL mode run with several overlapping links can mark still live jobsEXPIRED. Keep each tracked search to one link per run if you rely onEXPIRED. TurningincrementalModeon together withresumeFromRunIdfails the run if that search already has saved incremental state; remove one of the two, or set a differentstateKey. With Incremental mode off, output is exactly as before.
Send results into your apps (MCP connectors)
Optionally pipe the scraped jobs into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.
What gets written to the connector: a condensed, human readable summary of each job, not the full JSON. Each job becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where job pages should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third party credentials. Leave the field empty to skip.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | search | search (filters below) or url (portal search links and direct Gupy job links). |
searchTerm | string | (empty) | Job title, skill, or keyword. Leave empty to scrape all jobs matching the other filters. |
state | string | (empty) | Brazilian state filter. Leave empty for all states. |
cities | array | [] | Gupy city names. Leave empty for all cities. |
workplaceTypes | array | [] | Remote, hybrid, or on site jobs. Leave empty for all workplace types. |
jobTypes | array | [] | Gupy vacancy type values (full time, apprentice, internship, trainee, and more). Leave empty for all job types. |
companies | array | [] | Gupy career page names. Leave empty for all companies. |
pwdOnly | boolean | false | Return only jobs marked for people with disabilities. |
friendlyBadgeOnly | boolean | false | Return only jobs from companies with Gupy's feedback badge. |
urls | array | the 7 example links below | Portal search URLs, company career pages or direct Gupy job URLs. Used only when Mode is url. If you leave the field out, the 7 examples run (one per supported link type); pass [] to run none. |
fetchDetails | boolean | false | Fetch the full per job record before saving each result (search mode and portal search URLs only; direct job URLs are always fetched in full and always carry the detail enrichment charge). Adds the detail enrichment charge per enriched job actually saved. |
sortBy | string | newest | Sort saved jobs after collection: newest, oldest, or company (A to Z). |
maxItems | integer | 20 | Maximum matching rows to save. 0 means unlimited. Fewer rows may come back when the source and filters match fewer live jobs. |
maxPages | integer | 0 | Leave at 0 to walk every result page. A positive number stops the walk after that many API pages. |
pageSize | integer | 100 | API page size, from 1 to 100. |
resumeFromRunId | string | (none) | A previous run ID or dataset ID to continue a full catalogue walk. Jobs already collected there are skipped. |
incrementalMode | boolean | false | Track this search's results between scheduled runs and classify each job as NEW, UPDATED, UNCHANGED, REAPPEARED, or EXPIRED. |
stateKey | string | (none) | Name an incremental mode baseline explicitly. Leave empty to derive one automatically from the search filters. |
emitUnchanged | boolean | false | Incremental mode only. Also return (and bill) jobs unchanged since the last tracked run. |
emitExpired | boolean | false | Incremental mode only. Also return (and bill) jobs tracked before but no longer found, after a run that fully scans the search. |
maxResults | integer | (none) | Alias of maxItems; maxItems wins when both are set. |
feedback | string | (none) | Optional free text note to the developers. Has no effect on the scrape. |
ignoreFieldsForChanges | array | (none) | Incremental mode only. Field names (dotted paths for nested fields) that never count as a change: they stay in every row but cannot make a job UPDATED or show up in changedFields. |
mcpConnectors | array | (none) | Optionally send the scraped jobs into the apps you already use, via MCP connectors. Leave empty to skip. |
notionParentPageUrl | string | (none) | Notion connector only: page under which job pages are created. |
maxNotifyListings | integer | 50 | Cap on jobs written to each connector per run. Does not affect the dataset. |
proxyConfiguration | object | Apify Proxy | Connection settings, honoured on every run (see Plan Requirement). |
The dataset has three views in the Console: Jobs overview, Job details (full description, application questions and company data) and Changes (incremental) (changeType, changedFields, firstSeenAt, lastSeenAt).
Output Example
Sample shape: values are illustrative placeholders, not from a live record.
{"id": 3050001,"code": "9001-3050001","name": "Analista de Sistemas Pleno","jobUrl": "https://sample-company.gupy.io/job/eyJqb2JJZCI6MzA1MDAwMX0=","description": "<p>Full HTML job description as published.</p>","descriptionPlainText": "Full job description, converted to plain text.","prerequisites": null,"city": "São Paulo","state": "São Paulo","stateCode": "SP","country": "Brasil","countryCode": "BR","jobType": "vacancy_type_effective","workplaceType": "hybrid","isRemoteWork": false,"publishedAt": "2026-08-01T12:00:00.000Z","applicationDeadline": "2026-09-15T23:59:59.000Z","expireDays": 17,"companyId": 9001,"companySubdomain": "sample-company","careerPageName": "Sample Company","careerPageDisplayName": "Sample Company","careerPageUrl": "https://sample-company.gupy.io","hasFriendlyBadge": true,"badgeIsPWD": false,"skills": ["Comunicação", "Excel"],"sourceQuery": { "searchTerm": "developer", "state": "São Paulo", "cities": [], "workplaceTypes": [], "jobTypes": [], "companies": [], "pwdOnly": false, "friendlyBadgeOnly": false },"detailFetched": true,"source": {},"scrapedAt": "2026-09-29T09:00:00.000Z"}
Plan Requirement
The default connection setting is Apify Proxy, and the Connection input is honoured on every run. The default Apify datacenter connection was measured serving Gupy: the portal search pages, company career pages, job pages and the job search data all loaded, so the default needs no residential proxy and no action on a plan that includes Apify Proxy. Apify free plans do not include any Apify proxy, so on a free plan the actor reports what happened in the run log and continues on a backup connection:
- If the selected connection is unavailable, the log shows "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable." Once the backup connection serves data it logs "Served over the backup connection (the default connection was unavailable)."
- If no results page can be loaded at all, the run fails instead of returning an empty dataset, with one of three messages: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required" (also check your own proxy URLs if you entered any); "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested Gupy pages"; or "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."
If you hit these, upgrade your Apify plan or supply your own proxy URLs under Connection.
FAQ
How much does it cost?
You pay per job saved, plus a one time actor start fee, with the detail enrichment charge added for each job whose full record was fetched and that actually reaches the dataset: every job when Fetch details is on, and always for jobs from direct Gupy job links. The Pricing tab shows the current rates. The detail enrichment charge is applied right after each batch of up to 50 saved jobs is written, only for the jobs in that batch whose full record was fetched, never for a job that was not saved. Events charged: the actor start (once per run), the saved job (per job) and the detail enrichment (per enriched job). Use Max items to cap the cost of any run.
Is it legal to scrape Gupy.io?
This actor collects only publicly available job listings. You are responsible for how you use it: follow Gupy.io's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution.
Can I get only new or changed jobs on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only NEW, UPDATED, and REAPPEARED jobs for that search, and unchanged ones are not billed unless you turn on Emit unchanged.
Why did my run return fewer jobs than I expected?
Max items and Max pages both cap a run, and Gupy's own reported result total is not a reliable signal once a search has many matches. Raise Max items, raise or clear Max pages, or set Max pages to 0, to walk the whole result set. Two cases can also end a search early without an error: several overlapping search links in one URL mode run, and a Resume run after new jobs were posted. Both are described under "How Max items and Max pages shape a run" above.
Why did my run fail instead of returning an empty dataset?
Two situations fail the run outright rather than returning an empty dataset: pasting a Resume from a previous run ID that this Apify account cannot read (checked before any scraping starts), and turning on Incremental mode together with Resume from a previous run when that search already has saved incremental state. Fix the ID, or remove one of the two settings, and run it again. A run also fails when no results page could be loaded through any connection (see Plan Requirement), and when a company or city you typed matches nothing.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear, or Airtable.
🔗 Want more jobs data?
Pair this actor with these related scrapers from the same team:
| 💼 Jora Jobs Scraper Scrape Jora.com job listings across supported countries by keyword, filters, or URL... | 💼 Workday Jobs Scraper Scrape job postings from any Workday-hosted careers site on Myworkdayjobs.com. Paste... |
| 🏷️ FINN.no Jobs Scraper Scrape active FINN.no job listings by search filters or URL. Extract 30+ fields including... | 💼 Jobsite UK Collect UK job listings from Jobsite.co.uk at scale. Search by keyword, location... |
| 💼 We Work Remotely Scraper Extract current remote job listings from weworkremotely.com. Use keyword search or WWR... | 💼 EdJoin.org Scraper Scrape EdJoin.org K-12 and higher-ed jobs by keyword, location, filters or URL. Extract... |
💬 Support
- 🐞 Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
- 🛠️ Need another site, extra fields or a private build? Email contact@abotapi.com.
- ⭐ Enjoying it? A quick review on the actor page helps other users find it.