Apply with Indeed
Create and deploy an Apply with Indeed button for Partner ATSs and employers.
- By using this API and its documentation and building an integration, you agree to the Additional API Terms and Guidelines.
Introduction
Apply with Indeed (AWI) lets you add and deploy an Apply with Indeed button on jobs that you post through the Job Sync API or XML integration. After you integrate AWI, job seekers can click the Apply with Indeed button on an employer career page and apply with the saved Indeed profile data in their Indeed account.
Prerequisites
Before you start
-
To use AWI, post the job through the Job Sync API or XML feeds and enable Indeed Apply for the job. See the Job Sync API guide or XML feed guide to learn how to post jobs and enable Indeed Apply.
-
Open an Integration Request for AWI.
- To request a new partnership, use this Request Form.
- Indeed generates a
partnerApiTokenfor AWI.
AWI provisioning
You can access credentials through Partner Console.
-
Indeed provisions AWI access credentials.
- OAuth token and secret: Use these credentials to generate access tokens that authenticate requests to our GraphQL API.
- Partner API token and secret: Use these credentials for AWI. These credentials are separate from your Indeed Apply API token that you use to post jobs on Indeed. In Partner Console, this token appears as Apply With Indeed Token.
AWI integration options recommendation
Use one of these methods to enable the Apply with Indeed button on ATS pages:
-
Add our SDK or JavaScript to your webpage code for fast and easy development.
Use this method if you can easily change your front-end code and want the SDK to handle button design and errors.
-
This method gives you more flexibility because it returns an apply form URL that you can integrate anywhere on your webpage.
Use this method if you can call Indeed GraphQL APIs from your back-end system and do not mind building the button UI and handling errors.
Indeed partners must identify whether they post jobs to Indeed and enable Indeed Apply through the Job Sync API or XML feed. The input parameters for adding an Apply with Indeed button depend on that choice.
AWI JavaScript
AWI JavaScript enables the Apply with Indeed button on ATS job pages.
Load the JavaScript
To load AWI JavaScript on an ATS job page, add a <script> tag to the page, as this code sample shows.
You can also include a <meta charset> tag if needed for page encoding.
<!DOCTYPE html><html> <head> ... <!-- Load the AWI JavaScript --> <script src="https://apply.indeed.com/indeedapply/static/scripts/app/awi-bootstrap.js"></script> ... </head>...</html>Enable the Apply with Indeed button
After you load the script, add an HTML element with the required attributes to enable the Apply with Indeed button. This code sample shows how.
The parameters vary based on whether you use the Job Sync API or XML feed.
Job Sync API code sample
<!DOCTYPE html><html> <head> ... <!-- Step 1: Load the script --> <script src="https://apply.indeed.com/indeedapply/static/scripts/app/awi-bootstrap.js"></script> ... </head> <body> ... <!-- Step 2: Specify where to display the **Apply with Indeed** button --> <div data-indeed-apply-widget-type="<WIDGET-TYPE>" data-indeed-apply-sourceJobPostingId="<JobId>" data-indeed-apply-partnerApiToken="<PartnerApiToken>" data-indeed-apply-encryptedJobUrl="<Encrypted Job URL>" data-indeed-apply-encryptedContinueUrl="<ContinueURL>" data-indeed-apply-hl="en" data-indeed-apply-co="US" data-indeed-apply-newTab="true" ></div> ... </body></html>XML Feed code sample
<body> ... <!-- Step 2: Specify where to display the **Apply with Indeed** button --> <div data-indeed-apply-widget-type="<WIDGET-TYPE>" data-indeed-apply-encryptedSourceName="<SourceName>" data-indeed-apply-encryptedFeedUrl="<FeedUrl>" data-indeed-apply-encryptedReferenceId="<ReferenceId or ReferenceNumber>" data-indeed-apply-partnerApiToken="<PartnerApiToken>" data-indeed-apply-encryptedJobUrl="<Encrypted Job URL>" data-indeed-apply-encryptedContinueUrl="<ContinueURL>" data-indeed-apply-hl="en" data-indeed-apply-co="US" data-indeed-apply-newTab="true" ></div> ... </body>Specify parameters
Replace the parameters in angle brackets (<>) in the previous code sample with your values.
The required parameters differ for the Job Sync API and XML feed.
This table describes the data-indeed-apply-* attributes:
| Attribute | Required | Encrypted | Description | Example |
|---|---|---|---|---|
Type: String | Required | No | Type of Apply with Indeed button. The supported value is AWI. | AWI |
Type: String | Required for Job Sync API | No | The Indeed employer job ID that the Job Sync API generates when you create a job posting. data-indeed-apply-sourceJobPostingId is also called sourcePostingId in the Job Sync API guide - Response – Create job posting. | 57caad99-6441-46ec-913c-e018e5013689 |
Type: String | Required for XML feed | Yes | The encrypted source name from the XML feed. This is the parent organization that is hiring for the role. | 1d76ab187297cf4c284e2621c2c7462fbfb216704ed0fdc325de0baf6dca5718 |
Type: String | Required for XML feed | Yes | The encrypted feed URL from the XML feed. This is the URL for the job listing on your site. | 0906256350d8ed657d9f70ffe91e84d4a117328ab5d42c22ccbac1689af2d1cb |
Type: String | Required for XML feed | Yes | The encrypted reference ID of the XML feed job. This ID uniquely identifies the job instance. | 1d76ab187297cf4c284e2621c2c7462fbfb216704ed0fdc325de0baf6dca5718 |
Type: String | Required | No | Your partner API token. | 98922e8fa1355c944b0f7efc6ae9b182ebb1f3ed8ce0b36ea40b33a9b73e2211 |
Type: String | Required | Yes | The encrypted public job description page URL where you load the Apply with Indeed button. | 0906256350d8ed657d9f70ffe91e84d4a117328ab5d42c22ccbac1689af2d1cb |
Type: String | Optional | Yes | The encrypted URL where applicants are redirected after they click Continue on the post-apply screen and successfully submit the application. | 0906256350d8ed657d9f70ffe91e84d4a117328ab5d42c22ccbac1689af2d1cb |
Type: String | Optional | Yes | The encrypted URL where applicants are redirected if they leave the Indeed Apply form before submitting the application by clicking the Exit link. | 0906256350d8ed657d9f70ffe91e84d4a117328ab5d42c22ccbac1689af2d1cb |
Type: String | Optional | No | Sets the language of the apply form. See supported languages. | en |
Type: String | Optional | No | Sets the applicant country code. See supported countries. | US |
Type: String | Optional | No | The name of the JavaScript method that runs when an applicant selects Apply with Indeed. | _onClick |
Type: String | Optional | No | The name of the JavaScript method that runs after the Apply with Indeed button loads successfully. | _onButtonReady |
Type: Boolean | Optional | No | Prevents the button CSS from loading. You must style the button yourself. | true |
Type: Boolean | Optional | No | Controls whether the application form opens in a new tab. | false |
Encrypt the required parameters with the secret that is associated with your partnerApiToken.
Callback methods
onClick:- The callback method takes one argument: the button
HTMLElement.
- The callback method takes one argument: the button
onReady:- The callback method accepts two arguments:
HTMLElementbutton andbuttonLoadStatus. buttonLoadStatusis an object with these fields:success, which indicates whether the button load succeeds or fails;message, which contains the success or error message; anderror_code, which contains the error code when the button load fails.
- The callback method accepts two arguments:
Handle attribute encryption
- Encrypt every attribute marked
Yesin the Encrypted column in the previous table. Use AES with your 128-bit secret key, which is the secret associated with the generatedpartnerApiToken. Use CBC mode with PKCS5 padding. Use an initialization vector of 16 bytes of00. - To encrypt an attribute:
- Use the first 16 bytes of your secret to create a 128-bit key. Your secret is the one associated with the generated
partnerApiToken. - Read the plain-text attribute bytes in UTF-8.
- Encrypt the attribute with AES, CBC mode, and PKCS5 padding.
- Convert the encrypted bytes to a hex string.
- Use that hex string as the
data-indeed-apply-{attribute-name}attribute value. - Send the encrypted value instead of the plain-text value. Indeed Apply recognizes the value as encrypted.
- Use the first 16 bytes of your secret to create a 128-bit key. Your secret is the one associated with the generated
- To encrypt and decrypt data, see this sample:
import java.nio.charset.Charset;import java.lang.RuntimeException;import javax.crypto.Cipher;import javax.crypto.spec.*;import javax.crypto.spec.SecretKeySpec;
public class EncryptionTest {
public static void main(String[] args) {
String url = "YOUR_URL"; String apiSecret = "YOUR_API_SECRET"; String encrypted_url = encrypt(url, apiSecret); String decrypted_url = decrypt(encrypted_url, apiSecret);
System.out.println(encrypted_url); System.out.println(decrypted_url); }
static String encrypt(String message, String apiSecret) { try { byte[] keyBytes = apiSecret.getBytes(Charset.forName("UTF-8")); byte[] message_bytes = message.getBytes("UTF-8"); SecretKeySpec key = new SecretKeySpec(keyBytes, 0, 16, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivspec = new IvParameterSpec(new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }); cipher.init(Cipher.ENCRYPT_MODE, key, ivspec); byte[] email_encrypted = cipher.doFinal(message_bytes); return bytesToHexString(email_encrypted); } catch (Exception e) { System.out.println(e.getMessage()); throw new RuntimeException(e); } }
static String decrypt(String message, String apiSecret) { try { byte[] keyBytes = apiSecret.getBytes(Charset.forName("UTF-8")); byte[] message_bytes = message.getBytes(Charset.forName("UTF-8")); message_bytes = decodeHex(message_bytes); SecretKeySpec key = new SecretKeySpec(keyBytes, 0, 16, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); IvParameterSpec ivspec = new IvParameterSpec(new byte[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }); cipher.init(Cipher.DECRYPT_MODE, key, ivspec); byte[] email_decrypted = cipher.doFinal(message_bytes); return new String(email_decrypted, "UTF-8"); } catch (Exception e) { System.out.println(e.getMessage()); throw new RuntimeException(e); } }
static String bytesToHexString(byte[] in) { final StringBuilder builder = new StringBuilder(); for (byte b: in) { builder.append(String.format("%02x", b)); } return builder.toString(); }
static byte[] decodeHex(byte[] data) throws Exception { String text = new String(data, "UTF-8"); char[] chars = text.toCharArray();
int len = chars.length; byte[] out = new byte[len >> 1]; int i = 0;
for (int j = 0; j < len; ++i) { int f = toDigit(chars[j], j) << 4; ++j; f |= toDigit(chars[j], j); ++j; out[i] = (byte)(f & 255); } return out; }
static int toDigit(char ch, int index) throws Exception { int digit = Character.digit(ch, 16); if (digit == -1) { throw new Exception("Illegal hexadecimal character " + ch + " at index " + index); } else { return digit; } }}Job Sync API sample data
<divdata-indeed-apply-widget-type="<WIDGET-TYPE>"data-indeed-apply-sourceJobPostingId="<JobId>"data-indeed-apply-partnerApiToken="<PartnerApiToken>"data-indeed-apply-encryptedJobUrl="b18d0be4c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedContinueUrl="417856e7c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedExitUrl="2b7cb78563dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"></div>XML feed sample data
<divdata-indeed-apply-widget-type="<WIDGET-TYPE>"data-indeed-apply-encryptedSourceName="1d76ab187297cf4c284e2621c2c7462fbfb216704ed0fdc325de0baf6dca5718"data-indeed-apply-encryptedFeedUrl="b18d0be4c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedReferenceId="<ReferenceId>"data-indeed-apply-partnerApiToken="<PartnerApiToken>"data-indeed-apply-encryptedJobUrl="b18d0be4c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedContinueUrl="417856e7c173dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"data-indeed-apply-encryptedExitUrl="2b7cb78563dfa2b7cb7856e7c7b6f02a563867a9df67ca208c8b9654966299"></div>Do not include multiple URLs in any URL attribute field for your job button configuration: encryptedJobUrl, encryptedContinueUrl, encryptedExitUrl, or encryptedFeedUrl. If you include multiple URLs, the button shows an error and appears gray and inactive.
Button design
This image shows a successful Apply with Indeed button.
This image shows an unsuccessful Apply with Indeed button.
If an issue occurs, see the AWI Javascript-specific errors and troubleshooting guide.
The generated Apply With Indeed button should match the size and presentation of the other Apply buttons.
applyUrlForEmployers mutation
Use this mutation to create an Indeed Apply URL each time you load an Apply with Indeed button.
Integrate with Indeed APIs
When you become an Indeed partner, Indeed sets up an app for your integration. Sign in to Partner Console to view your app and OAuth credentials (client ID, secret, and authorization code for 3-legged OAuth). Exchange credentials for an access token to authenticate API calls.
Create Apply with Indeed URL
To create an Apply with Indeed URL, also called an Indeed Apply URL, call the ApplyUrlMutations.applyUrlForEmployers mutation. Send the inputs that identify the job for which you want to load the Apply with Indeed button. The required inputs differ for XML feed and Job Sync API.
Job Sync API inputs
sourcedPostingId*: the Indeed employer job ID that the Job Sync API generates when you create a job postingjobUrl*: the public job description page URL where you loaded the Apply with Indeed buttoncontinueUrl: the URL where applicants are redirected when they click Continue on the success screenexitUrl: the URL where applicants are redirected when they exit the Indeed Apply form
* - required inputs
XML feed inputs
sourceName*: the parent organization name hiring for the role, such as Test Company Name or Indeed JapanfeedUrl*: the feed URL of your XML jobsreferenceId*: the<referenceNumber>or<referenceId>from the XML feedjobUrl*: the public job description page URL where you loaded the Apply with Indeed buttoncontinueUrl: the URL where applicants are redirected when they click Continue on the success screenexitUrl: the URL where applicants are redirected when they exit the Indeed Apply form
* - required inputs
Generate a new Apply with Indeed URL every time you render an Apply with Indeed button. Each URL works only once and cannot be reused.
Request
Job Sync API request code sample
mutation { applyUrl { createApplyUrlForEmployers( input: { jobId: { sourceJobPostingId: "jobId" } jobUrl: "http://example.com/careers/job1.html" continueUrl: "http://example.com/careers/indeedapply-continue.html" exitUrl: "http://example.com/careers" } ) { applyUrl } }}XML feed request code sample
mutation { applyUrl { createApplyUrlForEmployers( input: { xmlFeedParams: { sourceName: "sourceName", feedUrl: "feedUrl", referenceId: "referenceNumber" } jobUrl: "http://example.com/careers/job1.html" continueUrl: "http://example.com/careers/indeedapply-continue.html" exitUrl: "http://example.com/careers" } ) { applyUrl } }}The mutation returns an applyUrl, which you can use on the Apply with Indeed button on the ATS job page.
Response
Response code sample:
{ applyUrl: "https://smartapply.indeed.com/beta/indeedapply/applybyapplyablejobid?indeedApplyableJobId=b957be31-16ed-4f65-9376-cf383594eee5-Y21ocWEx"}Headers
| Header | Meaning | Required or optional | Details | Example |
|---|---|---|---|---|
authorization | Access token | Required | Authorizes access to the mutation. Get an access token | Bearer eyJrEIOeWQiOiI5NzVkOWZkMC01NzE3LTQzMzQtOTM |
indeed-co | Country | Optional | Sets the country for the request. See supported countries. | US |
indeed-locale | Locale | Optional | Sets the client's locale for the original request. | en-US (format) |
indeed-user-agent | Applicant’s user agent string | Optional | Sets the user agent for the original browser request. | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 |
indeed-user-ip | Applicant’s IP | Optional | Sets the client's IP address for the original browser request. | 192.168.0.0 |
Integrate button design with mutation
Clients that use the mutation can use the following script to load the button CSS that Indeed provides.
<!DOCTYPE html><html><head> ... <!-- Step 1: Load the script --> <script src="https://apply.indeed.com/indeedapply/static/scripts/app/buttonStyles.js" ></script></head><body> ... <!-- Step 2: Specify data-style as indeed-apply-button for the button where you want to enable button style --> <button data-style="indeed-apply-button">Apply Now</button></body></html>This image shows the Apply with Indeed button after you apply the CSS with the previous script.
To disable the button after a failure, add the aria-disabled=true attribute to the button element.
<!-- Set aria-disabled attribute to true to disabled the button --><button data-style="indeed-apply-button" aria-disabled=true>Apply Now</button>This image shows the Apply with Indeed button after you apply the attribute with the previous script.
Button translations
To change the language of the Apply with Indeed button, set the language in the script with the hl query parameter, such as hl=ja or hl=es. For valid hl values, see supported languages.
<!DOCTYPE html><html><head> ... <!-- Step 1: Specify query parameter --> <script src="https://apply.indeed.com/indeedapply/static/scripts/app/buttonStyles.js" ></script></head><body> ... <!-- Step 2: Specify data-style as indeed-apply-button for the button where you want to enable button style --> <button data-style="indeed-apply-button">Apply Now</button></body></html>This image shows the Japanese Apply with Indeed button after applying the attribute by using the previous script.
Troubleshoot errors
When a request fails, the data field is null, and the errors field contains details about the failure. Common errors include GRAPHQL_PARSE_FAILED, BAD_USER_INPUT with sub-codes such as JOB_NOT_FOUND and PARTNER_DATA_NOT_FOUND, and INTERNAL_SERVER_ERROR.
If a request fails and you do not receive a URL, retry the request without showing the Apply with Indeed button. Enable the button again after you receive a URL.
For detailed error descriptions, sub-codes, and resolution steps, see Troubleshoot Indeed Apply errors.