---
title: "On-site applications"
description: "How the on-site application form is built from each job's Workable questions, what happens on submit, and where failed attempts are logged."
source: https://workable.w4dev.com/docs/on-site-applications/
---

With an API token saved, candidates apply on your job pages instead of leaving for Workable.
Each application is sent straight to Workable through its API and shows up in Workable as a new
candidate on that job.

## Turning it on

1. Generate a Workable API token with the `r_jobs` and `w_candidates` scopes. The steps are in
   [Installation](/docs/installation/#4-optional-add-an-api-token-for-on-site-applications).
2. Save it under **Workable Jobs → Settings → API access token**.
3. Leave **Applications** on **Automatic**, or choose **On-site application form**.

Open any job page. The **Apply on Workable** button is replaced by the application form.

<figure class="ak-shot">
  <img src="/screenshots/job-detail-apply.webp" alt="Job page apply area showing the Apply on Workable button used when no API token is configured" width="1200" height="844" loading="lazy" decoding="async" />
  <figcaption>Without a token, job pages show the Apply on Workable button; once you save a token, the on-site application form appears in its place.</figcaption>
</figure>

When applications are taken on your site, the job pages' `JobPosting` markup also includes
`directApply: true`, which tells Google that candidates can apply directly on the page.

## What the form contains

The form is built from the application form you set up for each job in Workable, so different
jobs can ask different questions. The fields appear in this order:

1. **First name, Last name, Email, Phone.** Always shown. Name and email are required. Phone is
   required only when the job asks for it in Workable.
2. **Resume and Cover letter.** Always offered. When the job's Workable form includes them,
   Workable's settings decide whether they are required.
3. **The job's other profile fields**, such as headline, summary or address.
4. **The job's screening questions.**
5. **The consent checkbox**, when turned on under **Workable Jobs → Settings → Privacy**.

Workable field and question types map to form inputs like this:

| Workable type | Form input |
|---|---|
| Short text | Text box |
| Free text | Text area |
| Multiple choice, one answer | Radio buttons |
| Multiple choice, several answers | Checkboxes |
| Dropdown | Dropdown |
| Yes/No | A checkbox, or Yes and No radio buttons when the question is required |
| Number | Number box |
| Date | Date picker |
| File | File upload |

### Not supported in 1.0

- **Experience and education sections.** Workable's structured work-history and education
  fields are not shown on the form. If a job requires them in Workable, Workable may refuse the
  application. Make them optional on jobs you publish through this plugin, or use the **Send
  applicants to Workable** mode.
- **Profile photo.** The avatar field is not shown.

### File uploads

A file field accepts the file types and size Workable lists for it. When Workable does not say,
the defaults are PDF, DOC, DOCX, TXT, RTF and ODT files up to 5 MB. Your server's PHP upload
limit still applies on top of that, so check `upload_max_filesize` if large files fail.

Files are held on your server only for the moment it takes to send them to Workable, then
deleted.

### When you change a job's questions in Workable

Each job's form is cached for an hour. To see a change straight away, use **Clear cache** under
**Workable Jobs → Settings → Tools**.

## What happens when someone applies

The form submits in the background and shows the result without reloading the page. Without
JavaScript it submits as a normal form and works the same way.

Before anything is sent to Workable, the plugin checks:

- the form's security token,
- a hidden honeypot field that bots tend to fill in,
- the Turnstile or reCAPTCHA answer, when one is configured,
- a rate limit of 5 applications per 10 minutes from the same IP address,
- that the job is still open on your site,
- required fields, file types and file sizes.

Then the application is sent to Workable. The applicant sees one of these outcomes:

| Outcome | What the applicant sees |
|---|---|
| Workable accepts it | "Thank you — your application has been submitted." |
| Workable rejects a field | The fields Workable named are highlighted, with "Please correct the highlighted fields and try again." |
| Workable is over its rate limit | "Workable is busy right now. Please try again in a moment." |
| Anything else | A general error. The details are recorded in **Submissions**. |

If Workable rejects the token when an application is sent, an admin notice in wp-admin says the
form is showing but applications are failing, and names the fix, as described in
[Installation](/docs/installation/#if-the-token-stops-working). When the form itself cannot be
fetched, the job falls back to the **Apply on Workable** button and the notice says that instead.

## The Submissions log

**Workable Jobs → Submissions** lists the last 50 application attempts, newest first, when **Log
submissions** is on. Each entry has:

- the time, the job and its shortcode,
- success or error, with the message,
- the applicant's IP address, shortened,
- on success, the Workable candidate id and a **View candidate in Workable** link.

The log does not store the applicant's name, email, answers or files. Those go only to Workable.
A **Clear log** button empties it.

If the WP Logs plugin is active, each attempt is also written to its log.

## Developer hooks

| Hook | Type | Use it to |
|---|---|---|
| `wkjb_application_fields` | filter | Change the whole form: add, remove or reorder groups of fields. Receives the groups and Workable's raw form. |
| `wkjb_map_application_field` | filter | Change how one Workable profile field becomes a form input. |
| `wkjb_map_application_question` | filter | Change how one Workable question becomes a form input. |
| `wkjb_candidate_payload` | filter | Change the candidate data sent to Workable. Receives the payload, the field groups and the submitted values. |
| `wkjb_allowed_file_types` | filter | Change the default file extensions, used when Workable does not list its own. |
| `wkjb_max_upload_size` | filter | Change the default maximum upload size, in bytes. Default 5242880 (5 MB). |
| `wkjb_application_validation_errors` | filter | Add your own field checks. |
| `wkjb_application_success_message` | filter | Change the thank-you message. |
| `wkjb_application_rate_limit` | filter | Change the number of applications allowed per IP address. Default 5. |
| `wkjb_application_rate_window` | filter | Change the rate limit window, in seconds. Default 600. |
| `wkjb_application_form_ttl` | filter | Change how long a job's form is cached, in seconds. Default 3600. |
| `wkjb_application_form_failure_ttl` | filter | Change how long a rejected token is remembered before Workable is asked again, in seconds. Default 300. |
| `wkjb_client_ip` | filter | Change how the applicant's IP address is detected, for example behind a proxy. |
| `wkjb_recaptcha_score_threshold` | filter | Change the minimum reCAPTCHA v3 score. Default 0.5. |
| `wkjb_application_submitted` | action | Run code after Workable accepts an application. Receives the job shortcode, the job and Workable's candidate record. |
| `wkjb_application_logged` | action | Run code after any attempt is logged. Receives the log entry. |

Example: email the site admin whenever Workable accepts an application:

```php
add_action( 'wkjb_application_submitted', function ( $job_id, $job ) {
	wp_mail(
		get_option( 'admin_email' ),
		'New application: ' . $job['title'],
		'A candidate applied through the website. Open Workable to review them.'
	);
}, 10, 2 );
```