SDK Customisation

SDK Customisation

All SDK configuration goes through the PageSenseSDKOptions object. Pass it in at initialization to control logging, polling frequency, and user storage behaviour.

Initialization with Custom Options  

  1. const sdkOptions = new PageSenseSDKOptions()
  2.   .addLogLevel('DEBUG')
  3.   .addCustomLogger(customLogger)
  4.   .addCustomStorage(customStorage)
  5.   .addPollingInterval(60); // seconds

  6. const pageSenseClient = await PageSenseClientBuilder.createNewPageSenseClient(
  7.   accountId,
  8.   sdkKey,
  9.   projectName,
  10.   sdkOptions
  11. );

Defaults (when no options are passed)  

Setting

Default

Description

Polling Interval

30 seconds

How often the SDK checks for updated settings.

Log Level

INFO

Captures INFO, WARN, ERROR, and FATAL messages.

Logger

Built-in console logger

Logs print to the application console.

User Storage Service

Disabled

Variation assignments are not persisted.


Polling Interval  

How often the SDK checks PageSense for configuration updates. Default is 10 seconds.
Method  
  1. .addPollingInterval(intervalInSeconds)
Parameter  
Parameter
Type
Description
intervalInSeconds
Integer
Polling frequency in seconds.

Example  
  1. const sdkOptions = new PageSenseSDKOptions()
  2.   .addPollingInterval(60);
Things to watch:
  • Under 10 seconds → higher server load, more network traffic, increased resource usage.
  • Over 5 minutes → experiment config changes reach users with a noticeable delay.
  • 30–120 seconds works well for most production setups.

Log Level  

Sets the minimum severity for SDK logs. Only messages at or above this level are captured.
Method  
.addLogLevel(logLevel)

Supported levels  
TRACE · DEBUG · INFO · WARN · ERROR · FATAL

Example  
  1. const sdkOptions = new PageSenseSDKOptions()
  2.   .addLogLevel("DEBUG");
DEBUG captures everything from DEBUG upward. Good for development and production debugging.

Custom Logger  

The SDK logs to the console by default. If your app uses an existing logging framework, plug it in via a custom logger that implements PageSenseLogger.
Method  
  1. .addCustomLogger(customLogger)
Example  
  1. const sdkOptions = new PageSenseSDKOptions()
  2.   .addCustomLogger(customLogger);
Works with Winston, Bunyan, Pino, or any enterprise logging system.

Sample Implementation (Winston)  
  1. const fs      = require('fs');
  2. const FileSys = require('fs');
  3. const Path    = require('path');
  4. const Winston = require('winston');
  5. const { PageSenseLogger } = require('@zohopagesense/pagesense-node-sdk');
  6. /**
  7. * FileSystemLogger — writes SDK logs to a file using Winston.
  8. * @implements PageSenseLogger
  9. */
  10. class FileSystemLogger extends PageSenseLogger {
  11.   constructor() {
  12.     super();
  13.     const logDir = Path.join(__dirname, '../../tests/logs');
  14.     if (!FileSys.existsSync(logDir)) {
  15.       FileSys.mkdirSync(logDir, { recursive: true });
  16.     }
  17.     this.logFilePath = Path.join(logDir, 'pagesense_custom_activity_log.log');
  18.     if (!FileSys.existsSync(this.logFilePath)) {
  19.       FileSys.writeFileSync(this.logFilePath, '');
  20.       FileSys.chmodSync(this.logFilePath, 0o666);
  21.     }
  22.     this.logger = Winston.createLogger({
  23.       level: 'debug',
  24.       format: Winston.format.combine(
  25.         Winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
  26.         Winston.format.printf(
  27.           ({ timestamp, level, message, className }) =>
  28.             `[${timestamp}] [${className}] [${level.toUpperCase()}] ${message}`
  29.         )
  30.       ),
  31.       transports: [
  32.         new Winston.transports.File({
  33.           filename: this.logFilePath,
  34.           level: 'debug'
  35.         })
  36.       ]
  37.     });
  38.   }
  39.   writeLog(levelName, message, className) {
  40.     this.logger.log({ level: levelName.toLowerCase(), message, className });
  41.   }
  42.   trace(className, logMessage)   { this.writeLog('silly', logMessage, className); }
  43.   debug(className, logMessage)   { this.writeLog('debug', logMessage, className); }
  44.   info(className, logMessage)    { this.writeLog('info',  logMessage, className); }
  45.   warning(className, logMessage) { this.writeLog('warn',  logMessage, className); }
  46.   error(className, logMessage)   { this.writeLog('error', logMessage, className); }
  47.   fatal(className, logMessage)   { this.writeLog('error', logMessage, className); }
  48.   // Winston doesn't have a FATAL level — mapped to error.
  49. }
  50. module.exports = FileSystemLogger;

