Categories
Applicant portal How To Integrations JavaScript Recruiting Management SAP SuccessFactors

How to access the candidate id/application id in an SAP SuccessFactors applicant portal

The applicant portal of SAP SuccessFactors Recruiting does not have the most modern UI, nor is there any real way of customizing the user experience. Which is why many companies end up developing various add-ons/plug-ins in order to add new features to the portal. Examples for such applications can be found in the SAP app center and range from quick apply solutions to video interview integrations.

If applicants should be able to jump from the applicant portal into the add-on, you will need to pass something to add-on that let’s it know which applicant it is. So you need to extract some sort identifier from the applicant portal before the user jumps over to your custom integration. I have seen plug-ins that use the applicant’s email address, since it can be easily extracted from the corresponding input field.

This, however, has two downsides: Firstly, it means that the user can only jump to your add-on from a page that contains the “Contact email”-field. Secondly, it results in you sending personally identifiable information to the add-on. Sending PII to a third party usually requires some sort of legal framework that clarifies how the data is processed and/or stored by the third party. So, in order to keep legal costs down and simplify your implementation, you might want to use the candidate or application id instead.

The Component._registry

During my work with the applicant portal, I discovered the JavaScript component/object that Recruiting Management, which the applicant portal is a part of, uses to store all of the data it needs.

The object can be accessed by logging into any SuccessFactors applicant portal, opening your browser’s developer tools and typing Component._registryin the console before hitting enter. Your browser will then show you the object in the console.

Screenshot of Chromiums developer tools console showing SAP SuccessFactors Component._registry
The Component._registry on the German Telekom’s applicant portal

Structure of the Component._registry object

As you can see in the screenshot above, the Component._registry object has a somewhat strange structure to it. It’s properties (all objects themselves) have keys similar to array indexes followed by a colon. So, unfortunately, finding the candidate id or an application id is not as simple as accessing Component._registry.candidate.id.

Also, the registry neither contains the same properties every time nor are the properties in any particular order. Thus, you cannot use Component._registry['56:'] just because that’s where you found the candidate information last time.

You will have to loop over the properties of the registry in order to find what you are looking for.

Finding the candidate id

Let’s first look at how to find and extract the candidate id. There are several objects in the registry that contain the candidate id somewhere in their properties. However, the easiest to work with and probably the most obvious are instances of RCMCandJobsInformation and RCMProfileInformation. They both contain a config property that contains the desired candidateId.

Screenshot of Chromium's developer tools console showing the structure of an RCMProfileInformation object
An RCMProfileInformation instance as an example

We will focus on the RCMCandJobsInformation object, because SuccessFactors adds a RCMProfileInformation instance without a candidate id to the registry when a user is on the “Apply”-page.

Let’s build a small function that extracts the candidate id with what we have learned. It could look something like this:

function getCandidateIdFromRegistry() {
    // Find the first instance of an object containing the candidate id
    var containingObject = Object.values(Component._registry).find(object => object instanceof RCMCandJobsInformation);
    
    // If a containing object was found, get the candidate id from the object and return it
    if (typeof containingObject !== 'undefined') return containingObject.config.candidateId;
}

Please note: The above function will not return anything for a user who is in the application process. However, we will get back to this.

Finding the application id

Now that we know how to get the candidate id, let’s look into how we can get an application id. Notice that I wrote “an” application id, not “the” application id. That’s going to be be imported because while you find the candidate id in several places, there is only one. The same cannot be said for the application id(s). As the user navigates through the applicant portal, they might submit a new application, look at a previously saved draft and/or look at an application they submitted earlier. At each of those steps, the Component._registry will contain a different application id.

The objects containing the application id are instances of RCMJobSpecificInfo.

Screenshot of Chromium's developer tools console showing the structure of an RCMJobSpecificInfo object
An RCMJobSpecificInfo instance example

So, we now know where to retrieve the application id from. However, SuccessFactors makes it just a little more difficult to retrieve the application id during the application process: When a user enters the “Apply”-page, the portal immediately adds an instance of RCMJobSpecificInfo to the registry. But because the user can just now start to fill out the application fields, no application has been created yet. Thus, that first instance of RCMJobSpecificInfo contains an applicationId of -1. An application id is only assigned if and once the user either saves the application as a draft or submits it. Either action creates a new RCMJobSpecificInfo object in the registry. So, in order to get the real application id if one has been assigned, we are going to search the registry in reverse order. That way, we either get a real application id we can work with or the initial -1 application id and we know that the user has neither saved nor submitted their application yet.

Here’s a function that put’s everything together:

function getApplicationIdFromRegistry() {
    // Find the last instance of an object containing an application id
    var containingObject = Object.values(Component._registry).reverse().find(object => object instanceof RCMJobSpecificInfo);
    
    // If a containing object was found, get the application id from the object and return it
    if (typeof containingObject !== 'undefined') return containingObject.config.applicationId;
}

A quick note on extracting the application id after the user saves a draft: SuccessFactors will display a “draft application saved”-message. The real application id seems to be added to the registry only after/as that message disappears. So be careful what event you use to trigger the extraction.

Screenshot of SuccessFactors message after an application draft has been saved successfully

Finishing touches

Remember that I mentioned we would get back to extracting the candidate id during the application process? You might have already spotted where we find it while on the “Apply”-page: In the RCMJobSpecificInfo object(s).

Now we need to change one last thing. As you can see in the screenshots, all of the objects we looked at so far contain both a config and a _config with the same data. This works fine on both the “Profile” and the “Apply”-page. On the “Settings”-page, however, you will only find object containing the candidateId in their _config property. And, because it’s SuccessFactors, the candidate id is stored as a string in those objects (all other objects store it as an integer).

Screenshot of Chromium's developer tools console showing the structure of both a RCMDeleteCandidateProfile and RCMCareerManagementPage object
RCMDeleteCandidateProfile and RCMCareerManagementPage contain the candidate id in their _config

So, in order to get our function to work on the settings page, we need to switch to using the _config rather than the config property and we need to add our new object types to our .find-condition. Also, let’s convert the candidate id to an integer so our function always returns the same type.

Here is a version of getCandidateIdFromRegistry that takes all that into consideration:

function getCandidateIdFromRegistry() {
    // Find the first instance of an object containing the candidate id
    // Skipping an instances of relevant object that do not contain a candidate id
    var containingObject = Object.values(Component._registry).find(object => object instanceof RCMCandJobsInformation || object instanceof RCMJobSpecificInfo || object instanceof RCMCareerAccountManagementPage);
    
    // If a containing object was found, get the candidate id from the object and return it
    if (typeof containingObject !== 'undefined') return parseInt(containingObject._config.candidateId);
}

Where/when do these functions work?

The getCandidateIdFromRegistry-function works:

  • on the “Profile”-page
  • on the “Settings-page
  • on the “Apply”-page
  • after opening an application draft (since this lead to the “Apply”-page)
  • after opening a submitted application (the page seems to be a slightly different version/rendering of the “Apply”-page)

The getApplicationIdFromRegistry-function works:

  • on the “Apply” page, once/if the user saved or submitted the application
  • after opening an application draft (see above)
  • after opening a submitted application (again, see above)

Please note that both functions only work in the Recruiting Management applicant portal. Neither will allow you to get an id while the user is still on the Recruiting Marketing (RMK)/Career Site Builder (CSB) portal. That portal is basically “read-only” and does not receive any candidate/application data as far as I am aware.

Sources