SDL Web Experience Optimization / Fredhopper Implementation Pitfalls

In this post I would like to address some issues experienced during a recent implementation of the SDL Web Experience Optimization. Experience Optimization integrates SDL Web with Fredhopper and supports creating and managing targeted content for websites driven by SDL Web. For more information, please refer to the online documentation.

Let's set the scenario:

  • 200-300 market websites delivered from SDL Web
  • 400 promotions already created (at the time of the experienced issues)
  • 6 live attributes set in Fredhopper
  • A plan for 1000 promotions in the coming 12 months


Fredhopper response size

Fredhopper stores all its configuration in XML files. In our case, there are hundreds of promotions using the BluePrinting capability with “Include child publications” selected. This results in one XML node per promotion containing a vast list of publication ids. All these get serialized to a single XML leading to a file of 25 MB.

With compression enabled, the 25 MB response gets shrunken very well (to ca. 800 K), however parsing of an XML document of such size is an expensive operation. This has an impact on the webservice which parses the XML from Fredhopper before returning to the SDL Web Experience Optimization (SmartTarget) UI.

A hotfix ( was provided by SDL R&D which brought a considerable improvement in the listing of promotions in the UI. The completion time for the GetPromotions call came down from 48 seconds to 15 seconds.

Automatic promotion publishing

Automatic publishing is enabled by default. Every time a promotion is created or updated in SmartTarget, the updated business.xml file (together with a few other files) are made available inside a directory so the syncserver/syncclient processes can push them to the query instances. In addition, the same files are copied to another directory, so they appear in the history.

In other words, not only the new promotion is saved in Fredhopper but also becomes automatically available to the query instances, and therefore the front-end client applications (i.e. websites).

Turning off automatic publishing avoids these intensive publishing operations at save time also saving on server resources. At save time, the business.xml file is still immediately saved on the indexer instance, but there is no longer any file copying for the syncserver/syncclient processes.

Disabling automatic publishing in Fredhopper requires adding an <ApproveEveryChange>false</ApproveEveryChange> node under the <IndexServer> node in the smarttarget_conf.xml file

Nothing changes in the use of the SmartTarget UI. Newly created and updated promotions are shown instantly. The only difference is that these promotions do not become automatically available to the front-end apps. They would appear as “pending” inside the Fredhopper admin UI.

The change described above requires an additional promotion publishing process. There are two options regarding this:

  1. An administrator publishes the pending promotions from the Fredhopper Business Manager.
  2. Publishing via a scheduled job which uses the com.tridion.smarttarget.webservice.ApproveAllChangesWorkerThread class (available from the smarttarget_core.jar) to perform the work.

With automatic publishing disabled, the time taken to save a promotion in SmartTarget came down from 1.2 min to 10 seconds.

Reload interval on query instances

The previous section relates to the synchronization of published configuration (XML files) from an indexer instance to the query instances, which is done by the syncserver/syncclient processes.
It is also possible to configure the interval in which a query instance will reload these configurations. The reload is done by the qserver process and involves reading the synchronized files and updating the rule engine and in-memory data structures. This qserver process also serves the end-user requests, so it's important to set the reload interval to a suitable time to avoid overload.
The update frequency can be updated via a property inside the query instance's config/system.xml file. The default value is one minute only.
Add the following into the system.xml (under the "root" node):
<node name="com"><map/>
  <node name="fredhopper"><map/>
    <node name="util"><map/>
      <node name="prefs"><map/>
        <node name="BusinessProperties">
            <entry key="auto-check-for-updated-config-interval" value="600000" />
The configuration above puts the update interval to 10 minutes.
  • After changing the configuration it is better to restart the qserver process.
  • Make sure to configure the same on all the query instances.
After this change, no matter how frequent the configuration (XML) gets published, a query qserver will only look for it every 10 minutes.
The change can be verified in the qserver.log file by checking the time interval in which the "Finished reloading business settings" message appears.

Promotion BluePrinting

This section is not meant to provide a recommendation, but only to share our experience in this particular project. From time to time you may find the need to re-index all content published from SDL Web (Tridion) to Fredhopper. In fact, according to Fredhopper's team, a full re-index is something that should happen fairly frequently.
Now imagine having 200 to 300 websites to re-publish from SDL Web in order to trigger the re-indexing against a wiped Fredhopper indexer. This is just not feasible.
As explained in the SmartTarget online documentation, it is possible to create generic promotions applicable for all Websites at a higher level in the BluePrint so that website publications lower down can use them.
So you can avoid indexing content from 200 to 300 lower level publications and having all content indexed from one publication. This means that re-indexing would require republishing content from a unique higher level publication in SDL Web.
There are two ways to achieve this:
  1. Localizing the component templates at the lower level publications and removing the "Add to SmartTarget" TBB.
  2. Adding conditional logic to the TBB in order to only process content originating from the higher level publication.
Of course this solution imposes limitations (i.e. if a promotion should only ever apply to a specific market), but it was a good fit in this particular project.


After a trial and error period, the following memory settings were implemented to meet the ongoing server load:
  • 64 GB of RAM on Fredhopper servers running an indexer and query instances.
  • 32 GB of RAM on Fredhopper servers running a query instance only.