---
title: "Greenhouse jobs sync settings"
description: "Board token, import schedule, JobPosting schema for Google for Jobs, sitemap, emails, filters and archives: every Greenhouse jobs sync setting explained."
source: https://greenhouse.w4dev.com/docs/settings/
---

Every setting below is on **Greenhouse → Settings**. Each one is stored as the WordPress option
in the Option column, so WP-CLI can read it: `wp option get ghjb_apply_mode`.

## Greenhouse job board: connection and applications

| Setting | Option | Default | What it does |
|---|---|---|---|
| Board token | `ghjb_board_token` | empty | Required. Your Greenhouse board token, such as `acme`: the last part of `https://job-boards.greenhouse.io/acme`. The full job board address also works, from `job-boards.greenhouse.io` or `boards.greenhouse.io`, and so does the address in Greenhouse's embed code. A new token is checked with Greenhouse on save: when Greenhouse has no board by that name, it is not saved and the previous value stays. When Greenhouse can't be reached, the token is saved and the next import reports the problem. A `job-boards.eu.greenhouse.io` address marks the board as one in Greenhouse's EU data centre; for a bare token, the plugin asks the EU data centre once on save. The answer is stored as `ghjb_board_region`, and reads and applications then go to that data centre. If the EU data centre can't be reached for that check, the region is stored as `unknown`, the settings page shows a warning, and reads and applications go to the US data centre until the check succeeds. It runs again on the next save and the next import. |
| Job Board API key | `ghjb_api_key` | empty | Optional. Turns on on-site applications; must be a **Job Board** key, not a Harvest key. Blank keeps the saved key; **Remove** deletes it. [How to create one](/docs/installation/#4-optional-add-a-job-board-api-key). |
| Applications | `ghjb_apply_mode` | `auto` | Where candidates apply. See the next table. |

### Where candidates apply

| Mode | Value | With a key | Without a key |
|---|---|---|---|
| Automatic | `auto` | On-site form | **Apply on Greenhouse** button |
| On-site application form | `form` | On-site form | **Apply on Greenhouse** button |
| Send applicants to Greenhouse | `redirect` | **Apply on Greenhouse** button | **Apply on Greenhouse** button |

The on-site form always needs a key, so **Automatic** and **On-site application form** behave
the same. Choose **Send applicants to Greenhouse** to keep a saved key but use the Greenhouse
posting's own form.

The **Apply on Greenhouse** button links to the job's Greenhouse posting. When that address
points back at your own site, as it does when your board is embedded on your careers page, the
button links to Greenhouse's hosted application form for the job instead:
`https://job-boards.greenhouse.io/embed/job_app?for=<board token>&token=<job id>` (`job-boards.eu.greenhouse.io` for a board in the EU data centre).

Even with the form on, a job shows the **Apply on Greenhouse** button when its questions cannot
be loaded. If Greenhouse rejects the key (HTTP 401 or 403) when an application is sent,
the applicant sees "Applications are temporarily unavailable. Please try again later." and
administrators see a notice in wp-admin. The notice clears when you save a new key, dismiss
it, or after a day. See [when the API key stops working](/docs/on-site-applications/#when-the-api-key-stops-working).

## Display: jobs address and import schedule

| Setting | Option | Default | What it does |
|---|---|---|---|
| Jobs page slug | `ghjb_jobs_page_slug` | `jobs` | The job list's address. With `jobs`, the list is at `/jobs/` and each job at `/jobs/{job-title}-{id}/`, where the id is Greenhouse's numeric job ID. A change applies on the next page load. |
| Import interval | `ghjb_sync_interval` | `30` minutes | How often jobs are re-imported from Greenhouse, from 15 to 1440 minutes. A change applies from the next scheduled run. |
| Pay ranges | `ghjb_show_pay` | on | Shows the pay ranges Greenhouse publishes for a job: a **Pay range** row on the job page and, when the pay period is clear, `baseSalary` in its `JobPosting` data. Off hides both. Greenhouse only shares ranges set to show on the job post. |

Pay ranges are read during the import, for new and changed jobs, up to 50 jobs per run
(developers: filter `ghjb_pay_ranges_per_run`). On a large board the rest follow on the next
runs. A failed pay read never fails the import.

There is no cache setting. Job lists and pages are read from your database. Each job's
application questions are cached for one hour (developers: filter `ghjb_application_form_ttl`).

## Features: schema, sitemap and submissions log

| Setting | Option | Default | What it does |
|---|---|---|---|
| JSON-LD schema | `ghjb_enable_schema` | on | Adds `JobPosting` structured data to each job page, which Google for Jobs reads. |
| Jobs sitemap | `ghjb_enable_sitemap` | on | Lists job pages in the WordPress XML sitemap, at `/wp-sitemap-posts-ghjb_job-1.xml`, and each [job archive](/docs/job-archives/) in its own taxonomy sitemap. Turn it off to leave them all out. |
| Log submissions | `ghjb_log_submissions` | on | Keeps the last 100 application attempts under **Greenhouse → Submissions**. [What each entry shows](/docs/on-site-applications/#the-submissions-log). |

The schema makes your job pages eligible for Google for Jobs. Greenhouse's hosted job page may
carry `JobPosting` data for the same job, and Google chooses which listing to show. A job that
names no location Google accepts, such as "Remote - Europe" with no office address, gets no
`JobPosting` data at all, because Google rejects it. Its **Greenhouse data** box says what to add.

### Meta descriptions and SEO plugins

Each job page gets its own meta description, with no setting to turn on:
`Title. Location · Type. Summary…`, up to 155 characters. The summary is the first paragraph
after the company intro: an "About us" style section, and paragraphs at least half of your jobs
share, are skipped. The jobs page and each [job archive](/docs/job-archives/#what-a-job-archive-page-shows)
get one naming the page and your organization.

Without an SEO plugin, the plugin prints the description with canonical and social tags. With
Yoast SEO, Rank Math, AIOSEO, SEOPress or Slim SEO active, it prints none of them and leaves
those tags to that plugin. Yoast SEO and Rank Math still get the plugin's description where they
have none of their own; for a job, Rank Math's automatic one is replaced too. Developers can
change the text with the `ghjb_job_meta_description` and `ghjb_archive_meta_description`
[filters](/docs/templates/#developer-hooks).

## Schema: hiring organization and validity

These fill the `JobPosting` data when **JSON-LD schema** is on.

| Setting | Option | Default | What it does |
|---|---|---|---|
| Organization name | `ghjb_organization_name` | empty | The `hiringOrganization` name. Empty uses the company name Greenhouse returns with your jobs, or your site name when there is none. Developers: filter `ghjb_organization_name`. |
| Organization logo URL | `ghjb_organization_logo` | empty | Full URL of a logo image, added to `hiringOrganization`. Google for Jobs shows it next to your postings. |
| Job validity | `ghjb_job_validity_days` | `30` days | Sets `validThrough` this many days ahead, from 0 to 365. The count starts from the posting date or the last import that found the job still open, whichever is later, so an open job never shows as expired. A job with an application deadline in Greenhouse uses that date instead. `0` leaves `validThrough` out, for roles open longer than a year. Jobs stay listed until they close in Greenhouse either way. |

## Privacy: consent checkbox

| Setting | Option | Default | What it does |
|---|---|---|---|
| Consent checkbox | `ghjb_enable_gdpr` | off | Adds a required consent checkbox to the on-site application form. |
| Consent text | `ghjb_gdpr_text` | empty | The wording next to the checkbox. Links and basic formatting are allowed, so you can link your privacy policy. Empty shows "I consent to my data being stored and processed for recruitment purposes." |

When a job's Greenhouse data-compliance settings ask for consent, the form shows the checkbox
for that job even with this setting off, and sends the answer to Greenhouse.

## Spam protection: Turnstile or reCAPTCHA

Configure one provider, or neither. A provider is used only when both its site key and its
secret key are saved: only then does the form show its widget, load its script and require its
answer. Without one, the form relies on its
[honeypot field and rate limit](/docs/on-site-applications/#what-happens-when-someone-applies).

| Setting | Option |
|---|---|
| Turnstile site key | `ghjb_turnstile_site` |
| Turnstile secret key | `ghjb_turnstile_secret` |
| reCAPTCHA site key | `ghjb_recaptcha_site` |
| reCAPTCHA secret key | `ghjb_recaptcha_secret` |

reCAPTCHA must be a **v3** key. Submissions scoring below 0.5 are rejected; the filter
`ghjb_recaptcha_score_threshold` changes that. Saved secret keys are never shown. Leave a secret
blank to keep the saved one, or tick **Remove** next to it to delete it.

## Application emails: hiring team and applicant

Both emails go out only after Greenhouse accepts an application made on your site. Greenhouse
may already notify your hiring team and acknowledge candidates, so turn these on only if yours
doesn't.

| Setting | Option | Default | What it does |
|---|---|---|---|
| Notify the hiring team | `ghjb_notify_admin` | off | Emails the job and the applicant's name, email and phone. Reply goes to the applicant. |
| Notification recipients | `ghjb_notify_admin_to` | empty | Comma-separated addresses. Empty sends to the site admin email. Invalid addresses are removed on save, with a warning. |
| Confirm to the applicant | `ghjb_notify_applicant` | off | Emails the applicant a confirmation. |
| Confirmation subject | `ghjb_applicant_subject` | We received your application for {job_title} | One line of text. |
| Confirmation message | `ghjb_applicant_body` | A short thank-you signed with your site name | Plain text. |

The subject and message take the placeholders `{first_name}`, `{last_name}`, `{job_title}`,
`{job_url}` and `{site_name}`. Leave either blank to use the default.

Emails are plain text and never carry the resume or answers; those stay in Greenhouse. A failed
email never fails the application. It shows as **Email failed** in
[the Submissions log](/docs/on-site-applications/#the-submissions-log).

## Job views: page view counter

| Setting | Option | Default | What it does |
|---|---|---|---|
| Count views | `ghjb_enable_view_tracking` | on | Counts views of each job page, shown in the **Views** column under **Greenhouse → Jobs**. |

A small script counts the view after the page is shown, so it works on cached pages. It posts
to the REST route `/wp-json/ghjb/v1/job-view`.

- Each browser session counts once per job.
- Search engine crawlers, prefetches and logged-in editors are not counted.
- No IP address or cookie is stored. A hashed marker, kept for an hour, stops repeat counts.
- One IP address, or one IPv6 /64 network, adds at most 60 views an hour (filter
  `ghjb_view_rate_limit`). Behind a proxy that hides visitors' addresses, fix the address with
  the `ghjb_client_ip` filter or raise the limit.

## Job list: page size and filters

These apply to the jobs page, the [job archives](/docs/job-archives/), and any
[shortcode or block](/docs/shortcodes-and-blocks/) that does not set its own.

| Setting | Option | Default | What it does |
|---|---|---|---|
| Jobs per page | `ghjb_jobs_per_page` | `20` | Jobs per page, from 1 to 100. |
| Filters to show | `ghjb_filters` | Keyword search, Department, Location, Employment type, Workplace | The filters above the list. Job function, Industry, Experience level and Education level are also available. Employment type and these four fill only when your jobs have matching custom fields in Greenhouse. |

A dropdown with only one choice hides itself. Each option shows its total number of jobs, not
narrowed by the other filters. To keep a term out of every dropdown,
[hide it](/docs/job-archives/#manage-job-terms-in-wp-admin).

## Job archives: one list per department, location and type

Each slug gives a taxonomy its own job lists, one per term, under the jobs page slug. Leave a
slug blank to use that taxonomy only in the filter.
[How job archives work](/docs/job-archives/).

| Setting | Option | Default |
|---|---|---|
| Departments | `ghjb_tax_slug_department` | `department` |
| Locations | `ghjb_tax_slug_location` | `location` |
| Employment types | `ghjb_tax_slug_employment_type` | `type` |
| Workplaces | `ghjb_tax_slug_workplace` | empty |
| Job functions | `ghjb_tax_slug_function` | empty |
| Industries | `ghjb_tax_slug_industry` | empty |
| Experience levels | `ghjb_tax_slug_experience` | empty |
| Education levels | `ghjb_tax_slug_education` | empty |

A slug is refused, and the old one kept, when it is `page`, `feed` or `embed`, the jobs page
slug, or already used by another taxonomy.

## Tools: test, import and clear cache

At the bottom of the Settings screen:

- **Test connection** fetches your Greenhouse job list and reports how many jobs came back.
- **Import jobs now** runs a full import straight away, and says so if one is already running.
  Below it, the panel shows the last import: when it ran and what changed, or **Last import
  failed** with the error.
- **Clear cache** deletes cached Greenhouse responses, including each job's application
  questions. Use it after you change a job's questions in Greenhouse. Jobs are not touched.

An HTTP 404 from Greenhouse means the board token is wrong. Check it against your job board
address.

## How the Greenhouse jobs sync works

- Each import fetches the jobs published on your Greenhouse job board and compares them with the
  jobs on your site. New jobs are added, changed ones updated, unchanged ones skipped.
- Each job is a post of type `ghjb_job`, listed under **Greenhouse → Jobs**. Jobs are managed in
  Greenhouse, so there is no **Add New** button.
- Each import also files jobs under their department, location, employment type and
  workplace, among eight [job taxonomies](/docs/job-archives/). Locations follow your Greenhouse
  offices, parents included; a job without offices gets its location text as a single
  location. Employment type comes from a custom field; workplace from a custom field or from
  the words "remote" or "hybrid" in the location or office.
- To build the location tree, each import reads your board's office list. On a board with many
  offices that list is large, so the plugin allows it up to 60 seconds and reads only the
  office details it needs. If the office list can't be read, the import changes nothing and
  the next run tries again. Job pages never wait for it: a page that loads the application
  form between imports reads only its own job.
- A job that closes, or is taken off the job board, moves to the trash. If it comes back, its
  page returns at the same address.
- If Greenhouse cannot be reached or answers with an error, the import changes nothing. Your
  jobs stay up and the next run tries again.
- Imports run on WP-Cron, so on a site with very little traffic a run can start a little late.
  Only one import runs at a time.
- One site imports one board. Developers can add more with the `ghjb_get_boards` filter.
- A board in Greenhouse's EU data centre is read from `boards.eu.greenhouse.io`, and its
  applications are sent there; other boards use `boards-api.greenhouse.io`. While the board's
  data centre is `unknown`, each import asks Greenhouse again first. Developers can switch
  a board between the two with the `ghjb_api_base` filter, which accepts only those two
  addresses.

## The Jobs screen

**Greenhouse → Jobs** lists every imported job with these columns: **Job ID** (Greenhouse's job
ID, linked to the job's Greenhouse posting), **Department**, **Location**, **Employment type**,
**Posted**, **Views** and **Applications**, the number accepted through your site. Sort by
**Posted** or **Views**, and filter by department, location, employment type or workplace. Each
row also has a **View on Greenhouse** link.

<figure class="ak-shot">
  <img src="/screenshots/admin-jobs.webp" alt="The Greenhouse Jobs screen in wp-admin with Job ID, department, location, employment type, posted date, views and applications columns" width="1200" height="750" loading="lazy" decoding="async" />
  <figcaption>Greenhouse → Jobs, with filters for department, location, employment type and workplace.</figcaption>
</figure>

Editing a job shows a read-only **Greenhouse data** box: the fields Greenhouse sent, the
application and view counts, and a **View on Greenhouse** link. Greenhouse is the source of
truth, so the next change there overwrites the job.

<figure class="ak-shot">
  <img src="/screenshots/admin-job-data.webp" alt="The read-only Greenhouse data box on a job: IDs, department, office, location, pay ranges, board, education and employment sections, applications and page views" width="754" height="1013" loading="lazy" decoding="async" />
  <figcaption>The Greenhouse data box on a job's edit screen.</figcaption>
</figure>