Export Indeed jobs to Google Sheets
Google Sheets is where a lot of job-market tracking actually lives. Here are three ways to get RolesAPI data into a sheet, from zero-code to fully automated.
Option A: Download a CSV, then File > Import
No code at all.
- In the dashboard, run a search or open a completed job and download the results as CSV. (Any results endpoint also serves CSV directly — add
?format=csv. See Output formats.) - In Sheets: File > Import > Upload, choose the CSV, and pick “Insert new sheet(s)”.
Nested fields arrive as dot-path columns (company.name, salary.min) and array fields joined with |, so the sheet is immediately sortable and filterable. Best for one-off analyses.
Option B: Apps Script on a time trigger (recommended for automation)
Apps Script can call RolesAPI with UrlFetchApp, which supports the Authorization header, and rewrite a sheet on a schedule.
- In your spreadsheet: Extensions > Apps Script.
- In the script editor, open Project Settings > Script Properties and add
ROLESAPI_KEYwith yourrk_key — keeps the key out of the code. - Paste this script:
const BASE = "https://api.rolesapi.com";const SHEET_NAME = "Jobs";
function refreshJobs() { const key = PropertiesService.getScriptProperties().getProperty("ROLESAPI_KEY");
const response = UrlFetchApp.fetch( BASE + "/v1/listings?keyword=" + encodeURIComponent("backend engineer") + "&location=" + encodeURIComponent("Austin, TX") + "&country=us&sort=date", { headers: { Authorization: "Bearer " + key } } ); const body = JSON.parse(response.getContentText()); const roles = body.data;
const rows = roles.map(function (r) { return [ r.job_key, r.title, r.company && r.company.name, r.location, r.remote, r.posted_at, r.url, ]; });
const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName(SHEET_NAME) || ss.insertSheet(SHEET_NAME); sheet.clearContents(); sheet .getRange(1, 1, 1, 7) .setValues([["job_key", "title", "company", "location", "remote", "posted_at", "url"]]); if (rows.length) { sheet.getRange(2, 1, rows.length, 7).setValues(rows); }}- Run
refreshJobsonce from the editor to authorize it and check the output. - Add the schedule: Triggers (clock icon) > Add Trigger, choose
refreshJobs, event source “Time-driven”, and an interval such as daily.
Each run makes one GET /v1/listings call — 1 credit per refresh, so a daily trigger costs about 30 credits a month. To pull larger sets, submit an async preset like posted-this-week in one function and read GET /v1/jobs/{id}/results in a second run.
Option C: Why =IMPORTDATA does not work (and what to do)
=IMPORTDATA("https://api.rolesapi.com/v1/jobs/job_01hxyz/results?format=csv") looks tempting: results endpoints do serve CSV. But IMPORTDATA cannot send headers, and RolesAPI authenticates with the Authorization: Bearer rk_... header — so the call returns 401 missing_api_key and the formula fails.
Putting a key in the URL is not supported, deliberately: spreadsheet formulas are visible to every viewer of the sheet, get copied between files, and end up in version history — the worst possible place for a credential.
Use option A for one-offs and option B for anything recurring; option B keeps the key in Script Properties, invisible to sheet viewers.