Daily JSearch job tracker with Google Sheets log and Slack recap

By General Input

Every weekday at 7am ET, pull fresh job postings from JSearch for each saved search, log the new ones to a Google Sheet, and post a Slack recap.

Integrations

  • JSearch
  • Google Sheets
  • Slack Bot

Type

Deterministic Code

Categories

  • HR & People
  • Operations

Build a code workflow that runs every weekday at 7am America/New_York and keeps a Google Sheet up to date with fresh job postings from JSearch, then posts a Slack recap. Pure deterministic pipeline: read, fetch, diff, append, notify.

Trigger: cron, Monday through Friday at 07:00 ET.

Inputs the workflow should expose as configuration: the Google Sheets spreadsheet id, the name of the Queries tab (default "Queries"), the name of the Tracked tab (default "Tracked"), and the Slack channel id for the recap.

Step 1 — Read saved searches from Google Sheets using Get Values on the Queries tab. Each row holds a query string in column A (for example "senior backend engineer remote") plus optional filter columns: employment_types (full-time, part-time, contract, intern, comma-delimited) and date_posted (today, 3days, week, month). Skip the header row and skip any row with an empty query.

Step 2 — Read the existing tracked job ids from Google Sheets using Get Values on the Tracked tab, column A only (the job_id column). Build an in-memory set of ids already seen so we can dedupe.

Step 3 — For each row from step 1, call JSearch Search Jobs with that row's query and filters. Use page=1 and num_pages=1 unless overridden. Note that JSearch expects employment_types and date_posted as query string params, and the location should be embedded inline in the query string (the API has no separate location parameter). Collect each returned posting's job_id, job_title, employer_name, job_city/job_state/job_country, job_posted_at_datetime_utc, job_min_salary/job_max_salary/job_salary_currency/job_salary_period, and job_apply_link.

Step 4 — Dedupe. Drop any posting whose job_id is already in the set from step 2. Also dedupe across queries within this run so a posting that matches two saved searches is only logged once (keep it under the first query that matched, for the recap).

Step 5 — Append the new rows to the Tracked tab using Append Values with valueInputOption USER_ENTERED. Columns, in order: job_id, title, company, location (formatted "City, State, Country" with empty parts omitted), posted_at (ISO date), salary_range (formatted like "$120k–$150k / year" when min and max are present, otherwise the single value or empty), apply_url.

Step 6 — Post one Slack message via Slack Bot Send a Message to the configured channel. Format with Slack mrkdwn. Headline line: "Fresh roles for {weekday date}: {total new} new". Then one section per query that produced results, in the form "*{query}* — {count} new", followed by up to 5 bullet lines linking the top postings as "<{apply_url}|{title}> at {company}". Omit queries that returned zero new postings. If the entire run produced zero new postings across every query, still post a short "No new roles today" message so the channel knows the watcher is alive.

Error handling: if JSearch returns a 429 or 5xx for a particular query, log the failure and continue with the next query rather than aborting the whole run; surface failed queries at the bottom of the Slack recap as "Could not fetch: {query}".

Integrations to use: jsearch (Search Jobs), google-sheets (Get Values, Append Values), slackbot (Send a Message).

Related prompts

Explore more prompts
Call overdue Xero customers with an AI collections agentLocal listing health board for every location you manageLet support send one-off Loops emails without an engineerA brand asset library your marketing team actually searchesTurn Mailjet email clicks into ranked HubSpot follow-upsClean out the Looker dashboards and Looks nobody opensStop cold emails to anyone with a live deal in PipedriveLiveKit live operations console for room moderationWake up dormant Keap leads with a researched reasoniMessage campaign console with pre-flight checks and delivery board