Taking control of the IBM Connections user experience

Introducing IBM Connections Customizer

Editor's note: The original content of this article appeared in App Dev Resources for IBM Connections Customizer on GitHub, and has since been updated with additional feature information.

If you’ve ever wanted to change the way IBM Connections looks or behaves, the new IBM Connections Customizer gives you the control you’ve been looking for. In this article, you’ll learn how Customizer lets you change the Connections user interface, and how you can get started using Customizer right away.

Customizer is a middleware service that lets you modify the IBM Connections user experience. In essence, it’s a proxy between IBM Connections and the end-user. It can intercept and modify requests and responses, so it can customize anything that flows through it, such as the behavior of APIs and the look-and-feel of the user interface.

The IBM Connections Customizer model is simple. The service performs customizations by injecting JavaScript, CSS, or other web resources into the HTML pages returned by IBM Connections in response to end-user requests generated in standard components like Communities, Profiles, Files, Homepage, and so on, as the user navigates the apps. The customization details (typically, what code should be inserted and on what requests) are defined by applications stored in the IBM Connections Application Registry (“App Reg”).

App Reg is a centralized design repository used to store and retrieve applications that customize and extend a variety of different IBM Connections services, including Customizer. In the cloud, App Reg is available to organization administrators via the Admin > Manage Organization > Organization Extensions menu path. There you can create and manage Customizer applications, which are simply JSON files containing design information defining the components that need to be targeted and the actions that need to be performed. Listing 1 shows a simple Customizer application.

