Integrate Sitecore Search with Workday jobs
Integrating two specific platforms can sometimes feel like hula hooping at the Olympics. But it can also give you insights into solutions that can be applied to other integrations as well. Authentication hurdles and multilingual requirements are a common scenario and for both I have some insights and learnings to share.
Why combine Sitecore Search and Workday?
Workday is a popular platform used by companies to manage their workforce. Companies can manage open positions in Workday and integrate them via API into the website. Instead of directly adding the API to the frontend application to display jobs, we chose to index them with Sitecore Search. The benefits being that jobs can be part of any search-based component, are filterable and can leverage personalization and boost features of Sitecore Search.
API authentication
Workday offers powerful REST APIs, but they are protected with OAuth. Unfortunately, Sitecore Search does not offer this type of authentication for its crawlers.
Another API option that Workday offers is called Report-as-a-Service (RaaS). The data available for this API can be configured by Workday and it supports basic authentication.
Adding support for this is as easy as adding an authorization header to the trigger for your crawler:
function extract() {
return [{
"url": "[YOUR_RAAS_API]",
"headers": {
"Authorization": [
"Basic NVSVX0lOAVD5MDhfVU5JQ19JbnRlcm5hbF9VU19JbmJvdW5kX0ZSQTpwOTNxZmI3NlBASEpEQG1yd25rQHQ="
]
}
}];
}
Support multiple languages
It is likely that your website supports multiple languages and so do the job openings. Therefore you might also need to index them by language. The Workday RaaS APIs handle languages not through the URL of the API, but with different logins. This means, the URL will stay the same, but you will have a different authorization token per language.
Add a trigger for every language
The authorization header can be set on a trigger level. To have different headers, you will need to add multiple triggers. In our example, we support both en-us
and de-ch
#EN
or #DE
to the API endpoint.To correctly index an entry for multiple languages, you need to define a locale extractor. Consider reading Dealing with multiple languages in Sitecore Search with XM Cloud if you want to learn more about locale extractors.
A simple trick to pass a language from the trigger to the locale extractor is an additional header. Here is an example how the final source of a trigger for the German language could look like.
function extract() {
return [{
"url": "[YOUR_RAAS_API]#DE",
"headers": {
"Authorization": [
"Basic NVSVX0lOAVD5MDhfVU5JQ19JbnRlcm5hbF9VU19JbmJvdW5kX0ZSQTpwOTNxZmI3NlBASEpEQG1yd25rQHQ="
],
"culture": ["de_ch"]
}
}];
}
Define a locale extractor
The locale extractor for this case is very simple. Use the Header extractor type and configure the header name from the previous paragraph.
Crawl the API
To get data out of the API and into Sitecore Search is the purpose of a document extractor. Be sure to check the Localized option and write your JavaScript code. Here is a simplified example of how this could look like.
function extract(request, response) {
var $ = response.body;
var jobs = $('wd\\:Report_Data').find('wd\\:Report_Entry');
var out = [];
for (var i = 0; i < jobs.length; i++) {
var job = jobs[i];
var id =
$(job).find('wd\\:workdayID').text() ||
$(job).find('wd\\:jobRequisitionId').text() ||
$(job).find('wd\\:Job_Requisition').children('wd\\:ID').first().text();
out.push({
id: id,
type: 'Job',
type_id: 'job',
page_type: 'Job Workday',
page_type_id: 'job-workday',
name: $(job).find('wd\\:title').text(),
job_name: $(job).find('wd\\:title').text(),
job_field: $(job).find('wd\\:jobFamilyGroup').attr('wd:Descriptor'),
job_exp_level: $(job).find('wd\\:CFINT0908ExperienceLevel').text(),
job_description: $(job).find('wd\\:workerSubType ').attr('wd:Descriptor'),
job_offer: $(job).find('wd\\:timeType').attr('wd:Descriptor'),
job_number: $(job).find('wd\\:jobRequisitionId').text(),
job_posting_status: $(job).find('wd\\:Status').text(),
url: $(job).find('wd\\:url').text()?.toLowerCase(),
tile_type: 'job',
});
}
return out;
}
Group jobs in a widget
A way to make the indexed jobs available to the Sitecore Search API is to combine them in a widget. If you haven't build a Sitecore Search powered component before, you might want to read Building Sitecore Search powered Components.
In the crawler code, we assign every job document a type_id
with the value job
. We can use this to define a widget rule that blacklists everything that is not a job. Additionally, we can also filter out expired or deleted postings.
Build your component
The final step is to build the actual component that exposes the jobs to the website. In our case, we built a component where you can search for jobs and filter them by various facets. Here is what we ended up with.
Summary
Integrating Sitecore Search with Workday has been an interesting journey. It's fascinating to see how combining these platforms can create such a seamless job search experience. The challenges we overcame taught me valuable lessons about API integrations and multilingual support. I'm excited to apply these insights to future projects and hope they prove useful to you too.