Skip to content

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.

  1. 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.)
  2. 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.

Apps Script can call RolesAPI with UrlFetchApp, which supports the Authorization header, and rewrite a sheet on a schedule.

  1. In your spreadsheet: Extensions > Apps Script.
  2. In the script editor, open Project Settings > Script Properties and add ROLESAPI_KEY with your rk_ key — keeps the key out of the code.
  3. 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);
}
}
  1. Run refreshJobs once from the editor to authorize it and check the output.
  2. 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.

RolesAPI is not affiliated with, endorsed by, or sponsored by Indeed, Inc. Indeed is a registered trademark of Indeed, Inc. RolesAPI provides access to publicly available data via a stable REST API.