This guide explains how to connect JobNimbus directly to Google Sheets using Google Apps Script and the JobNimbus API. The goal is a lightweight reporting pipeline that automatically pulls job data into a structured spreadsheet for reporting, dashboards, and operational visibility — and, further down, a live map of real jobs on your website.
If you want a native, direct connection without paying for a third-party automation service, this is the method: Google's built-in JavaScript engine talking straight to the JobNimbus API. No Zapier, no monthly connector fees.
Why this integration matters
Most teams using JobNimbus rely on manual exports or limited reporting views. A direct data connection between JobNimbus and Google Sheets lets you:
- Build custom dashboards in Google Sheets
- Track job status in real time
- Filter jobs by date, status, or type
- Combine JobNimbus data with other business systems
- Automate reporting without third-party tools
How the integration works
This solution uses Google Apps Script and UrlFetchApp to communicate directly with the JobNimbus API. The script:
- Authenticates using a JobNimbus API key
- Pulls job data from the JobNimbus API
- Handles pagination for large datasets
- Filters jobs by a configurable time window (default 365 days)
- Extracts and maps key job fields
- Writes structured results into Google Sheets
Step 1: Open Google Apps Script
- Open your Google Sheet
- Go to Extensions → Apps Script
- Remove any default code in the editor
Step 2: Add the script
Paste the following script into the editor:
Code.gs — JobNimbus → Google Sheets/********* CONFIG *********/
const API_KEY = 'PUT_YOUR_JOBNIMBUS_API_KEY_HERE';
const BASE_URL = 'https://app.jobnimbus.com/api1';
const PAGE_SIZE = 100;
const MAX_PAGES = 200;
/********* QUERY STRING HELPER *********/
function toQuery_(obj) {
return Object.keys(obj)
.filter(k => obj[k] !== undefined && obj[k] !== null && obj[k] !== '')
.map(k => Array.isArray(obj[k])
? obj[k].map(v => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&')
: `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`
)
.join('&');
}
/********* FETCH JOB DATA *********/
function fetchJobsAll_({ updatedAfterISO } = {}) {
const headers = {
Authorization: `Bearer ${API_KEY}`
};
let allJobs = [];
let page = 1;
for (; page <= MAX_PAGES; page++) {
const params = {
page: String(page),
pageSize: String(PAGE_SIZE),
...(updatedAfterISO ? { updatedAfter: updatedAfterISO } : {})
};
const url = `${BASE_URL}/jobs?${toQuery_(params)}`;
const response = UrlFetchApp.fetch(url, {
method: 'get',
headers
});
const data = JSON.parse(response.getContentText());
const jobs = Array.isArray(data)
? data
: (data.results || data.items || data.data || []);
if (!jobs.length) break;
allJobs = allJobs.concat(jobs);
if (jobs.length < PAGE_SIZE) break;
}
return allJobs;
}
/********* WRITE TO SHEET *********/
function writeToSheet_(sheetName, headers, rows) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName(sheetName);
if (!sheet) sheet = ss.insertSheet(sheetName);
sheet.clearContents();
sheet.getRange(1, 1, 1, headers.length).setValues([headers]);
if (rows.length) {
sheet.getRange(2, 1, rows.length, headers.length).setValues(rows);
}
}
/********* FIELD EXTRACTION *********/
function getJobType_(job) {
return job.record_type_name || '';
}
function getJobStatus_(job) {
return job.status_name || '';
}
function getJobDescription_(job) {
return job.description || '';
}
function getAddress_(job) {
return [
job.address_line1,
job.address_line2
].filter(Boolean).join(', ');
}
/********* MAIN FUNCTION *********/
function Load_Jobs_Address_JN() {
// Default: last 365 days (customizable)
const updatedAfterISO = new Date(
Date.now() - 365 * 24 * 60 * 60 * 1000
).toISOString();
const jobs = fetchJobsAll_({ updatedAfterISO });
const headers = [
'Job Type',
'Address',
'City',
'ZIP',
'Description',
'Status'
];
const rows = jobs.map(job => {
return [
getJobType_(job),
getAddress_(job),
job.city || '',
job.zip || '',
getJobDescription_(job),
getJobStatus_(job)
];
});
writeToSheet_('Jobs (Address)', headers, rows);
}
Step 3: Run the script
- Select the function
Load_Jobs_Address_JN - Click Run
- Authorize permissions when prompted
- A new sheet tab is created automatically
What this script does
- Connects to the JobNimbus API using Bearer token authentication
- Loops through paginated job results
- Normalizes job fields for reporting
- Writes structured output into Google Sheets
- Refreshes data based on a rolling 365-day window
Configurable options
Change the data window by adjusting the number of days in the main function:
90 daysnew Date(Date.now() - 90 * 24 * 60 * 60 * 1000)
180 days
new Date(Date.now() - 180 * 24 * 60 * 60 * 1000)
365 days (default)
new Date(Date.now() - 365 * 24 * 60 * 60 * 1000)
Load_Jobs_Address_JN on a schedule — hourly or daily depending on how often your crews close out jobs.
Use case: a realtime website job map
This integration is what powers a realtime website job listing map that updates automatically from JobNimbus. As jobs are created or updated, the data flows into Google Sheets, which then feeds a live map on the website.
The map shows real job locations, service activity, and completed work across geographic regions — a dynamic visualization of service coverage instead of static service descriptions. Seeing actual work in real locations improves transparency and builds trust.
Instead of telling visitors where you work, you show them — every recent job, pinned on a live map.
Local service map pin optimization
We also build a map pin optimization system for local service businesses. It turns JobNimbus job data into structured geographic signals that improve both user experience and search visibility, combining job data, Google Sheets, and structured schema markup so search engines better understand your service coverage areas.
Key capabilities:
- Auto-updated job pin map powered by JobNimbus + Google Sheets
- Real-time display of service activity on your website
- Stronger trust through visible proof of completed work
- Stronger local SEO signals across Google, Apple, and Bing Maps
- LLM-optimized
LocalBusinessschema for better entity and location understanding
Why this works
Search engines rely on structured data, geographic consistency, and entity signals to determine local relevance. By connecting job-level data to structured mapping and schema markup, you give both people and algorithms far clearer proof of where you operate and what you deliver — which is exactly what earns local visibility and trust.
Frequently asked questions
Does JobNimbus have an API?
Yes. JobNimbus offers a REST API that returns your contacts, jobs, and activities as JSON. Requests are authenticated with an API key sent as a Bearer token, which is exactly what the Apps Script above uses to pull job records into Google Sheets.
Can I connect JobNimbus to Google Sheets without Zapier?
Yes. No-code tools like Zapier, Make, or Integrately can connect the two, but they aren't required. Google Apps Script talks directly to the JobNimbus API using UrlFetchApp, so you get a native connection with no third-party middleman — the method shown in this guide.
Is it free to connect JobNimbus to Google Sheets?
The Apps Script method is free — it runs inside your own Google account with no subscription. No-code automation platforms typically charge a monthly fee once you exceed their free task limits, so for straightforward reporting the script route usually costs nothing beyond your existing JobNimbus and Google accounts.
Where do I find my JobNimbus API key?
Log into JobNimbus as a user with Settings access, open your API settings, create a new key (assigning it an access profile with the permissions you need), and copy the generated key. Paste it into the API_KEY value at the top of the script. Treat the key like a password — anyone who has it can read your data.
Do I need to know how to code?
Not really. You can copy the script as-is, paste in your API key, and run it. Some comfort reading JavaScript helps if you want to add fields or change filters, but the default setup works out of the box. If you'd rather not touch code at all, a no-code tool is the alternative.
How often can the data refresh?
As often as you like. Add a time-driven trigger in Apps Script (Triggers → Add Trigger) to run the function on a schedule — hourly, daily, or your own interval. That keeps the sheet, and anything downstream of it like a live job map, current without manual exports.
What JobNimbus data can I pull into Google Sheets?
The API exposes jobs, contacts, and activities along with their fields — status, type, address, dates, and more. This script maps job type, address, city, ZIP, description, and status, and you can filter by a rolling time window. Adjust the field extraction functions to capture any additional fields your reporting needs.
Is connecting JobNimbus to Google Sheets secure?
The script runs inside your own Google account and stores the API key in your private Apps Script project rather than sending it to an outside service. Keep the key confidential, use read-only reporting where possible, and rotate or delete the key in JobNimbus if it's ever exposed.