Listing 1. Hello World Connections Customizer application
  "services": [ 
  "name": "Simple Customizer Sample", 
  "title": "My First Customizer App", 
  "description": "Perform a modification to the Connections Homepage", 
  "extensions": [ 
      "name": "Hello World Extension", 
      "type": "", 
      "path": "homepage", 
      "payload": { 
        "include-files": [ 
         "include-repo": {
           "name": "global-samples"

This application simply prepends "Hello World" to the title string in the Connections home page.

The JSON should be easy to understand.

  • The app is named “Simple Customizer Sample” and it extends the Customizer service.
  • It contains one extension, named “Hello World Extension”. (Note that apps can have many extensions.)
  • The extension type (“”) shows that it is a customization of the UI.
  • The extension path (“homepage”) shows that the customization applies to the Connections homepage.
  • A file named helloWorld.user.js is to be injected into the homepage.

Tables 1 and 2 summarize the properties you can use in the JSON.

Table 1. Generic Customizer application properties
NameString used to identify the extension
TitleShort string description (translatable for international audiences)
DescriptionLong string description (translatable for international audiences)
ServicesThe service(s) with which the application is associated
TypeString used to identify the extension point being implemented – required. Valid values:
PathString used to identify the component to customize:
*Unlike the other path values, global does not represent a real URL path element. It is a keyword meaning “match all URLs.”
Table 2. Payload Customizer application properties
match: urlA regular expression used to provide more fine-grained target resource matching than the broad match specified in the path property
match: user-nameString used to identify one or more users as the target for the customization. Note that user names may not be unique in a given organization.
match: user-idString used to identify one or more users as the target for the customization. This property is unique in a given organization.
match: user-emailString used to identify one or more users based on email address value
include-filesList of files to be inserted into the response for a matched page request
include-repo: nameString used to identify the repository where the include-files are stored

A closer look at Customizer properties

As shown in Table 1 and Table 2, Customizer properties fall into two categories:

  • Generic App Reg Properties
    Properties defined for all App Reg applications across all services
  • Customizer service properties
    Properties specific to the Customizer service (everything in Table 2)

App Reg requires that applications specify the generic name, title, description, service, and type property values. The Application Registry specification does not require the path property to be specified when an application is created, but the Customizer service puts it to good use for every request it processes, as we’ll soon see. Therefore, in reality a path value is required for Customizer applications to work properly.

Of the generic properties in Table 1, only type and path need further discussion.

A type value is always the name of an extension point defined by a service. At present, Customizer defines only two extension points:

    A declaration that the Customizer extension modifies the IBM Connections UI. The extension will be handled in accordance with a prescribed UI extension pattern. For example, any include files specified in the payload are injected into the response document.
    This extension point is reserved for future use. As a middleware proxy, Customizer can modify API behaviors, but that feature is not available in the current Customizer release.

The path property value represents a path element in the IBM Connections request URL, which in most use cases corresponds to a standard IBM Connections component. Consider the URLs displayed in Listing 2.

Listing 2. Examples of IBM Connections URLs
/* homepage */ 
/* communities */ 
/* files */ 
/* blogs */ 
/* wikis */ 

These sample URLs follow a clear pattern, in which the next element after the IBM Connections cloud domain name identifies the Connections component or application handling the request. The possible values of this element are the path values in Table 1 (homepage, communities, files, and so on).

As http requests flow through Customizer, it can query the Application Registry for any extensions relating to a given request URL and reduce the scope of the result set by specifying the particular in-context path value. A typical REST request from Customizer to App Reg for Files customizations might look like this:


This translates as, “Get all UI extensions registered for the Customizer service that apply to Files.” This explains why Customizer extensions must contain both a type and a path value. One detail to note about the path value is the special global keyword. This supports the use case where an extension needs to apply to all requests. For example, suppose you need to display corporate footer text at the bottom of every page in IBM Connections. Clearly, it would be inefficient to create an extension for every possible path value. The global path value solves the problem.

Processing payload properties

In response to the request shown above, App Reg returns the extensions that match the criteria as a single collection of one or more JSON files just like the one in Listing 1. The Customizer service implementation then parses and applies the design metadata in the returned extensions, and that is where the payload data comes into play.

App Reg itself does not use payload properties. It simply passes them to the nominated service (Customizer, in this context) for processing.

Fine grained URL matching

The generic path property provides a coarse means of querying the Application Registry for extensions pertaining to a given IBM Connections component. The optional match properties inside the Customizer payload let you fine-tune extension filtering, to determine whether an extension is applied to a given URL request.

The match url property takes a regular expression and evaluates it against the current URL. If it matches, the extension is applied; otherwise, the extension is not applied. This is a powerful feature, as the following code snippets demonstrate.

Listing 3 shows a Communities extension that has a fine-grained URL match applied on lines 14 – 16. In this case, the extension is applied only if the Communities followedcommunities URL is being processed. The extension is ignored for other Communities URLs like those shown in Listing 3; for example, ownedcommunities, communityinvites, and so on.

Listing 3. Customizer application with URL matching
 "services": [ 
 "name": "Communities Customization", 
 "title": "UI Customization for Communities I Follow", 
 "description": "Sample to modify Connections Communities", 
 "extensions": [ 
     "name": "Followed Communities Customizer", 
     "type": "", 
     "path": "communities", 
     "payload": { 
       "match": { 
         "url": "followedcommunities" 
       "include-files": [ 
         "flipCard/commListCardsFlipStyle.user.js " 
       "include-repo": {
           "name": "global-samples"
2    }

Similarly, the following fragment shows how a single global extension can be applied to Homepage and Communities but nothing else:

Listing 4. Global Customizer application with URL matching
   "path": "global", 
   "payload": { 
     "match": { 
       "url": "homepage|communities" 

Note: The design of some IBM Connections components, like Homepage, is based on the Single Page App paradigm. For example, look at the Homepage URLs in Listing 2. All contain hashtags, which means that new http requests are not fired as the user navigates around the page. Therefore, Customizer is not notified when, for example, a user moves from imfollowing to atmentions. In contrast, Customizer is notified when a user in Communities moves from ownedcommunities to followedcommunities. You can target individual Communities URLs with the match url property, but you cannot use the same technique to match the Homepage hashtag URLs. Instead, your homepage extension would need to inject a script that listens for hash change events and responds accordingly. For an example, look at the handleHashChangeEvent() function in the homepage sample newsRiverSectionedHashChange.user.js. (All the latest samples are in the samples folder of ibmcnxdev/customizer on GitHub.)

It’s easy to imagine many other uses for fine-grained match criteria. For instance, if you want to apply a customization to any Files URL that contains a GUID, you can set the path value to “files” and the match url value to “id=[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}”. For an example of such a URL, take another look at Listing 2.

Note: The braces in the regular expression must be escaped (that is, preceded by a backslash character) when included in JSON stored in App Reg.

Fine-grained matching based on the active user

The match property also accepts various user-related conditions based on the current user’s name or id. In both cases, you can specify single- or multi-value parameters—or, in JSON parlance, a single string value or an array of string values. Listing 5 shows how a Communities extension can target specific users based on their user names.

Listing 5. Customizer application targeting specific users by name
 "path": "communities", 
 "payload": { 
   "match": { 
         "Jane Doe", 
         "Joe Schmoe" 

Since user names are not always unique in an organization, you might inadvertently target unintended users with this technique, so that any user with the same name see the extension. To avoid this, you can use the user-id match property instead, as shown in Listing 6. Note that the term "subscriber id" is sometimes used in place of "user id" in the IBM Connections user interface and documentation.

Listing 6. Customizer application targeting specific users by ID
 "path": "communities", 
 "payload": { 
   "match": { 

The story so far

So far, we’ve learned that:

  • Customizer is a proxy through which all Connections requests and responses flow.
  • Based on the URL requests it processes, Customizer queries App Reg to ascertain if customizations have been registered for Connections components.
  • When App Reg returns application definitions to Customizer, Customizer uses the metadata in the JSON payload to decide if a customization should be applied.

Figure 1 shows this request processing mechanism.

Figure 1. IBM Customizer request life cycle
IBM Customizer request life cycle
IBM Customizer request life cycle

Now, how does Customizer manage the file resources listed in the include-files property?

Managing application file resources

The include-files payload property lists one or more files to be inserted into the Connections http response, thus becoming part of the DOM structure loaded in the user’s browser. Listing 1 shows a simple single-item value for this parameter: "helloWorld/helloWorld.user.js", where helloWorld is a folder and helloWorld.user.js is a JavaScript file in it.

On IBM Connections Cloud, files declared in the include-files property are stored in one of two locations:

  • a private IBM GitHub organization (, accessible only to IBM)
  • a public IBM Connections GitHub organization (

The include-repo payload property value identifies the name of the actual repository. For example, Listing 1 and Listing 3 show an include-repo object with a name value of "global-samples". This is a reference to a repository on that contains ready-made samples that any IBM Cloud tenant can use in a Customizer app. "Hello World", "FlipCard," and the other samples described later in the Standard Samples section are all located in this repository. IBM Customizer resolves the GitHub organization referred to in the JSON markup; that is, whether it is in the private or public location. IBM has control over the repositories in both locations, so duplicate names are not allowed.

Customizer assets like global-samples are directly provisioned to by the IBM Customizer team. Since this is a private GitHub organization, you can't explore it to discover available repositories, but you will of them through public samples, documentation, and other enablement materials (such as this article). It is envisaged that an enhanced App Reg IDE may expose these repositories through the UI in a future release.

You can freely explore the assets available on the public IBM Connections Developers GitHub organization. You can leverage any Customizer repository in this organization, or collaborate with the IBM Customizer team to create your own repository in this location. This could be a fork of an existing repository or a brand new repository created for you from scratch, depending on your needs.

If you are familiar with GitHub and have a GitHub account, you are well on your way. If not, you can start learning about GitHub here using this quick 10 minute guide. Once you know the rudiments, creating a GitHub account is straight- forward and free for public and open-source projects.

Once you have a GitHub account, create a source repository on the public organization to store and manage your Customizer include files. When you are ready to deploy those resources to IBM Connections Cloud, complete the following steps.

  1. Share your repository with IBM by adding "ibmcnxdev" as a collaborator. IBM creates a fork of your repository under and grants you read access by default.
  2. Work on your extension in your own repository as needed, and then issue a pull request to IBM when your extension is ready.
  3. IBM merges your pull request once its acceptance criteria are met. Repository files are pushed to IBM Customizer via a webhook upon merge.
  4. Repeat, starting with step 2, as needed for extension updates.

In Step 2, issue a pull request across forks (in GitHub parlance). Your own repository, which contains the latest changes, is always the “head fork”, while the “base fork” refers to the repository on

Step 3 involves a lightweight summary review by IBM, which looks at various aspects of the proposed customization, primarily from a performance and security standpoint. However, ultimate responsibility for the behaviour of the Customizer application remains that of the customer who creates or adopts the extension. The review process by IBM provides no guarantee whatsoever of protection against adverse security or performance impacts.

Figure 2. IBM Connections Developers organization on GitHub
IBM Connections Developers Organization on GitHub
IBM Connections Developers Organization on GitHub

Tip: More information on how to integrate your Customizer include files with IBM Connections Cloud is available in the IBM Connections Customizer Episode 2 video on

Restricting access to include-files

By default, any IBM Cloud tenant can use the contents of any repository in either GitHub organization for its Customizer apps. This is flexible and convenient, but may not always be the right solution. If you want to keep the include-files for your Customizer apps private, or restrict usage to a subset of tenants, you can use one of these solutions.

  • Access Control Lists for Tenant Organizations
    Access Control Lists (ACLs) are used to manage access to a particular object. IBM Connections Customizer provides a simple ACL implementation that can control which tenant organizations are allowed to load include files from your repositories. Simply provide an acl.ids file at the root of your project and populate it with the IBM Connections Cloud ids of the tenant organizations to whom you wish to grant access.
    Listing 7. Sample acl.ids file

    This is basically a whitelist for tenant access. Once you create an acl.ids file in your repository, only those tenant organizations listed in the file are allowed to use it. All others are denied access.
  • Private GitHub Repositories on
    GitHub users on a paid GitHub plan can create private repositories, which you can still share with the IBM Connections Developers organization. Private repositories appear in the list of projects under, but only administrators of ibmcnxdev can see the contents. Even though read access to the files is restricted, you should also add an acl.ids file if you want to prevent run time access by other tenant organizations.
  • Private Repositories on
    If the previous two solutions don't fit your needs, you can also request a private repository for your organization’s include-files on In this situation, the JSON definition would typically not contain any include-repo reference, since Customizer resolves the include-files location based on the tenant’s organization id.

Inside a Connections Customizer include file

What exactly does the helloWorld.user.js include file do? Listing 8 shows the code. Certain variable names and comments have been trimmed for readability, but nothing that affects the execution of the script.

Listing 8. Hello World include file
if(typeof(dojo) != "undefined") { 
  require(["dojo/domReady!"], function(){ 
    try { 
      // utility function to wait for a specific element to load... 
      var waitFor = function(callback, eXpath, eXpathRt, maxIV, waitTime){ 
        if(!eXpathRt) var eXpathRt = dojo.body(); 
        if(!maxIV) var maxIV = 10000; // intervals before expiring 
        if(!waitTime) var waitTime = 1; // 1000=1 second 
        if(!eXpath) return; 
        var waitInter = 0; // current interval 
        var intId = setInterval( function(){ 
          if(++waitInter < maxIV && !dojo.query(eXpath,eXpathRt).length) 
          if( waitInter >= maxIV) { 
            console.log("**** WAITFOR ["+eXpath+"] WATCH EXPIRED!!! interval "+waitInter+" (max:"+ maxIV +")"); 
          } else { 
            console.log("**** WAITFOR ["+eXpath+"] WATCH TRIPPED AT interval "+waitInter+" (max:"+maxInter+")"); 
        }, waitTime); // end setInterval() 
      }; // end waitFor() 
      // here we use waitFor to wait for the 
      // .lotusStreamTopLoading div.loaderMain.lotusHidden element 
      // before we proceed to customize the page... 
      waitFor( function(){ 
        // wait until the "loading..." node has been hidden 
        // indicating that we have loaded content. 
        dojo.query("span.shareSome-title")[0].textContent="Hello World! "; 
      }, ".lotusStreamTopLoading div.loaderMain.lotusHidden"); 
    } catch(e) { 
      alert("Exception occurred in helloWorld: " + e); 

For a simple Hello World example, this may appear more complicated than you would expect, but closer inspection simplifies matters considerably.

  • Most of the code is a re-usable template.
  • Only one line of code (line 32) is needed for the actual Hello World UI update.
  • The IBM Connections classic user interface uses Dojo, so the code is injected into a Dojo structured page.

The JavaScript code first validates that Dojo itself is loaded, and then uses a standard Dojo utility (domReady) to wait for the DOM to fully load before calling a bound function to perform the customization. Lines 2 – 23 define a function (waitFor()) that waits a maximum of 10 seconds for the page to fully load. If the page loads within 10 seconds, the function executes a callback function. Otherwise, an error is logged to the JavaScript console.

Figure 3. Hello World extension for IBM Connections Homepage
Hello World extension for IBM Connections Homepage
Hello World extension for IBM Connections Homepage

The waitFor() function call passes in the callback function to manipulate the DOM and modify the UI. The interesting part of the callback function (line 32) locates a DOM element and assigns “Hello World” as the text content. When Customizer loads and runs this extension, the IBM Connections Homepage is modified as shown in Figure 3.

If we view the source of the IBM Connections Homepage in the browser, we can see the code injection at the bottom of the page, as shown in Listing 9.

Listing 9. Customizer script injection
<script type='text/javascript'

URLs with '/files/customizer' path are handled by Customizer, and in this example it fetches the '/helloWorld/helloWorld.user.js' script from the 'global-samples' repository. Your JavaScript code can use such URLs to directly load other resources from repositories you have access to in IBM Connections Cloud. For instance, since 'global-samples' is a public repository that is available to all organizations, any Customizer application can reference resources contained inside it using links of this format:


The profiles sample described later uses a JavaScript code injection to load a CSS file from the profiles folder in the global-samples repository. Be ware that this type of broad access to repositories can also be prevented using the acl.ids mechanism described earlier.

Tip: IBM Connections web pages contain many predefined JavaScript variables that Customizer extensions can use. For instance, lconn is an object with many properties that any extension script can exploit. Thus on line 3, replacing "Hello World: " with "Hello " + lconn.homepage.userName + " " dynamically includes the current user in the Homepage customization. Exploring the lconn object and others like it will show you many valuable features that your extensions can leverage.

Standard samples

Besides Hello World, a number of other ready-made Customizer examples are available for experimentation. You can always find the latest samples in the samples folder of ibmcnxdev/customizer on GitHub.

Each sample has its own subfolder, which contains the App Reg design definition (JSON file) and the resources to be injected to perform the customization (JavaScript, CSS). Take a look at the following examples:


This extension provides an alternative rendering for the Communities pages, so that a user’s communities can be displayed as flip cards rather than a table of rows. Figure 4 shows a list of three communities, with the traditional row-based rendering on the left-hand side juxtaposed with the flip card layout on the right. Each flip card displays the Communities logo until the user hovers over it, whereupon the card is flipped to display the details of the community.

Figure 4. Communities page before and after flipcard customization
Communities Page before and after Flipcard Customization
Communities Page before and after Flipcard Customization

flipCard.json follows the standard App Reg pattern used in the Hello World example. commListCardsFlipStyle.user.js uses the sample Dojo wrapper to envelope the customization, but the code itself is significantly more advanced and serves to give a more real-world indication of what’s possible with Customizer extensions. When the customization is applied, look for the Toggle Extension control on the Communities page. Clicking the button lets the user switch between the standard row layout and the flip card format.


This extension targets the IBM Connections Homepage and reformats the layout of the activity stream updates by accentuating the space surrounding each entry. Figure 5 shows the Homepage with the newsRiver customization. Note how the entries display as sections against a pink backdrop. Also notice that the Hello World extension is also applied to the Home page. This shows how multiple App Reg extensions can target the same IBM Connections path. If you view the source of the page, you will see two JavaScript file injections.

Figure 5. Multiple extensions for IBM Connections homepage
Multiple Extensions for IBM Connections Homepage
Multiple Extensions for IBM Connections Homepage


This extension delivers a more sophisticated rendering of the page that is displayed when the user selects the “My Profile” dropdown menu option in IBM Connections. The new appearance is achieved with stylesheet updates. In the profiles subfolder, profilesCustomization.js simply inserts a link to profilesCustomization.css, which does all the work. The new look is shown in Figure 6. Note the inclusion of a new page header graphic, the relocation of action buttons, and so forth.

Figure 6. Profile page extension
Profile Page Extension
Profile Page Extension

Ordering include-files and extensions

All the preceding samples are simple standalone projects. Customizer applications typically have one main entry point (for example, main.js), and this resource is referenced in the include-files payload property and rendered in the modified HTML output. However the include-files property is an array and can contain more than one file reference. The snippet in Listing 10 is an example from the enhanced-activity-stream project available on the OpenCode4Connections GitHub repository.

Listing 10. Multiple Include Files
"payload": {
        "include-files": [

The three JavaScript files referenced in Listing 10 are injected in the order they are listed.

Although the samples we've looked at have just a single extension each, Customizer applications can contain many extensions. An extension ideally represents a project that carries out a specific task or a tightly related set of tasks. The include-files referenced in the extension must be contained in a single include-repo; that is, it is a strict one-to-one mapping. This makes sense from an organizational standpoint. Extensions do specific jobs and the tools for these jobs are typically found in a single dedicated repository. If your application consists of many related tasks and the tools to carry out the work are many and varied, it would make sense for your application to have multiple extensions, where each extension manages a discrete function and maps to a repository designed for that purpose. However, note that Customizer loads the extensions in alphabetical order, not the order in which they appear in the JSON definition of the application. If your application has multiple extensions and is sensitive to the load order of the include files, you can control the load order by applying an ordered naming convention to your extensions.

NOTE: The alphabetical order of extensions applies across all applications. For example, you may have two separate apps that target the IBM Connections homepage. The App Registry sorts the extensions defined in both applications as a single alphabetical list and returns them to Customizer for injection in that order into the IBM Connections homepage. In most cases, the order of injections does not present a problem. You can see the order at any time by viewing the Connections page source and looking at the <script> tags inserted at the bottom of the page, as shown in Listing 9.

Getting up and running

The sample customizations discussed in this document are available to any IBM Connections Cloud tenant organization. Applying a sample customization is an easy way to get started with IBM Connections Customizer. Any sample can be used by importing the relevant JSON file into an organization’s Application Registry. For example, you can take a copy of the helloWorld.json file from the helloWorld samples project published on the Customizer GitHub repository, and import it into App Reg.

  1. Go to
  2. Navigate to the helloWorld.json file and copy/paste the contents to a local file.
  3. As Admin user in your IBM Connections Cloud organization, go to Admin > Manage Organization > Organization Extensions.
  4. Click the new Apps Manager link to take you to the Pink Application Registry. (Note that this step is temporary, while the new IBM Connections Pink user interface components are being integrated into the cloud.)
  5. Click New App.
  6. When the App Editor appears, click the Import button.
  7. Select your local copy of helloWorld.json.
  8. Insert a match criterion like the one in Listing 5 so that the extension is applied only to you. Match to your user-name, e-mail address, or user id.
  9. Click Save to save the application into Application Registry.
  10. Refresh the IBM Connections Homepage and verify that the Hello World extension appears.

Tip: The steps above are covered in the 'IBM Connections Customizer Episode 01" enablement video on OpenCode4 Connections.

You can experiment with the other samples in a similar way. You may notice that some samples use a JavaScript filename notation that follows the GreaseMonkey naming convention: somename.user.js. These customizations were originally developed as GreaseMonkey scripts using browser-based extensions. They were then deployed on the server in IBM Connections as Customizer extensions. This is standard practice for developing Customizer apps. First create a new browser extension using a user script technology like GreaseMonkey for Firefox or TamperMonkey for Chrome. Once you are happy with the local customization, submit the resources to IBM for review. The JavaScript and CSS files you create using GreaseMonkey or TamperMonkey become your Customizer include files. You can then invoke the customization by creating a Customizer extension (just like the JSON files contained in the standard samples) in the Application Registry.

Some points to note regarding Customizer applications

Support for Customizer applications follows the same policy as any other customization to the IBM Connections user interface. IBM Support can address questions about the customization process, but cannot address questions about the particulars of your customization.

Listing 2 provides the list of currently supported paths for Customizer. This list currently encompasses all core IBM Connections components with the exception of the Administration URLs (BSS) and related IBM collaboration components like Docs, Meetings, Chat, and Verse. The list may be expanded to include these and other components in the future.

Customizer extensions are currently restricted to the organization in which they have been added. Users from one organization may have access to communities in other organizations if they have been invited, but they will not see any customizations added to the “external” communities.

Useful links

Downloadable resources

ArticleTitle=Taking control of the IBM Connections user experience