User Storage Service  

The User Storage Service (USS) saves variation assignments so users see the same variation across sessions — even if experiment configurations change between visits.
Without USS, the SDK recalculates assignments from scratch each time using MurmurHash. That works fine until you add a variation or adjust traffic splits — at which point some users may shift to a different variation mid-experiment.

Method  
  1. .addCustomStorage(userStorageService)

Example  
  1. const sdkOptions = new PageSenseSDKOptions()
  2.   .addCustomStorage(userStorageService);
Your implementation must follow the UserStorageService interface — two methods: look up an existing assignment, save a new one. Storage options include JSON files, relational databases, Redis, and cloud storage.

Sample Implementation (File-based)  
  1. const fs   = require('fs');
  2. const path = require('path');
  3. const Winston = require('winston');
  4. const { UserStorageService } = require('@zohopagesense/pagesense-node-sdk');
  5. /**
  6. * FileUserStorageService — stores experiment–variation mappings in a JSON file.
  7. * @implements UserStorageService
  8. */
  9. class FileUserStorageService extends UserStorageService {
  10.   constructor(storageDirectory) {
  11.     super();
  12.     this.storageDir = storageDirectory;
  13.     this.userFile   = path.join(storageDirectory, 'user_storage.json');
  14.     this.logFile    = path.join(storageDirectory, 'user_storage.log');
  15.     this.initializeStorage();
  16.     this.initializeLogger();
  17.   }
  18.   initializeStorage() {
  19.     if (!fs.existsSync(this.storageDir)) {
  20.       fs.mkdirSync(this.storageDir, { recursive: true });
  21.     }
  22.     if (!fs.existsSync(this.userFile)) {
  23.       fs.writeFileSync(this.userFile, JSON.stringify({}, null, 2));
  24.     }
  25.   }
  26.   initializeLogger() {
  27.     this.logger = Winston.createLogger({
  28.       level: 'info',
  29.       format: Winston.format.combine(Winston.format.timestamp(), Winston.format.json()),
  30.       transports: [new Winston.transports.File({ filename: this.logFile })]
  31.     });
  32.   }
  33.   lookUp(userId) {
  34.     if (!fs.existsSync(this.userFile)) return null;
  35.     const data = this.safeJsonDecode(fs.readFileSync(this.userFile, 'utf8'));
  36.     return data && data[userId] ? JSON.stringify(data[userId]) : null;
  37.   }
  38.   async save(userProfile) {
  39.     const userId      = userProfile.getUserId();
  40.     const profileData = this.safeJsonDecode(userProfile.getUserProfileJSONString());
  41.     if (!profileData) return;
  42.     const fileContent  = await fs.promises.readFile(this.userFile, 'utf8').catch(() => '{}');
  43.     const existingData = this.safeJsonDecode(fileContent) || {};
  44.     existingData[userId] = profileData;
  45.     await fs.promises.writeFile(this.userFile, JSON.stringify(existingData, null, 2));
  46.   }
  47.   safeJsonDecode(jsonString) {
  48.     try { return jsonString ? JSON.parse(jsonString) : null; }
  49.     catch { return null; }
  50.   }
  51. }
  52. module.exports = FileUserStorageService;
What the storage file looks like  
  1. {
  2.   "User123": {
  3.     "userId": "User123",
  4.     "experiments": [
  5.       {
  6.         "experiment_key": "expkey0001",
  7.         "variation_key": "varkey001"
  8.       }
  9.     ]
  10.   }
  11. }








We’ve designed this documentation to guide you every step of the way. If you need further assistance or have any questions, don’t hesitate to contact us at support@zohopagesense.com - we’re always here to help!