Personalization Articles / Blogs / Perficient https://blogs.perficient.com/category/services/customer-experience-design/personalization/ Expert Digital Insights Mon, 16 Feb 2026 21:34:44 +0000 en-US hourly 1 https://blogs.perficient.com/files/favicon-194x194-1-150x150.png Personalization Articles / Blogs / Perficient https://blogs.perficient.com/category/services/customer-experience-design/personalization/ 32 32 30508587 Building a Marketing Cloud Custom Activity Powered by MuleSoft https://blogs.perficient.com/2026/02/12/building-a-marketing-cloud-custom-activity-powered-by-mulesoft/ https://blogs.perficient.com/2026/02/12/building-a-marketing-cloud-custom-activity-powered-by-mulesoft/#comments Thu, 12 Feb 2026 17:37:13 +0000 https://blogs.perficient.com/?p=390190

The Why…

Salesforce Marketing Cloud Engagement is incredibly powerful at orchestrating customer journeys, but it was never designed to be a system of record. Too often, teams work around that limitation by copying large volumes of data from source systems into Marketing Cloud data extensions—sometimes nightly, sometimes hourly—just in case the data might be needed in a journey. This approach works, but it comes at a cost: increased data movement, synchronization challenges, latency, and ongoing maintenance that grows over time.

Custom Activities, which are surfaced in Journey Builder, open the door to a different model. Instead of forcing all relevant data into Marketing Cloud ahead of time, a journey can request exactly what it needs at the moment it needs it. When you pair a Custom Activity with MuleSoft, Marketing Cloud can tap into real-time, orchestrated data across your enterprise—without becoming another place where that data has to live.

Example 1: Weather

Consider a simple example like weather-based messaging. Rather than pre-loading weather data for every subscriber into a data extension, a Custom Activity can call an API at decision time, retrieve the current conditions for a customer’s location, and immediately branch the journey or personalize content based on the response. The data is used once, in context, and never stored unnecessarily inside Marketing Cloud.

Example 2: Enterprise Data

The same pattern becomes even more compelling with enterprise data. Imagine a post-purchase journey that needs to know the current status of an order, a shipment, or a service case stored in a system like Data 360. Instead of replicating that operational data into Marketing Cloud—and keeping it in sync—a Custom Activity can call MuleSoft, which in turn retrieves and aggregates the data from the appropriate back-end systems and returns only what the journey needs to proceed.

Example 3: URL Shortener for SMS (Real-Time)

While Marketing Cloud Engagement does provide it own form of a URL shortener, some companies want to use Bitly.  Typically in order to use a Bitly URL we would have to move our logic to Server Side Javascript (SSJS) so the API call to Bitly could be made in the SSJS, and then we could use the URL in our text message.  SSJS forces us to use Automation Studio which cannot be run in real-time and must be scheduled.  This is very important to note, that being able to do API calls within the flow of a Journey is very powerful and helps to meet more real-time use cases. With these Custom Activities we can ask Mulesoft to call the Bitly API which returns the shortened URL so then it can be used in the email or SMS message.

This is where MuleSoft truly shines. It acts as a clean abstraction layer between Marketing Cloud and your enterprise landscape, handling authentication, transformation, orchestration, and governance. Marketing Cloud stays focused on customer engagement, while MuleSoft owns the complexity of integrating with source systems. The result is a more scalable, real-time, and maintainable architecture—one that reduces data duplication, respects system boundaries, and enables richer, more contextual customer experiences.

The How….

So how does this actually work in practice? In the next section, we’ll walk through how a Marketing Cloud Custom Activity can call a MuleSoft API in the middle of a Journey, receive a response in real time, and use that data to drive decisions or personalization. We’ll focus on the key building blocks—what lives in Marketing Cloud, what belongs in MuleSoft, and how the two communicate—so you can see how this pattern comes together without turning Marketing Cloud into yet another integration layer.

Part 1 – Hosted Files

Every Marketing Cloud Custom Activity starts with hosted files. These files provide the user interface and configuration that Journey Builder interacts with, making them the foundation of the entire solution. At a minimum, this includes five main files/folders.

  1. index.html – This is what you see in Journey Builder when you click on the Custom Activity to configure it.
  2. config.json – This holds the Mulesoft endpoint to call and what output arguments will be used.
  3. customactivity.js – The javascript that is running behind the index.html page.
  4. postmonger.js – More javascript to support the index.html page
  5. A folder called images must exist and a single icon.png image should exist in it.  This image is shown within Journey Builder.

Blog Ca Files

These files tell Marketing Cloud how the activity behaves, what endpoints it uses, and how it appears to users when they drag it onto a journey. While the business logic ultimately lives elsewhere, within Mulesoft in our example, hosted files are what make the Custom Activity feel native inside Journey Builder.

In this pattern, hosted files are intentionally lightweight. Their primary responsibility is to capture configuration input from the marketer—such as which API operation to call, optional parameters, or behavior flags—and pass that information along when the journey executes. They are not responsible for complex transformations, orchestration, or direct system-to-system integrations. By keeping the hosted files focused on presentation and configuration, you reduce coupling with backend systems and make the Custom Activity easier to maintain, update, and reuse across different journeys.

A place to do a simple proof of concept is on GitHub if you want to try this yourself.  You can easily create these four files and one folder in a repo.  If you use GitHub, then you do have to use the Pages functionality in GitHub to make that repo public.  This public URL will then be used when we configure the ‘Installed App’ in Marketing Cloud Engagement later.

In production, Custom Activity config.json and UI assets should be hosted on an enterprise‑grade HTTPS platform like Azure App Service, AWS CloudFront/S3, or Heroku—not GitHub.

One thing I had to overcome is that the config.json gets cached at the Marketing Cloud server level as talked about in this post.  So when I had to make changes to my config.json, I would create a new folder (v2 / v3) in my repository and then use that path in my Installed Package in the Component added in Journey Builder.

Part 2 – API Server – Mulesoft

This is really the beauty here.  Instead of building API calls in SSJS that are hard to debug, difficult to scale and hard to secure, we get to pass all of that off to an enterprise API platform like Mulesoft.  It really is the best of both worlds.  There are basically two main pieces on the Mulesoft side: A) Five endpoints to develop and B) security.

The Five Endpoints.

Journey Builder uses four lifecycle endpoints to manage the activity and one execute endpoint to process each contact and return outArguments used for decisioning and personalization.

The five endpoints that have to be developed in Mulesoft are…

Endpoint Called When Per Contact? Returns outArguments?
/save User saves config ❌ ❌
/validate User publishes ❌ ❌
/publish Journey goes live ❌ ❌
/execute Contact hits activity ✅ ✅
/stop Journey stops ❌ ❌

For the save, validate, publish and stop in Mulesoft they need to return a 200 status code and can return an empty JSON string of {} in the most basic example.

For the execute method, it should also return a 200 status code and simple json that looks like this for any outArguments…  { status: “myStatus” }

The Security.

The first piece of security is configured in the config.json file.   There is a useJwt key that can either be true of false for each of the endpoint.   If it is true, then Mulesoft will receive an encoded string based on the JWT Signing Secret that was created from the Installed Package in Marketing Cloud.  If jwt is false then Mulesoft will just receive the plain JSON.  For production level work we should make sure jwt is true.
We can also use an OAuth 2.0 Bearer Token.  We want to make sure that our Mulesoft endpoints are only responding to calls coming from Marketing Cloud Engagement.

Part 3 – Journey Builder – Custom Activities

Once the configuration details are setup in the app described in step 2, then creating the custom activity and adding it to the Journey is pretty quick.
  1. Go to the ‘Installed Package’ in setup and create a new app following these steps.
    1. When you add your ‘Component’ to the Installed App selecting ‘Customer Updates’ in the ‘Category’ drop-down worked for me.
    2. My ‘Endpoint URL’ had a format like this:  https://myname.github.io/my_repo_name/v3/
      Blog Ca Package
  2. Create a new Journey
  3. Your new Custom Activity will show up in the Components panel on the left-hand side.  Since we selected ‘Customer Updates’ in step 1 above, our ‘Send to Mulesoft V3a’ Custom Activity shows in that section.   The name under the icon comes from the config.json file.  The image is the icon.png from the images folder.
    Blog Jb View
  4. Once you drag your Custom Activity onto the Journey Builder page you will be able to click on it to configure it.
  5. The user interface from the index.html will display when you click on it so you can configure your Custom Activity.  Note that this user interface could be changed to collect whatever configuration needs to be collected.
    Blog Ca Indexpage
  6. When the ‘Done’ buttons are clicked on the page, then the javascript runs and saves the configuration details into the Journey Builder itself.  In my example the gray and blue ‘Done’ buttons are hooked to the same javascript and really do the same thing.

Part 4 – How to use the Custom Activity

outArguments

Now that we have our Custom Activity configured and in our journey, now the integration with Mulesoft becomes a configuration detail which is so great for admins.  In the config.json file there are two places where the outArguments are placed.
The first is in the arguments section towards the top.  Here I can provide a default value for my status field, which is this case is the very intuitive “DefaultStatus”.  🙂
"arguments": {
   "execute": {
     "inArguments": [],
     "outArguments": [
       {
         "status": "DefaultStatus"
       }
     ],
     "url": "https://mymuleAPI.partofurl.usa-e1.cloudhub.io/api/marketingCloud/execute",
     "useJwt": false,
     "timeout": 60000,
     "retryCount": 3,
     "retryDelay": 3000,
     "concurrentRequests": 5
   }
 },

The second place is lower in the config.json file in the schema section and describes the actual data type for my output variable.  We can see the status variable is a ‘Text’ field, that has access = visible and direction = out.

"schema":{
      "arguments":{
          "execute":{
              "inArguments": [],
              "outArguments":[
                  {
                      "status":{
                          "dataType":"Text",
                          "isNullable":true,
                          "access":"visible",
                          "direction":"out"
                      }
                  }
              ]
          }
      }
  }

Note in the example below that I did not use a typical status value like ‘Not Started’, ‘In Progress ‘ and ‘Done’.  That would have made more sense. 🙂  Instead I was running five records through my journey with various versions of my last name: Luschen, Luschen2, Luschen3, Luschen4 and Luschen5.  So Mulesoft was basically received these different spellings through the json being passed over, parsed it out of the incoming json and then injected it into the response json in the status field.  This is what the incoming data extension looked like.

Blog De

An important part of javascript turned out to be setting the isConfigured flag to true in the customActivity.js file.  This makes sure Journey Builder understands that node has been configured when the journey is ‘Validated’ before it is ‘Activated’.

activity.metaData = activity.metaData || {};
activity.metaData.isConfigured = true;

Now that we have our ‘status’ field as an output from Mulesoft via the Custom Activity, I will describe how it can be used in either a Decision Split or some AmpScript.

Decision Split

The outArguments show up under the ‘Journey Data’ portion of the configuration screen.  Once you select the ‘status’ outArgument you configure the rest of the decision split like any other one you have built before.
Blog Ca Decision Split
Blog Ca Decision Split2

AmpScript

These outArguments are also available as send context attributes so they are easy to use in any manner you want within your AmpScript for either email or SMS personalization.
%%[
SET @status = AttributeValue(“status”)
]%%
%%=v(@status)=%%

The Wrap-up…

As you let the flexibility of these Custom Activities sink in, it really creates a lot of flexible patterns.  The more data we can surface to our marketing team, the more dynamic, personalized and engaging the content will become.  While we all see more campaigns and use cases being developed on the new Agentforce Marketing, we all know that Marketing Cloud Engagement has some legs to it yet.  I hope this post has given you some ideas to make your Marketing team look like heros as they use Journey Builder to its fullest potential!

I want to thank my Mulesoft experts Anusha Danda and Jana Pagadala for all of their help!

Please connect with me on LinkedIn for more conversations!  I am here to help make you a hero with your next Salesforce project.

Example Files…

Config.JSON

{  
  "workflowApiVersion": "1.1",
  "metaData": {
    "icon": "images/icon.png",
    "category": "customer",
    "isConfigured": true,
    "configOnDrop": false
  },
  "type": "REST",
  "lang": {
    "en-US": {
      "name": "Send to MuleSoft V3a",
      "description": "Calls MuleSoft to orchestrate downstream systems V3a."
    }
  },
  "arguments": {
    "execute": {
      "inArguments": [],
      "outArguments": [
        {
          "status": "DefaultStatus"
        }
      ],
      "url": "https://myMuleAPI.rajrd4-1.usa-e1.cloudhub.io/api/marketingCloud/execute",
      "useJwt": true,
      "timeout": 60000,
      "retryCount": 3,
      "retryDelay": 3000,
      "concurrentRequests": 5
    }
  },
  "configurationArguments": {
    "applicationExtensionKey": "MY_KEY_ANYTHING_I_WANT_MULESOFT_TEST",
    "save":    { "url": "https://myMuleAPI.rajrd4-1.usa-e1.cloudhub.io/api/marketingCloud/save",    "useJwt": true },
    "publish": { "url": "https://myMuleAPI.rajrd4-1.usa-e1.cloudhub.io/api/marketingCloud/publish", "useJwt": true },
    "validate":{ "url": "https://myMuleAPI.rajrd4-1.usa-e1.cloudhub.io/api/marketingCloud/validate","useJwt": true },
    "stop":    { "url": "https://myMuleAPI.rajrd4-1.usa-e1.cloudhub.io/api/marketingCloud/stop",    "useJwt": true }
  },
  "userInterfaces": {
    "configModal": { "height": 480, "width": 480 }
  },
  "schema":{
      "arguments":{
          "execute":{
              "inArguments": [],
              "outArguments":[
                  {
                      "status":{
                          "dataType":"Text",
                          "isNullable":true,
                          "access":"visible",
                          "direction":"out"
                      }
                  }
              ]
          }
      }
  }
}

Index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Terry – JB → Mule Custom Activity</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; margin: 24px; }
    label { display:block; margin-top: 16px; font-weight:600; }
    input, select, button { padding: 8px; font-size: 14px; }
    button { margin-top: 20px; }
    .hint { color:#666; font-size:12px; }
  </style>
</head>
<body>
  <h2>Send to MuleSoft – Custom Activity</h2>
  <p class="hint">Configure the API URL and (optionally) bind a Journey field3.</p>

  <label for="apiUrl">MuleSoft API URL</label>
  <input id="apiUrl" type="url" placeholder="https://api.example.com/journey/execute2" style="width:100%" />

  <label for="fieldPicker">Bind a field from Entry Source (optional)</label>
  <select id="fieldPicker">
    <option value="">— none —</option>
  </select>

  <button id="done">Done</button>

  <!-- Postmonger must be local in your repo - ADD BEGIN AND CLOSE BRACKETS BELOW-->
  script src="./postmonger.js"></script
  <!-- Your Postmonger client logic - ADD BEGIN AND CLOSE BRACKETS BELOW-->
  script src="./customActivity.js?v=2026-02-02v1"></script
</body>
</html>

 

CustomActivity.js

/* global Postmonger */
(function () {
  'use strict';

  // Create the Postmonger session (bridge to Journey Builder)
  const connection = new Postmonger.Session();

  // Journey Builder supplies this payload when we call 'ready'
  let activity = {};
  let schema = [];
  let pendingSelectedField = null;  // holds saved token until options exist

  document.addEventListener('DOMContentLoaded', () => {
    // Listen to JB lifecycle events
    connection.on('initActivity', onInitActivity);
    connection.on('requestedTokens', onTokens);
    connection.on('requestedEndpoints', onEndpoints);
    connection.on('requestedSchema', onRequestedSchema); // common pattern in field pickers
    connection.on('clickedNext', onDone);

    // Signal readiness and request useful context
    connection.trigger('ready');
    connection.trigger('requestTokens');
    connection.trigger('requestEndpoints');

    // Optionally, ask for Entry Source schema (undocumented but widely used in the field)
    connection.trigger('requestSchema');

    // Bind UI
    document.getElementById('done').addEventListener('click', onDone);
  });

  function onInitActivity (payload) {
    activity = payload || {};
    // Re-hydrate UI if the activity is being edited
    try {
      const args = (activity.arguments?.execute?.inArguments || [])[0] || {};
      if (args.apiUrl) document.getElementById('apiUrl').value = args.apiUrl;
      if (args.selectedField) document.getElementById('fieldPicker').value = args.selectedField;
      pendingSelectedField = args.selectedField;
    } catch (e) {}
  }

  function onTokens (tokens) {
    // If you ever need REST/SOAP tokens, they arrive here
    // console.log('JB tokens:', tokens);
  }

  function onEndpoints (endpoints) {
    // REST base URL for BU, if you need it
    // console.log('JB endpoints:', endpoints);
  }

  function onRequestedSchema (payload) {
    schema = payload?.schema || [];
    const select = document.getElementById('fieldPicker');

    // Keep current value if re-opening
    const current = select.value;
    // Reset options (leave the first '— none —')
    select.length = 1;

    // Populate with Entry Source keys (e.g., {{Event.APIEvent-UUID.Email}})
    schema.forEach(col => {
      const opt = document.createElement('option');
      opt.value = `{{${col.key}}}`;
      opt.textContent = col.key.split('.').pop();
      select.appendChild(opt);
    });

    if (current) select.value = current;
    if (pendingSelectedField) select.value = pendingSelectedField;
    
  }

  function onDone () {
    const apiUrl = document.getElementById('apiUrl').value?.trim() || '';
    const selectedField = document.getElementById('fieldPicker').value || '';

    // Validate minimal config
    if (!apiUrl) {
      alert('Please provide a MuleSoft API URL.10');
      return;
    }
    // alert(selectedField);

    // Build inArguments that JB will POST to /execute at run time
    const inArguments = [{
      apiUrl,            // static value from UI
      selectedField      // optional mustache ref to Journey Data
    }];

    // Mutate the activity payload we received and hand back to JB
    activity.arguments = activity.arguments || {};
    activity.arguments.execute = activity.arguments.execute || {};
    activity.arguments.execute.inArguments = inArguments;

    activity.metaData = activity.metaData || {};
    activity.metaData.isConfigured = true;

    // Tell Journey Builder to save this configuration
    connection.trigger('updateActivity', activity);
  }
})();

 

]]>
https://blogs.perficient.com/2026/02/12/building-a-marketing-cloud-custom-activity-powered-by-mulesoft/feed/ 3 390190
Enhancing Fluent UI DetailsList with Custom Sorting, Filtering, Lazy Loading and Filter Chips https://blogs.perficient.com/2026/02/04/enhancing-fluent-ui-detailslist-with-custom-sorting-filtering-lazy-loading-and-filter-chips/ https://blogs.perficient.com/2026/02/04/enhancing-fluent-ui-detailslist-with-custom-sorting-filtering-lazy-loading-and-filter-chips/#respond Wed, 04 Feb 2026 07:48:24 +0000 https://blogs.perficient.com/?p=390027

Fluent UI DetailsList custom sorting and filtering can transform how structured data is displayed. While the default DetailsList component is powerful, it doesn’t include built‑in features like advanced sorting, flexible filtering, lazy loading, or selection‑driven filter chips. In this blog, we’ll show you how to extend Fluent UI DetailsList with these enhancements, making it more dynamic, scalable, and user‑friendly.

We’ll also introduce simple, reusable hooks that allow you to implement your own filtering and sorting logic, which will be perfect for scenarios where the default behavior doesn’t quite fit your needs. By the end, you’ll have a flexible, feature-rich Fluent UI DetailsList setup with sorting and filtering that can handle complex data interactions with ease.

Here’s what our wrapper brings to the table:

  • Context‑aware column menus that enable sorting beyond simple A↔Z ordering
  • Filter interfaces designed for each data type (.i.e. freeform text, choice lists, numeric ranges, or time values)
  • Selection chips that display active filters and allow quick deselection with a single click
  • Lazy loading with infinite scroll, seamlessly integrated with your API or pagination pipeline
  • One orchestrating component that ties all these features together, eliminating repetitive boilerplate

Core Architecture

The wrapper includes:

  • Column Definitions: To control how each column sorts/filters
  • State & Refs: To manage final items, full dataset, and UI flags
  • Default Logic By overriding hooks – onSort, onFilter
  • Selection: Powered by Fluent UI Selection API
  • Lazy Loading: Using IntersectionObserver
  • Filter Chips: Reflect selected rows

Following are the steps to achieve these features:

Step 1: Define Column Metadata

Each column in the DetailsList must explicitly describe its data type, sort behavior, and filtering behavior. This metadata helps the wrapper render the correct UI elements such as combo boxes, number inputs, or time pickers.

Each column needs metadata describing:

  • Field type
  • Sort behavior
  • Filter behavior
  • UI options (choice lists, icons, etc.)
export interface IDetailsListColumnDefinition {
  fieldName: string;
  displayName: string;
  columnType?: DetailsListColumnType; // Text, Date, Time, etc.
  sortDetails?: { fieldType: SortFilterType };
  filterDetails?: {
    fieldType: SortFilterType;
    filterOptions?: IComboBoxOption[];
    appliedFilters?: any[];
  };
}

Following is the example:

const columns = [{
  fieldName: 'status',
  displayName: 'Status',
  columnType: DetailsListColumnType.Text,
  sortDetails: {
    fieldType: SortFilterType.Choice
  },
  filterDetails: {
    fieldType: SortFilterType.Choice,
    filterOptions: [{
      key: 'Active',
      text: 'Active'
    },
    {
      key: 'Inactive',
      text: 'Inactive'
    }]
  }
}];

Step 2: Implement Type-Aware Fluent UI DetailsList Custom Sorting

The sorting mechanism dynamically switches based on the column’s data type. Time fields are converted to minutes to ensure consistent sorting, while text and number fields use their native values. It supports following:

  • Supports Text, Number, NumberRange, Date, and Time (custom handling for time via minute conversion).
  • Sort direction is controlled from the column’s context menu.
  • Works with default sorting or lets you inject custom sorting via onSort.
  • Default sorting uses lodash orderBy unless onSort is provided

Sample code for its implementation can be written as follows:

switch (sortColumnType) {
case SortFilterType.Time:
  sortedItems = orderBy(sortedItems, [item = >getTimeForField(item, column.key)], column.isSortedDescending ? ['desc'] : ['asc']);
  break;
default:
  sortedItems = orderBy(sortedItems, column.fieldName, column.isSortedDescending ? 'desc': 'asc');
}

Step 3: Implement Fluent UI DetailsList Custom Filtering (Text/Choice/Range/Time)

Filtering inputs change automatically based on column type. Text and choice filters use combo boxes, while numeric fields use range inputs. Time filters extract and compare HH:mm formatted values.

Text & Choice Filters

Implemented using Fluent UI ComboBox as follows:

<ComboBox

    allowFreeform={!isChoiceField}
    
    multiSelect={true}
    
    options={comboboxOptions}
    
    onChange={(e, option, index, value) =>
    
    _handleFilterDropdownChange(e, column, option, index, value)
    
    }
/>

Number Range Filter

Implemented as two input boxes, min & max for defining number range.

  • Min/Max chips are normalized in order [min, max].
  • Only applied if present; absence of either acts as open‑ended range.

Time Filter

For filtering time, we are ignoring date part and just considering time part.

  • Times are converted to minutes since midnight(HH:mm) to sort reliably regardless of display format.
  • Filtering uses date-fns format() for display and matching.

Step 4: Build the Filtering Pipeline

This step handles the filtering logic as capturing user-selected values, updating filter states, re-filtering all items, and finally applying the active sorting order. If custom filter logic is provided, it overrides the defaults. It will work as follows:

  1. User changes filter
  2. Update column.filterDetails.appliedFilters
  3. Call onFilter (if provided)
  4. Otherwise run default filter pipeline as follows:

allItems → apply filter(s) → apply current sort → update UI

Following are some helper functions that can be created for handing filter/sort logic:

  • _filterItems
  • _applyDefaultFilter
  • _applyDefaultSort

Step 5: Display Filter Chips

When selection is enabled, each selected row appears as a dismissible chip above the grid. Removing the chip automatically deselects the row, ensuring tight synchronization between UI and data.

<FilterChip key={filterValue.key} filterValue={filterValue} onRemove={_handleChipRemove} />

Note: This is a custom subcomponent used to handle filter chips. Internally it display selected values in chip form and we can control its values and functioning using onRemove and filterValue props.

Chip removal:

  • Unselects row programmatically
  • Updates the selection object

Step 6: Implementing Lazy Loading (IntersectionObserver)

The component makes use of IntersectionObserver, to detect if the user reaches the end of the list. Once triggered, it calls the lazy loading callback to fetch the next batch of items from the server or state.

  • An additional row at the bottom triggers onLazyLoadTriggered() as it enters the viewport.
  • Displays a spinner while loading; attaches the observer when more data is available.

A sentinel div at the bottom triggers loading:

observer.current = new IntersectionObserver(async entries => {
  const entry = entries[0];
  if (entry.isIntersecting) {
    observer.current ? .unobserve(lazyLoadRef.current!);
    await lazyLoadDetails.onLazyLoadTriggered();
  }
});

Props controlling behavior:

lazyLoadDetails ? :{
  enableLazyLoad: boolean;
  onLazyLoadTriggered: () => void;
  isLoading: boolean;
  moreItems: boolean;
};

Step 7: Sticky Headers

Sticky headers keep the column titles visible as the user scrolls through large datasets, improving readability and usability. Following is the code where, maxHeight property determines the scrollable container height:

const stickyHeaderStyle = {
  root: {
    maxHeight: stickyHeaderDetails ? .maxHeight ? ?450
  },
  headerWrapper: {
    position: 'sticky',
    top: 0,
    zIndex: 1
  }
};

Step 8: Putting It All Together — Minimal Example for Fluent UI DetailsList custom filtering and sorting

Following is an example where we are calling our customizes details list component:

<CustomDetailsList
  columnDefinitions={columns}
  items={data}
  allItems={data}
  checkboxVisible={CheckboxVisibility.always}
  initialSort={{ fieldName: "name", direction: SortDirection.Asc }}
  filterChipDetails={{
    filterChipKeyColumnName: "key",

    filterChipColumnName: "name",
  }}
  stickyHeaderDetails={{ enableStickyHeader: true, maxHeight: 520 }}
  lazyLoadDetails={{
    enableLazyLoad: true,

    isLoading: false,

    moreItems: true,

    onLazyLoadTriggered: async () => {
      // load more
    },
  }}
/>;

Accessibility & UX Notes

  • Keyboard: Enter key applies text/number inputs instantly; menu remains open so users can stack filters.
  • Clear filter: Context menu shows “Clear filter” action only when a filter exists; there’s also a “Clear Filters (n)” button above the grid that resets all columns at once.
  • Selection cap: To begin, maxSelectionCount helps prevent accidental bulk selections; next, it provides immediate visual feedback so users can clearly see their limits in action.

Performance Guidelines

  • Virtualization: For very large datasets, you can enable virtualization and validate both menu positioning and performance. For current example, onShouldVirtualize={() => false} is used to maintain a predictable menu experience.
  • Server‑side filtering/sorting: If your dataset is huge, pass onSort/onFilter and do the heavy lifting server‑side, then feed the component the updated page through items.
  • Lazy loading: Use moreItems to hide the sentinel when the server reports the last page; set isLoading to true to show the spinner row.

Conclusion

Finally, we have created a fully customized Fluent UI DetailsList with custom filtering and sorting which condenses real‑world list interactions into one drop‑in component. CustomDetailsList provides a production-ready, extensible, developer-friendly data grid wrapper with following enhanced features:

  • Clean context menus for type‑aware sort & filter
  • Offers selection chips for quick, visual interaction and control
  • Supports lazy loading that integrates seamlessly with your API
  • Allows you to keep headers sticky to maintain clarity in long lists
  • Delivers a ready‑to‑use design while allowing full customization when needed

GitHub repository

Please refer to the GitHub repository below for the full code. A sample has been provided within to illustrate its usage:

https://github.com/pk-tech-dev/customdetailslist

 

 

 

]]>
https://blogs.perficient.com/2026/02/04/enhancing-fluent-ui-detailslist-with-custom-sorting-filtering-lazy-loading-and-filter-chips/feed/ 0 390027
Build a Custom Accordion Component in SPFx Using React – SharePoint https://blogs.perficient.com/2026/01/22/build-a-custom-accordion-component-in-spfx-using-react-sharepoint/ https://blogs.perficient.com/2026/01/22/build-a-custom-accordion-component-in-spfx-using-react-sharepoint/#comments Thu, 22 Jan 2026 07:50:54 +0000 https://blogs.perficient.com/?p=389813

When building modern SharePoint Framework (SPFx) solutions, reusable UI components play a crucial role in keeping your code clean, scalable, and maintainable. In particular, interactive components help improve the user experience without cluttering the interface.

Among these components, the Accordion is a commonly used UI element. It allows users to expand and collapse sections, making it easier to display large amounts of information in a compact and organized layout. In this blog, we’ll walk through how to create a custom accordion component in SPFx using React.


Create the Accordion Wrapper Component

To begin with, we’ll create a wrapper component that acts as a container for multiple accordion items. At a high level, this component’s responsibility is intentionally simple: it renders child accordion items while keeping styling and layout consistent across the entire accordion.This approach allows individual accordion items to remain focused on their own behavior, while the wrapper handles structure and reusability.

Accordion.tsx

import * as React from 'react';
import styles from './Accordion.module.scss';
import classNames from 'classnames';
import { IAccordionItemProps } from './subcomponents/AccordionItem';

import { ReactElement } from 'react';

export interface IAccordionProps {
  children?:
    | ReactElement<IAccordionItemProps>
    | ReactElement<IAccordionItemProps>[];
  className?: string;
}


const Accordion: React.FunctionComponent<
  React.PropsWithChildren<IAccordionProps>
> = (props) => {
  const { children, className } = props;
  return (
    <div className={classNames(styles.accordionSubcomponent, className)}>
      {children}
    </div>
  );
};

export default Accordion;

Styling with SCSS Modules

Next, let’s focus on styling. SPFx supports SCSS modules, which is ideal for avoiding global CSS conflicts and keeping styles scoped to individual components. Let’s see styling for accordion and accordion items.

Accordion.module.scss

.accordionSubcomponent {
    margin-bottom: 12px;
    .accordionTitleRow {
        display: flex;
        flex-direction: row;
        align-items: center;
        padding: 5px;
        font-size: 18px;
        font-weight: 600;
        cursor: pointer;
        -webkit-touch-callout: none;
        -webkit-user-select: none;
        -khtml-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        border-bottom: 1px solid;
        border-color: "[theme: neutralQuaternaryAlt]";
        background: "[theme: neutralLighter]";
    }
    .accordionTitleRow:hover {
        opacity: .8;
    }
    .accordionIconCol {
        padding: 0px 5px;
    }
    .accordionHeaderCol {
        display: inline-block;
        width: 100%;
    }
    .iconExpandCollapse {
        margin-top: -4px;
        font-weight: 600;
        vertical-align: middle;
    }
    .accordionContent {
        margin-left: 12px;
        display: grid;
        grid-template-rows: 0fr;
        overflow: hidden;
        transition: grid-template-rows 200ms;
        &.expanded {
          grid-template-rows: 1fr;
        }
        .expandableContent {
          min-height: 0;
        }
    }
}

Styling Highlights

  • Grid‑based animation for expand/collapse
  • SharePoint theme tokens
  • Hover effects for better UX

Creating Accordion Item Component

Each expandable section is managed by AccordionItem.tsx.

import * as React from 'react';
import styles from '../Accordion.module.scss';
import classNames from 'classnames';
import { Icon } from '@fluentui/react';
import { useState } from 'react';


export interface IAccordionItemProps {
  iconCollapsed?: string;
  iconExpanded?: string;
  headerText?: string;
  headerClassName?: string;
  bodyClassName?: string;
  isExpandedByDefault?: boolean;
}
const AccordionItem: React.FunctionComponent<React.PropsWithChildren<IAccordionItemProps>> = (props: React.PropsWithChildren<IAccordionItemProps>) => {
  const {
    iconCollapsed,
    iconExpanded,
    headerText,
    headerClassName,
    bodyClassName,
    isExpandedByDefault,
    children
  } = props;
  const [isExpanded, setIsExpanded] = useState<boolean>(!!isExpandedByDefault);
  const _toggleAccordion = (): void => {
    setIsExpanded((prevIsExpanded) => !prevIsExpanded);
  }
  return (
    <Stack>
    <div className={styles.accordionTitleRow} onClick={_toggleAccordion}>
        <div className={styles.accordionIconCol}>
            <Icon
                iconName={isExpanded ? iconExpanded : iconCollapsed}
                className={styles.iconExpandCollapse}
            />
        </div>
        <div className={classNames(styles.accordionHeaderCol, headerClassName)}>
            {headerText}
        </div>
    </div>
    <div className={classNames(styles.accordionContent, bodyClassName, {[styles.expanded]: isExpanded})}>
      <div className={styles.expandableContent}>
        {children}
      </div>
    </div>
    </Stack>
  )
}
AccordionItem.defaultProps = {
  iconExpanded: 'ChevronDown',
  iconCollapsed: 'ChevronUp'
};
export default AccordionItem;

Example Usage in SPFx Web Part

<Accordion>
  <AccordionItem headerText="What is SPFx?">
    <p>SPFx is a development model for SharePoint customizations.</p>

  </AccordionItem>

  <AccordionItem
    headerText="Why use custom controls?"
    isExpandedByDefault={true}
  >
    <p>Custom controls improve reusability and UI consistency.</p>
  </AccordionItem>
</Accordion>

Accordion

Conclusion

By building a custom accordion component in SPFx using React, you gain:

  • Full control over UI behavior
  • Lightweight and reusable code
  • Native SharePoint theming

This pattern is perfect for:

  • FAQ sections
  • Configuration panels
  • Dashboard summaries
]]>
https://blogs.perficient.com/2026/01/22/build-a-custom-accordion-component-in-spfx-using-react-sharepoint/feed/ 1 389813
Building Custom Search Vertical in SharePoint Online for List Items with Adaptive Cards https://blogs.perficient.com/2026/01/14/build-custom-search-vertical-in-sharepoint-for-list-items-with-adaptive-cards/ https://blogs.perficient.com/2026/01/14/build-custom-search-vertical-in-sharepoint-for-list-items-with-adaptive-cards/#respond Wed, 14 Jan 2026 06:25:15 +0000 https://blogs.perficient.com/?p=389614

This blog explains the process of building a custom search vertical in SharePoint Online that targets a specific list using a dedicated content type. It covers indexing important columns, and mapping them to managed properties for search. Afterward, a result type is configured with Adaptive Cards JSON to display metadata like title, category, author, and published date in a clear, modern format. Then we will have a new vertical on the hub site, giving users a focused tab for Article results. In last, the result is a streamlined search experience that highlights curated content with consistent metadata and an engaging presentation.

For example, we will start with the assumption that a custom content type is already in place. This content type includes the following columns:

  • Article Category – internal name article_category
  • Article Topic – internal name article_topic

We’ll also assume that a SharePoint list has been created which uses this content type, with the ContentTypeID: 0x0101009189AB5D4FBA4A9C9BFD5F3F9F6C3B

With the content type and list ready, the next steps focus on configuring search so these items can be surfaced effectively in a dedicated vertical.

Index Columns in the List

Indexing columns optimize frequently queried metadata, including category or topic, for faster search.. This improves performance and makes it easier to filter and refine results in a custom vertical.

  • Go to List Settings → Indexed Columns.
  • Ensure article_category and article_topic are indexed for faster search queries.

Create Managed Properties

First, check which RefinableString managed properties are available in your environment. After you identify them, configure them as shown below.:

Refinable stringField nameAlias nameCrawled property
RefinableString101article _topicArticleTopicows_article _topic
RefinableString102article_categoryArticleCategoryows_article_category
RefinableString103article_linkArticleLinkows_article_link

Tip: Creating an alias name for a managed property makes it easier to read and reference. This step is optional — you can also use the default RefinableString name directly.

To configure these fields, follow the steps below:

  • Go to the Microsoft Search Admin Center → Search schema.
  • Go to Search Schema → Crawled Properties
  • Look for the field (ex. article _topic or article_category),  find its crawled property (starts with ows_)
  • Click on property → Add mapping
  • Popup will open → Look for unused RefinableString properties (e.g., RefinableString101, RefinableString102) → click “Ok” button
  • Click “Save”
  • Likewise, create managed properties for all the required columns.

Once mapped, these managed properties can be searched, found, and defined. This means they can be used in search filters, result types, and areas.

Creating a Custom Search Vertical

This lets you add a dedicated tab that filters results to specific content, improving findability and user experience. It ensures users quickly access targeted items like lists, libraries, or content types without sifting through all search results. In this example, we will set the filter for a specific articles list.

This lets you add a dedicated tab that filters results to specific content, improving findability and user experience. It ensures users quickly access targeted items like lists, libraries, or content types without sifting through all search results. In this example, we will set the filter for a specific articles list.

Following the steps given below to create and configure a custom search vertical from the admin center:

  • In “Verticals” tab, add a new value as per following configuration:
    • Name = “Articles”
    • Content source = SharePoint and OneDrive
    • KQL query = It is the actual filter where we specify the filter for items from the specific list to display in search results. In our example, we will set it as: ContentTypeId:0x0101009189AB5D4FBA4A9C9BFD5F3F9F6C3B*Verticalskql
    • Filters: Filters are an optional setting that allows users to narrow search results based on specific criteria. In our example, we can add a filter by category. To add “Categories” filter on search page, follow below steps:
      • Click on add filter
      • Select “RefinableString102” (This is a refinable string managed property for “article_category” column as setup in above steps)
      • Name = “Category” or other desired string to display on search

Set Vertical filter

Creating a Result Type

Creating a new result type in the Microsoft Search Admin Center lets you define how specific content (like items from a list or a content type) is displayed in search results. In this example, we set some rules and use Adaptive Card template to make search easier and more interesting.

Following are the steps to create a new result type in the admin center.

  • Go to admin center, https://admin.cloud.microsoft
  • Settings → Search & intelligence
  • In “Customizations”, go to “Result types”
  • Add new result types with the following configurations:
    • Name = “AarticlesResults” (Note: Specify any name you want to display in search vertical)
    • Content source = SharePoint and OneDrive
    • Rules
      • Type of content = SharePoint list item
      • ContentTypeId starts with 0x0101009189AB5D4FBA4A9C9BFD5F3F9F6C3B (Note: Content type Id created in above steps)Set Result type
      • Layout = Put the JSON string for Adaptive card to display search result. Following is the JSON for displaying the result:
        {
           "type": "AdaptiveCard",
          "version": "1.3",
          "body": [
            {
              "type": "ColumnSet",
              "columns": [
                {
                  "type": "Column",
                  "width": "auto",
                  "items": [
                    {
                    "type": "Image",
                    "url": <url of image/thumbnail to be displayed for each displayed item>,
                    "altText": "Thumbnail image",
                    "horizontalAlignment": "Center",
                    "size": "Small"
                    }
                  ],
                  "horizontalAlignment": "Center"
                },
                {
                  "type": "Column",
                  "width": 10,
                  "items": [
                    {
                      "type": "TextBlock",
                      "text": "[${ArticleTopic}](${first(split(ArticleLink, ','))})",
                      "weight": "Bolder",
                      "color": "Accent",
                      "size": "Medium",
                      "maxLines": 3
                    },
                    {
                      "type": "TextBlock",
                      "text": "**Category:** ${ArticleCategory}",
                      "spacing": "Small",
                      "maxLines": 3
                    }
                  ],
                  "spacing": "Medium"
                }
              ]
            }
          ],
          "$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
        }

        Set Result type adaptive card

When you set up everything properly, the final output will look like this:

Final search results

Conclusion

Finally, we created a special search area in SharePoint Online for list items with adaptive cards. This changes how users use search. Important metadata becomes clearly visible when you index key columns, map them to managed properties, and design a tailored result type. Since we used Adaptive Card, it adds a modern, interesting presentation layer. It makes it easier to scan and more visually appealing. In the end, publishing a special section gives you a special tab that lets you access a special list of content. This makes it easier to work with and makes the user experience better.

]]>
https://blogs.perficient.com/2026/01/14/build-custom-search-vertical-in-sharepoint-for-list-items-with-adaptive-cards/feed/ 0 389614
5 Imperatives Financial Leaders Must Act on Now to Win in the Age of AI-Powered Experience https://blogs.perficient.com/2025/12/02/5-imperatives-financial-leaders-must-act-on-now-to-win-in-the-age-of-ai-powered-experience/ https://blogs.perficient.com/2025/12/02/5-imperatives-financial-leaders-must-act-on-now-to-win-in-the-age-of-ai-powered-experience/#respond Tue, 02 Dec 2025 12:29:07 +0000 https://blogs.perficient.com/?p=388106

Financial institutions are at a pivotal moment. As customer expectations evolve and AI reshapes digital engagement, leaders in marketing, CX, and IT must rethink how they deliver value.

Adobe’s report, State of Customer Experience in Financial Services in an AI-Driven World,” reveals that only 36% of the customer journey is currently personalized, despite 74% of executives acknowledging rising customer expectations. With transformation already underway, financial leaders face five imperatives that demand immediate action to drive relevance, trust, and growth.

1. Make Personalization More Meaningful

Personalization has long been a strategic focus, but today’s consumers expect more than basic segmentation or name-based greetings. They want real-time, omnichannel interactions that align with their financial goals, life stages, and behaviors.

To meet this demand, financial institutions must evolve from reactive personalization to predictive, intent-driven engagement. This means leveraging AI to anticipate needs, orchestrate journeys, and deliver content that resonates with individual context.

Perficient Adobe-consulting principal Ross Monaghan explains, “We are still dealing with disparate data and slow progression into a customer 360 source of truth view to provide effective personalization at scale. What many firms are overlooking is that this isn’t just a data issue. We’re dealing with both a people and process issue where teams need to adjust their operational process of typical campaign waterfall execution to trigger-based and journey personalization.”

His point underscores that personalization challenges go beyond technology. They require cultural and operational shifts to enable real-time, AI-driven engagement.

2. Redesign the Operating Model Around the Customer

Legacy structures often silo marketing, IT, and operations, creating friction in delivering cohesive customer experiences. To compete in a digital-first world, financial institutions must reorient their operating models around the customer, not the org chart.

This shift requires cross-functional collaboration, agile workflows, and shared KPIs that align teams around customer outcomes. It also demands a culture that embraces experimentation and continuous improvement.

Only 3% of financial services firms are structured around the customer journey, though 19% say it should be the ideal.

3. Build Content for AI-Powered Search

As AI-powered search becomes a primary interface for information discovery, the way content is created and structured must change. Traditional SEO strategies are no longer enough.

Customers now expect intelligent, personalized answers over static search results. To stay visible and trusted, financial institutions must create structured, metadata-rich content that performs in AI-powered environments. Content must reflect experience-expertise-authoritativeness-trustworthiness principles and be both machine-readable and human-relevant. Success depends on building discovery journeys that work across AI interfaces while earning customer confidence in moments that matter.

4. Unify Data and Platforms for Scalable Intelligence

Disconnected data and fragmented platforms limit the ability to generate insights and act on them at scale. To unlock the full potential of AI and automation, financial institutions must unify their data ecosystems.

This means integrating customer, behavioral, transactional, and operational data into a single source of truth that’s accessible across teams and systems. It also involves modernizing MarTech and CX platforms to support real-time decisioning and personalization.

But Ross points out, “Many digital experience and marketing platforms still want to own all data, which is just not realistic, both in reality and cost. The firms that develop their customer source of truth (typically cloud-based data platforms) and signal to other experience or service platforms will be the quickest to marketing execution maturity and success.”

His insight emphasizes that success depends not only on technology integration but also on adopting a federated approach that accelerates marketing execution and operational maturity.

5. Embed Guardrails Into GenAI Execution

As financial institutions explore GenAI use cases, from content generation to customer service automation, governance must be built in from the start. Trust is non-negotiable in financial services, and GenAI introduces new risks around accuracy, bias, and compliance.

Embedding guardrails means establishing clear policies, human-in-the-loop review processes, and robust monitoring systems. It also requires collaboration between legal, compliance, marketing, and IT to ensure responsible innovation.

At Perficient, we use our PACE (Policies, Advocacy, Controls, Enablement) Framework to holistically design tailored operational AI programs that empower business and technical stakeholders to innovate with confidence while mitigating risks and upholding ethical standards.

The Time to Lead is Now

The future of financial services will be defined by how intelligently and responsibly institutions engage in real time. These five imperatives offer a blueprint for action, each one grounded in data, urgency, and opportunity. Leaders who move now will be best positioned to earn trust, drive growth, and lead in the AI-powered era.

Learn About Perficient and Adobe’s Partnership

Are you looking for a partner to help you transform and modernize your technology strategy? Perficient and Adobe bring together deep industry expertise and powerful experience technologies to help financial institutions unify data, orchestrate journeys, and deliver customer-centric experiences that build trust and drive growth.

Get in Touch With Our Experts

]]>
https://blogs.perficient.com/2025/12/02/5-imperatives-financial-leaders-must-act-on-now-to-win-in-the-age-of-ai-powered-experience/feed/ 0 388106
Sitecore Content SDK: What It Offers and Why It Matters https://blogs.perficient.com/2025/11/19/sitecore-content-sdk-what-it-offers-and-why-it-matters/ https://blogs.perficient.com/2025/11/19/sitecore-content-sdk-what-it-offers-and-why-it-matters/#respond Wed, 19 Nov 2025 15:08:05 +0000 https://blogs.perficient.com/?p=388367

Sitecore has introduced the Content SDK for XM Cloud-now Sitecore AI to streamline the process of fetching content and rendering it on modern JavaScript front-end applications. If you’re building a website on Sitecore AI, the new Content SDK is the modern, recommended tool for your development team.

Think of it as a specialized, lightweight toolkit built for one specific job: getting content from Sitecore AI and displaying it on your modern frontend application (like a site built with Next.js).

Because it’s purpose-built for Sitecore AI, it’s fast, efficient, and doesn’t include a lot of extra baggage. It focuses purely on the essential “headless” task of fetching and rendering content.

What About the JSS SDK?
This is the original toolkit Sitecore created for headless development.

The key difference is that the JSS SDK was designed to be a one-size-fits-all solution. It had to support both the new, headless Sitecore AI and Sitecore’s older, all-in-one platform, Sitecore XP/XM.

To do this, it had to include extra code and dependencies to support older features, like the “Experience Editor”. This makes the JSS SDK “bulkier” and more complex. If you’re only using Sitecore AI, you’re carrying around a lot of extra weight you simply don’t need.

The Sitecore Content SDK is the modern, purpose-built toolkit for developers using Sitecore AI, providing seamless, out-of-the-box integration with the platform’s most powerful capabilities. This includes seamless visual editing that empowers marketers to build and edit pages in real-time, as well as built-in hooks for personalization and analytics that simplify the delivery and tracking of targeted user experiences. For developers, it provides GraphQL utilities to streamline data fetching and is deeply optimized for Next.js, enabling high-performance features like server-side rendering. Furthermore, with the recent introduction of App Router support (in beta), the SDK is evolving to give developers even more granular control over performance, SEO, bundle sizes, and security through a more modern, modular code structure.

What does the Content SDK offer?

1) App Router support (v1.2)

With version 1.2.0, Sitecore Content SDK introduces App Router support in beta. While the full fledged stable release is expected soon, developers can already start exploring its benefits and work flow with 1.2 version.
This isn’t just a minor update; it’s a huge step toward making your front-end development more flexible and highly optimized.

Why should you care? –
The App Router introduces a fantastic change to your starter application’s code structure and how routing works. Everything becomes more modular and declarative, aligning perfectly with modern architecture practices. This means defining routes and layouts is cleaner, content fetching is neatly separated from rendering, and integrating complex Next.js features like dynamic routes is easier than ever. Ultimately, this shift makes your applications much simpler to scale and maintain as they grow on Sitecore AI.

Performance: Developers can fine-tune route handling with nested layouts and more aggressive and granular caching to seriously boost overall performance, leading to faster load times.

Bundle Size: Smaller bundle size because it uses React Server Components (RSC) to render components. It help fetch and render component from server side without making the static files in bundle.

Security: It helps with security by giving improved control over access to specific routes and content.

With the starter kit applications, this is how app router routing structure looks like:

Approute

 

2) New configs – sitecore.config.ts & sitecore.cli.config.ts

The sitecore.config.ts file, located in the root of your application, acts as the central configuration point for Content SDK projects. It is replacement of the older temp/config file used by the JSS SDK. It contains properties that can be used throughout the application just by importing the file. It contains important properties like sitename, defaultLanguage, edge props like contextid. Starter templates include a very lightweight version containing only the mandatory parameters necessary to get started. Developers can easily extend this file as the project grows and requires more specific settings.

Key Aspects:

Environment Variable Support: This file is designed for deployment flexibility using a layered approach. Any configuration property present in this file can be sourced in three ways, listed in order of priority:

  1. Explicitly defined in the configuration file itself.
  2. Fallback to a corresponding environment variable (ideal for deployment pipelines).
  3. Use a default value if neither of the above is provided.

This layered approach ensures flexibility and simplifies deployment across environments.

 

The sitecore.cli.config.ts file is dedicated to defining and configuring the commands and scripts used during the development and build phases of a Content SDK project.

Key Aspects:

CLI Command Configuration: It dictates the commands that execute as part of the build process, such as generateMetadata() and generateSites(), which are essential for generating Sitecore-related data and metadata for the front-end.

Component Map Generation: This file manages the configuration for the automatic component map generation. This process is crucial for telling Sitecore how your front-end components map to the content structure, allowing you to specify file paths to scan and define any files or folders to exclude. Explored further below.

Customization of Build Process: It allows developers to customize the Content SDK’s standard build process by adding their own custom commands or scripts to be executed during compilation.

While sitecore.config.ts handles the application’s runtime settings (like connection details to Sitecore AI), sitecore.cli.config.ts works in conjunction to handle the development-time configuration required to prepare the application for deployment.

Cli Config

 

3) Component map

In Sitecore Content SDK-based applications, every custom component must be manually registered in the .sitecore/component-map.ts file located in the app’s root. The component map is a registry that explicitly links Sitecore renderings to their corresponding frontend component implementations. The component map tells the Content SDK which frontend component to render for each component receives from Sitecore. When the rendering gets added to any page via presentation, component map tells which frontend rendering should be rendered at the place.

Key Aspects:

Unlike JSS implementations that automatically maps components, the Content SDK’s explicit component map enables better tree-shaking. Your final production bundle will only include the components you have actually registered and use, resulting in smaller, more efficient application sizes.

This is how it looks like: (Once you start creating custom component, you have to add the component name here to register.)

Componentmap

 

4) Import map

The import map is a tool used specifically by the Content SDK’s code generation feature. It manages the import paths of components that are generated or used during the build process. It acts as a guide for the code generation engine, ensuring that any new code it creates correctly references your existing components.
Where it is: It is a generated file, typically found at ./sitecore/import-map.ts, that serves as an internal manifest for the build process. You generally do not need to edit this file manually.
It simplifies the logic of code generation, guaranteeing that any newly created code correctly and consistently references your existing component modules.

The import map generation process is configurable via the sitecore.cli.config.ts file. This allows developers to customize the directories scanned for components.

 

5) defineMiddleware in the Sitecore Content SDK

defineMiddleware is a utility for composing a middleware chain in your Next.js app. It gives you a clean, declarative way to handle cross-cutting concerns like multi-site routing, personalization, redirects, and security all in one place. This centralization aligns perfectly with modern best practices for building scalable, maintainable functions.

The JSS SDK leverages a “middleware plugin” pattern. This system is effective for its time, allowing logic to be separated into distinct files. However, this separation often requires developers to manually manage the ordering and chaining of multiple files, which could become complex and less transparent as the application grew. The Content SDK streamlines this process by moving the composition logic into a single, highly readable utility which can customizable easily by extending Middleware

Middleware

 

6) Debug Logging in Sitecore Content SDK

Debug logging helps you see what the SDK is doing under the hood. Super useful for troubleshooting layout/dictionary fetches, multisite routing, redirects, personalization, and more. The Content SDK uses the standard DEBUG environment variable pattern to enable logging by namespace. You can selectively turn on logging for only the areas you need to troubleshoot, such as: content-sdk:layout (for layout service details) or content-sdk:dictionary (for dictionary service details)
For all available namespaces and parameters, refer to sitecore doc – https://doc.sitecore.com/sai/en/developers/content-sdk/debug-logging-in-content-sdk-apps.html#namespaces 

 

7) Editing & Preview

In the context of Sitecore’s development platform, editing and preview render optimization with the Content SDK involves leveraging middleware, architecture, and framework-specific features to improve the performance of rendering content in editing and preview modes. The primary goal is to provide a fast and responsive editing experience for marketers using tools like Sitecore AI Pages and the Design Library. EditingRenderMiddleware: The Content SDK for Next.js includes optimized middleware for editing scenarios. Instead of a multi-step process involving redirects, the optimized middleware performs an internal, server-side request to return the HTML directly. This reduces overhead and speeds up rendering significantly.
This feature Works out of the box in most environments: Local container, Vercel / Netlify, SitecoreAI (defaults to localhost as configured)

For custom setups, override the internal host with: SITECORE_INTERNAL_EDITING_HOST_URL=https://host
This leverages a Integration with XM Cloud/Sitecore AI Pages for visual editing and testing of components.

 

8) SitecoreClient

The SitecoreClient class in the Sitecore Content SDK is a centralized data-fetching service that simplifies communication with your Sitecore content backend typically with Experience Edge or preview endpoint via GraphQL endpoints.
Instead of calling multiple services separately, SitecoreClient lets you make one organized request to fetch everything needed for a page layout, dictionary, redirects, personalization, and more.

Key Aspect:

Unified API: One client to access layout, dictionary, sitemap, robots.txt, redirects, error pages, multi-site, and personalization.
To understand all key methods supported, please refer to sitecore documentation: https://doc.sitecore.com/sai/en/developers/content-sdk/the-sitecoreclient-api.html#key-methods

Sitecoreclientmethods

9) Built-In Capabilities for Modern Web Experiences

GraphQL Utilities: Easily fetch content, layout, dictionary entries, and site info from Sitecore AI’s Edge and Preview endpoints.
Personalization & A/B/n Testing: Deploy multiple page or component variants to different audience segments (e.g., by time zone or language) with no custom code.
Multi-site Support: Seamlessly manage and serve content across multiple independent sites from a single Sitecore AI instance.
Analytics & Event Tracking: Integrated support via the Sitecore Cloud SDK for capturing user behavior and performance metrics.
Framework-Specific Features: Includes Next.js locale-based routing for internationalization, and supports both SSR and SSG for flexible rendering strategies.

 

10) Cursor for AI development

Starting with Content SDK version 1.1, Sitecore has provided comprehensive “Cursor rules” to facilitate AI-powered development.
The integration provides Cursor with sufficient context about the Content SDK ecosystem and Sitecore development patterns. These set of rules and context helps to accelerate the development. The cursor rules are created for contentsdk with starter application under .cursor folder. This enables the AI to better assist developers with tasks specific to building headless Sitecore components, leading to improved development consistency and speed following same patterns just by providing few commands in generic terms. Example given in below screenshot for Hero component which can act as a pattern to create another similar component by cursor.

Cursorrules

 

11) Starter Templates and Example Applications

To accelerate development and reduce setup time, the Sitecore Content SDK includes a set of starter templates and example applications designed for different use cases and development styles.
The SDK provides a Next.js JavaScript starter template that enables rapid integration with Sitecore AI. This template is optimized for performance, scalability, and best practices in modern front-end development.
Starter Applications in examples

basic-nextjs -A minimal Next.js application showcasing how to fetch and render content from Sitecore AI using the Content SDK. Ideal for SSR/SSG use cases and developers looking to build scalable, production-ready apps.

basic-spa -A single-page application (SPA) example that demonstrates client-side rendering and dynamic content loading. Useful for lightweight apps or scenarios where SSR is not required.

Other demo site to showcase Sitecore AI capabilities using the Content SDK:

kit-nextjs-article-starter

kit-nextjs-location-starter

kit-nextjs-product-starter

kit-nextjs-skate-park

 

Final Thoughts

The Sitecore Content SDK represents a major leap forward for developers building on Sitecore AI. Unlike the older JSS SDK, which carried legacy dependencies, the Content SDK is purpose-built for modern headless architectures—lightweight, efficient, and deeply optimized for frameworks like Next.js. With features like App Router support, runtime and CLI configuration flexibility, and explicit component mapping, it empowers teams to create scalable, high-performance applications while maintaining clean, modular code structures.

]]>
https://blogs.perficient.com/2025/11/19/sitecore-content-sdk-what-it-offers-and-why-it-matters/feed/ 0 388367
The Personalization Gap Is Hurting Financial Services, Here’s How to Close It https://blogs.perficient.com/2025/10/15/the-personalization-gap-is-hurting-financial-services-heres-how-to-close-it/ https://blogs.perficient.com/2025/10/15/the-personalization-gap-is-hurting-financial-services-heres-how-to-close-it/#respond Wed, 15 Oct 2025 15:22:25 +0000 https://blogs.perficient.com/?p=387848

In today’s financial landscape, personalization is no longer a luxury; it’s a customer expectation. Yet, according to Adobe’s latest State of Customer Experience in Financial Services in an AI-Driven World report, only 36% of the customer journey is currently personalized, despite 74% of financial services executives acknowledging that their customers expect tailored interactions.

This gap isn’t just a missed opportunity; it’s a trust breaker.

Why Personalization Matters More Than Ever

Financial decisions are deeply personal. Whether a customer is exploring mortgage options, planning for retirement, or managing small business finances, they expect advice and experiences that reflect their unique goals and life stage. Generic nudges and one-size-fits-all messaging simply don’t cut it anymore.

Early-stage interactions—like product discovery or financial education—are especially critical. These are high-value moments where relevance builds trust and guides decision-making. Yet many institutions fall short, lacking the orchestration needed to deliver personalized engagement across these initial touchpoints.

What’s Holding Institutions Back?

The report highlights several barriers:

  • Fragmented data systems that prevent a unified view of the customer
  • Legacy operating models that prioritize product silos over customer journeys
  • Compliance concerns that limit personalization efforts, even when customers expect it

These challenges are compounded by the rise of AI-powered experiences, which demand real-time, context-aware personalization across channels.

Adobe State of CX In Fs in an AI-Driven World Report Stat 2025

The Path Forward: Adaptive, Lifecycle Personalization

To close the gap, financial institutions must evolve from episodic personalization to adaptive, full-lifecycle engagement. That means:

  • Investing in unified customer profiles and behavioral insights
  • Building real-time content engines that respond to customer signals
  • Designing personalization strategies that grow with the relationship and not just the transaction

Download the full Adobe report to explore the top 10 insights shaping the future of financial services, and discover how your organization can lead with intelligence, responsibility, and trust.

Learn About Perficient and Adobe’s Partnership

Are you looking for a partner to help you transform and modernize your technology strategy? Perficient and Adobe bring together deep industry expertise and powerful experience technologies to help financial services organizations unify data, orchestrate journeys, and deliver customer-centric experiences that build trust and drive growth.

Get in Touch With Our Experts

]]>
https://blogs.perficient.com/2025/10/15/the-personalization-gap-is-hurting-financial-services-heres-how-to-close-it/feed/ 0 387848
Closing the Gap Between Expectations and Experience in Financial Services https://blogs.perficient.com/2025/10/06/closing-the-gap-between-expectations-and-experience-in-financial-services/ https://blogs.perficient.com/2025/10/06/closing-the-gap-between-expectations-and-experience-in-financial-services/#comments Mon, 06 Oct 2025 12:09:20 +0000 https://blogs.perficient.com/?p=387620

As customer expectations continue to rise, financial services organizations are under increasing pressure to deliver personalized, seamless, and secure digital experiences. Adobe’s latest report, The Total Economic Impact of Adobe’s Content Supply Chain Solution, reveals how Generative AI and connected data are reshaping the industry and why now is the time for financial institutions to evolve.

A Wake-Up Call for Financial Services

Consumers today expect more than just secure transactions. They want personalized recommendations, consistent omnichannel experiences, and transparency in how their data and AI-generated content are used. Yet, Adobe’s research shows a significant gap between these expectations and what financial services brands currently deliver:

  • 90% of consumers rate data privacy as critical, but only 58% feel their data is handled securely
  • 79% expect consistent experiences across channels, but just 47% say brands deliver
  • Only 33% feel brands anticipate their needs with relevant offers, despite 70% expecting it

This disconnect presents a clear opportunity for financial institutions to differentiate themselves by investing in AI-powered personalization and content delivery.

GenAI Moves From Concept to Competitive Advantage

Generative AI is no longer a futuristic concept; it is now a reality. It’s a strategic imperative. In 2025, 56% of financial services organizations are prioritizing GenAI to improve client interactions and employee productivity. Wealth and asset management firms lead the charge with 60% focusing on AI-driven client engagement compared to 52% in retail banking.

Use cases are expanding rapidly:

  • Chatbots are the most mature application, with 49% of organizations already using them
  • Journey optimization and data analysis are gaining traction, with over 40% of firms piloting or deploying solutions
  • AI is also being used to automate workflows, generate creative content, and personalize customer experiences across channels

Efficiency, Engagement, and Growth

Executives are already seeing tangible benefits from AI adoption:

  • 51% report major gains in content production speed
  • 50% see improved team productivity
  • 47% note freed-up resources for strategic initiatives

These improvements are driving better customer engagement and laying the foundation for scalable, personalized marketing.

Overcoming Compliance, Data Silos, and Culture

Despite the momentum, scaling AI in financial services isn’t without challenges. Governance, compliance, and privacy concerns top the list, especially in retail banking, where 59% of executives cite compliance as the biggest hurdle. Siloed data is another major issue, particularly in wealth and asset management, where 51% struggle to unify customer insights.

To move forward, organizations must:

  • Establish cross-functional AI governance committees
  • Invest in real-time data platforms
  • Prioritize ethical AI practices to protect brand reputation

The Road Ahead

The Adobe report paints a clear picture: financial services organizations must embrace AI and digital transformation to stay competitive. Key trends shaping the future include:

  • Hyper-Personalization | Real-time, one-to-one interactions are the goal, but only 33% of firms can update offers based on browsing history.
  • Omnichannel Consistency | Practitioners feel pressure to deliver more content across more channels, with 43% citing increased volume demands.
  • Sustainable Innovation | Wealth managers are leading the way in sustainable investing, responding to growing consumer demand.

To succeed, financial institutions must take a methodical, compliant approach to AI adoption, balancing innovation with trust. The winners will be those who connect data, content, and customer insights to deliver meaningful, personalized experiences at scale.

Ready to Transform Your Digital Experience Strategy?

Navigating the complexities of AI adoption, data governance, and digital transformation requires more than just technology. It demands deep industry expertise and a strategic partner who understands the nuances of financial services.

Our experts bring together Adobe solutions, generative AI innovation, and financial services experience to help you:

  • Deliver personalized, compliant, and scalable digital experiences
  • Break down data silos and activate real-time insights
  • Accelerate content creation and journey optimization with AI
  • Build trust through secure, transparent, and consistent customer interactions

Whether you’re modernizing for next-gen customers, launching new digital offerings, or scaling AI across your organization, we’re here to help you move forward with confidence.

Let’s connect and explore how we can elevate your customer experience together.

]]>
https://blogs.perficient.com/2025/10/06/closing-the-gap-between-expectations-and-experience-in-financial-services/feed/ 1 387620
Perficient Earns Adobe’s Real-time CDP Specialization https://blogs.perficient.com/2025/09/16/perficient-earns-adobes-real-time-cdp-specialization/ https://blogs.perficient.com/2025/09/16/perficient-earns-adobes-real-time-cdp-specialization/#respond Tue, 16 Sep 2025 11:02:09 +0000 https://blogs.perficient.com/?p=386861

We’re proud to announce that we’ve earned our 8th Adobe specialization in Adobe’s Real-time Customer Data Platform. This milestone reflects our continued commitment to delivering exceptional digital experiences and deepens our already robust Adobe partnership.

View our other specializations in the Adobe partner directory.

What is Adobe’s Real-time CDP?

Real-time Customer Data Platform is a powerful solution that enables organizations to unify customer data from multiple sources in real-time, creating actionable profiles that drive personalized, omnichannel experiences. As customer expectations continue to rise, Real-time CDP empowers brands to activate their data with precision, speed, and relevance.

Why This Specialization Matters

Achieving an Adobe specialization is no small feat. Adobe’s rigorous program evaluates partners on their technical expertise, successful implementations, and proven customer impact. This new Real-time CDP specialization validates Perficient’s ability to architect and deploy scalable data solutions that help clients unlock the full potential of their customer data.

Delivering Real-time Impact Across Industries

Our team has already helped leading brands across industries leverage Adobe’s Real-time CDP to:

  • Break down data silos and unify fragmented customer information
  • Build real-time, privacy-compliant customer profiles
  • Activate audiences across channels for personalized engagement
  • Drive measurable business outcomes through data-driven marketing

“This specialization is a testament to our team’s deep expertise in Adobe Experience Cloud and our ability to help clients harness real-time data to deliver meaningful customer experiences,” said Lynn Brading, Global Adobe Alliance Director at Perficient.

How We’re Innovating and Growing With Adobe

As we continue to expand our Adobe capabilities, this specialization reinforces our position as a trusted advisor for enterprise organizations seeking to modernize their digital ecosystems. Whether you’re just beginning your journey with Real-time CDP or looking to optimize an existing implementation, Perficient is ready to help.

Let’s Connect

Explore our Adobe partner page to learn more about our specializations, success stories, and how we can help you turn data into a strategic advantage.

]]>
https://blogs.perficient.com/2025/09/16/perficient-earns-adobes-real-time-cdp-specialization/feed/ 0 386861
AI in Medical Device Software: From Concept to Compliance https://blogs.perficient.com/2025/07/31/ai-in-medical-device-software-development-lifecycle/ https://blogs.perficient.com/2025/07/31/ai-in-medical-device-software-development-lifecycle/#respond Thu, 31 Jul 2025 14:30:11 +0000 https://blogs.perficient.com/?p=385582

Whether you’re building embedded software for next-gen diagnostics, modernizing lab systems, or scaling user-facing platforms, the pressure to innovate is universal, and AI is becoming a key differentiator. When embedded into the software development lifecycle (SDLC), AI offers a path to reduce costs, accelerate timelines, and equip the enterprise to scale with confidence. 

But AI doesn’t implement itself. It requires a team that understands the nuance of regulated software, SDLC complexities, and the strategic levers that drive growth. Our experts are helping MedTech leaders move beyond experimentation and into execution, embedding AI into the core of product development, testing, and regulatory readiness. 

“AI is being used to reduce manual effort and improve accuracy in documentation, testing, and validation.” – Reuters MedTech Report, 2025 

Whether it’s generating test cases from requirements, automating hazard analysis, or accelerating documentation, we help clients turn AI into a strategic accelerator. 

AI-Accelerated Regulatory Documentation 

Outcome: Faster time to submission, reduced manual burden, improved compliance confidence 

Regulatory documentation remains one of the most resource-intensive phases of medical device development.  

  • Risk classification automation: AI can analyze product attributes and applicable standards to suggest classification and required documentation. 
  • Drafting and validation: Generative AI can produce up to 75% of required documentation, which is then refined and validated by human experts. 
  • AI-assisted review: Post-editing, AI can re-analyze content to flag gaps or inconsistencies, acting as a second set of eyes before submission. 

AI won’t replace regulatory experts, but it will eliminate the grind. That’s where the value lies. 

For regulatory affairs leaders and product teams, this means faster submissions, reduced rework, and greater confidence in compliance, all while freeing up resources to focus on innovation. 

Agentic AI in the SDLC 

Outcome: Increased development velocity, reduced error rates, scalable automation 

Agentic AI—systems of multiple AI agents working in coordination—is emerging as a force multiplier in software development. 

  • Task decomposition: Complex development tasks are broken into smaller units, each handled by specialized agents, reducing hallucinations and improving accuracy. 
  • Peer review by AI: One agent can validate the output of another, creating a self-checking system that mirrors human code reviews. 
  • Digital workforce augmentation: Repetitive, labor-intensive tasks (e.g., documentation scaffolding, test case generation) are offloaded to AI, freeing teams to focus on innovation. This is especially impactful for engineering and product teams looking to scale development without compromising quality or compliance. 
  • Guardrails and oversight mechanisms: Our balanced implementation approach maintains security, compliance, and appropriate human supervision to deliver immediate operational gains and builds a foundation for continuous, iterative improvement. 

Agentic AI can surface vulnerabilities early and propose mitigations faster than traditional methods. This isn’t about replacing engineers. It’s about giving them a smarter co-pilot. 

AI-Enabled Quality Assurance and Testing 

Outcome: Higher product reliability, faster regression cycles, better user experiences 

AI is transforming QA from a bottleneck into a strategic advantage. 

  • Smart regression testing: AI frameworks run automated test suites across releases, identifying regressions with minimal human input. 
  • Synthetic test data generation: AI creates high-fidelity, privacy-safe test data in minutes—data that once took weeks to prepare. 
  • GenAI-powered visual testing: AI evaluates UI consistency and accessibility, flagging issues that traditional automation often misses. 
  • Chatbot validation: AI tools now test AI-powered support interfaces, ensuring they provide accurate, compliant responses. 

We’re not just testing functionality—we’re testing intelligence. That requires a new kind of QA.

Organizations managing complex software portfolios can unlock faster, safer releases. 

AI-Enabled, Scalable Talent Solutions 

Outcome: Scalable expertise without long onboarding cycles 

AI tools are only as effective as the teams that deploy them. We provide specialized talent—regulatory technologists, QA engineers, data scientists—that bring both domain knowledge and AI fluency. 

  • Accelerate proof-of-concept execution: Our teams integrate quickly into existing workflows, leveraging Agile and SAFe methodologies to deliver iterative value and maintain velocity. 
  • Reduce internal training burden: AI-fluent professionals bring immediate impact, minimizing ramp-up time and aligning with sprint-based development cycles. 
  • Ensure compliance alignment from day one: Specialists understand regulated environments and embed quality and traceability into every phase of the SDLC, consistent with Agile governance models. 

Whether you’re a CIO scaling digital health initiatives or a VP of Software managing multiple product lines, our AI-fluent teams integrate seamlessly to accelerate delivery and reduce risk. 

Proof of Concept Today, Scalable Solution Tomorrow 

Outcome: Informed investment decisions, future-ready capabilities 

Many of the AI capabilities discussed are already in early deployment or active pilot phases. Others are in proof-of-concept, with clear paths to scale. 

We understand that every organization is on a unique AI journey. Whether you’re starting from scratch, experimenting with pilots, or scaling AI across your enterprise, we meet you where you are. Our structured approach delivers value at every stage, helping you turn AI from an idea into a business advantage. 

As you evaluate your innovation and investment priorities across the SDLC, consider these questions: 

  1. Are we spending too much time on manual documentation?
  2. Do we have visibility into risk classification and mitigation?
  3. Can our QA processes scale with product complexity?
  4. How are we building responsible AI governance?
  5. Do we have the right partner to operationalize AI?

Final Thought: AI Demands a Partner, Not Just a Platform 

AI isn’t the new compliance partner. It’s the next competitive edge, but only when guided by the right strategy. For MedTech leaders, AI’s real opportunity comes by adopting and scaling it with precision, speed, and confidence. That kind of transformation can be accelerated by a partner who understands the regulatory terrain, the complexity of the SDLC, and the business outcomes that matter most. 

No matter where you sit — on the engineering team, in the lab, in business leadership, or in patient care — AI is reshaping how MedTech companies build, test, and deliver value. 

From insight to impact, our industry, platform, data, and AI expertise help organizations modernize systems, personalize engagement, and scale innovation. We deliver AI-powered transformation that drives engagement, efficiency, and loyalty throughout the lifecycle—from product development to commercial success. 

  • Business Transformation: Deepen collaboration, integration, and support throughout the value chain, including channel sales, providers, and patients. 
  • Modernization: Streamline legacy systems to drive greater connectivity, reduce duplication, and enhance employee and consumer experiences. 
  • Data + Analytics: Harness real-time data to support business success and to impact health outcomes. 
  • Consumer Experience: Support patient and consumer decision making, product usage, and outcomes through tailored digital experiences. 

Ready to move from AI potential to performance? Let’s talk about how we can accelerate your roadmap with the right talent, tools, and strategy. Contact us to get started. 

]]>
https://blogs.perficient.com/2025/07/31/ai-in-medical-device-software-development-lifecycle/feed/ 0 385582
Creating a Brand Kit in Stream: Why It Matters and How It helps Organizations https://blogs.perficient.com/2025/07/15/brandkit-sitecore-stream/ https://blogs.perficient.com/2025/07/15/brandkit-sitecore-stream/#respond Tue, 15 Jul 2025 09:24:10 +0000 https://blogs.perficient.com/?p=384493

In today’s digital-first world, brand consistency is more than a visual guideline, it’s a strategic asset. As teams scale and content demands grow, having a centralized Brand Kit becomes essential. If you’re using Sitecore Stream, building a Brand Kit is not just useful, it’s transformational.

In my previous post, I tried to explore Sitecore Stream, highlighting how it reimagines modern marketing by bringing together copilots, agentic AI, and real-time brand intelligence to supercharge content operations. We explored how Stream doesn’t just assist it acts with purpose, context, and alignment to your brand.

Now, we take a deeper dive into one of the most foundational elements that makes that possible: Brand Kit.

In this post, we’ll cover:

  • What a Brand Kit is inside Stream, and why it matters
  • How to build one – from brand documents to structured sections
  • How AI copilots use it to drive consistent, on-brand content creation

Let’s get into how your brand knowledge can become your brand’s superpower.

 

What Is a Brand Kit?

A Brand Kit is a centralized collection of brand-defining assets, guidelines, tone, messaging rules.

Brand kit sections represent a subset of your brand knowledge.
It includes information about your brands like:

  • Logo files and usage rules
  • Typography and color palettes
  • Brand voice and tone guidelines
  • Brand specific imagery or templates
  • Do’s and Don’ts of brand usage
  • Compliance or legal notes

Think of it as your brand’s source of truth, accessible by all stakeholders – designers, marketers, writers, developers, and AI assistants.

 

Why Stream Needs a Brand Kit

Stream is a platform where content flows – from ideas to execution. Without a Brand Kit:

  • Writers may use inconsistent tone or terminology as per their knowledge or considerations about brand.
  • Designers may reinvent the wheel with each new visual.
  • Copilots might generate off-brand content.
  • Cross-functional teams lose time clarifying brand basics.

With a Brand Kit in place, Stream becomes smarter, faster, and more aligned with your organization’s identity.

 

How a Brand Kit Helps the Organization

Here’s how Stream and your Brand Kit work together to elevate content workflows:

  •  Faster onboarding: New team members instantly understand brand expectations.
  •  Accurate content creation: Content writers, designers, and strategists reference guidelines directly from the platform.
  •  AI-assisted content stays on-brand: Stream uses your brand data to personalize AI responses for content creation and editing.
  •  Content reuse and updates become seamless with analysis: Brand messaging is consistent across landing pages, emails, and campaigns. You can also perform A/B testing with brandkit generated content vs manually added content.

Now that we understand what a Brand Kit is and why it’s essential, let’s walk through how to create one effectively within Sitecore Stream.

 

Uploading Brand Documents = Creating Brand Knowledge

To create a Brand Kit, you begin by uploading and organizing your brand data this includes documents, guidelines, assets, and other foundational materials that define your brand identity.

Below screenshot displays the screen of uploaded brand document, button to process the document and an option to upload another document.

Upload Doc

 

In Stream, when you upload brand-specific documents, they don’t just sit there. The process:

  • Analyses the data
  • Transforms them into AI-usable data by Creating brand knowledge
  • Makes this knowledge accessible across brainstorming, content creation, and AI prompts

Process

In short, Here’s how the process works:

  • Create a Brand Kit – Start with a blank template containing key sections like Brand Context, Tone of Voice, and Global Goals.
  • Upload Brand Documents – Add materials like brand books, visual and style guides to serve as the source of your brand knowledge.
  • Process Content – Click Process changes to begin ingestion. Stream analyzes the documents, breaks them into knowledge chunks, and stores them.
  • Auto-Fill Sections – Stream uses built-in AI prompts to populate each section with relevant content from your documents.

 

Brand Kit Sections: Structured for Versatility

Once your Brand Kit is created and the uploaded documents are processed, Stream automatically generates key sections. Each section serves a specific purpose and is built from well-structured content extracted from your brand documents. These are essentially organized chunks of brand knowledge, formatted for easy use across your content workflows. Default sections that gets created are as follows:

  • Global Goals – Your brand’s core mission and values.
  • Brand Context – Purpose, positioning, and brand values.
  • Dos and Don’ts – Content rules to stay on-brand.
  • Tone of Voice – Defines your brand’s personality.
  • Checklist – Quick reference for brand alignment.
  • Grammar Guidelines – Writing style and tone rules.
  • Visual Guidelines – Imagery, icons, and layout specs.
  • Image Style – Color, emotion, and visual feel.

Each section holds detailed, structured brand information that can be updated manually or enriched using your existing brand knowledge. If you prefer to control the content manually and prevent it from being overwritten during document processing, you can mark the section as Non-AI Editable.

Stream allows you to add new subsections or customize existing ones to adapt to your evolving brand needs. For example, you might add a “Localization Rules” section when expanding to global markets, or a “Crisis Communication” section to support PR strategies.

When creating a new subsection, you’ll provide a name and an intent a background prompt that guides the AI to extract relevant information from your uploaded brand documents to populate the section accurately.

Below screenshot of sections created after brand document process and subsections for example:

Brand Kit Sections

Section Details

AI + Brand Kit = Smarter Content, Automatically

Now we have created brand kit, lets see how AI in Stream uses your Brand Kit to:

Suggest on-brand headlines or social posts

  • Flag content that strays from brand guidelines
  • Assist in repurposing older content using updated brand tone

It’s like having a brand-savvy assistant embedded in your workflow.

 

Brand assist in Sitecore Stream

Once you have Brand Kit ready, you can use the Brand Assistant to generate and manage content aligned with your brand using simple prompts.

Key uses:

  • Ask brand-related questions
  • Access brand guidelines
  • Generate on-brand content
  • Draft briefs and long-form content
  • Explore ideas and marketing insights

It uses agentic AI, with specialized agents that ensure every output reflects your brand accurately.

When a user enters a prompt in the Brand Assistant, whether it’s a question or an instruction the copilots automatically includes information from the Brand Context section of the Brand Kit. It then evaluates whether this context alone is enough to generate a response. If it is, a direct reply is provided. If not, specialized AI agents are activated to gather and organize additional information.

These include a Search Agent (to pull data from brand knowledge or the web), a Brief Agent (for campaign or creative brief requests), and a Summary Agent (to condense information into a clear, relevant response).

I clicked on Brand Assistant tab, selected my Brand Kit, asked a question, and the response I got was spot on! It perfectly aligned with the brand documents I had uploaded and even suggested target consumer based on that information. Super impressed with how well it worked!

Brandkit Selection In Assist

Brainstorm

 

Now it’s time to see how the Brand Kit helps me generate content on XM Cloud or Experience Platform. To do that, connect XM Cloud website with Sitecore Stream so the copilots can access the Brand Kit.

I simply went to Site Settings, found the Stream section, selected my Stream instance and that’s it. I was all set to use brandkit.

Brandkit Setting In Site

Now, when I open the page editor and click on Optimize, I see an additional option with my Brand Kit name. Once selected, I can either draft new text or optimize existing content.

The copilot leverages the Brand Kit sections to generate content that’s consistent, aligned with our brand voice, and ready to use.

For example, I asked the brand kit to suggest campaign content ideas and it provided exactly the kind of guidance I needed.

Campaign Page

 

Conclusion

Building and maintaining a Brand Kit in Stream isn’t just about visual consistency, it’s about scaling brand intelligence across the entire content lifecycle. When your Brand Kit is connected to the tools where work happens, everyone from AI to human collaborators works with the same understanding of what your brand stands for.

]]>
https://blogs.perficient.com/2025/07/15/brandkit-sitecore-stream/feed/ 0 384493
Importance of Performance Adaptation in Frontend Development https://blogs.perficient.com/2025/06/20/importance-of-performance-adaptation-in-frontend-development/ https://blogs.perficient.com/2025/06/20/importance-of-performance-adaptation-in-frontend-development/#respond Fri, 20 Jun 2025 08:09:38 +0000 https://blogs.perficient.com/?p=383195

In today’s fast-paced digital world, users expect websites and applications to load quickly and run smoothly. Performance optimization in Frontend Development is not just a technical requirement – it is an important factor that can create or break user experience, engagement and conversion. If you are a developer, designer, or product owner, then here is why the front performance should be at the top of your priority list – and how you can start improving it now.

 

Why performance matters

1. User Experience – First Impression Matter

A well-optimized website attracts and retains users, while a poorly performing one pushes them away.

Over half of people using their phones will leave a website if it takes more than 3 seconds to load. If your site is slow, they might never even see what you’re offering before they leave.

2. SEO Benefits

A well optimized website isn’t just good for your users — it’s great for search engine optimization (SEO). Businesses that ignore performance risk losing visitors and rankings.

Better performance = better SEO = more visibility and traffic.

3. Conversion rate – speed = more revenue

Performance has a direct impact on conversion and revenue. Even a one-second delay in page load time can reduce conversions by up to 7%. Fast sites accelerate sales and make customers happy.

4. Mobile Optimization

Reach every user with mobile devices dominating web traffic, performance on mobile is important. Mobile networks can be slow and less reliable, which makes it necessary to ensure that your site performs well everywhere from high end desktop to low end smartphones. If your site is not adapted to mobile, then you are losing users for those competitors.

 

Key Areas for Performance Optimization
Now that we know why performance matters, let’s talk about how to achieve it — without overcomplicating things.

1. Minimize HTTP Requests

Every image, script, and stylesheet make an HTTP request. The fewer requests, the faster your page loads.

Tips: Combine files: Merge CSS and JavaScript files.

2. Optimize and Compress Images
Images are often the heaviest part of a webpage.
Tips:
• Use modern formats like WebP or AVIF.
• Compress images with tools like TinyPNG or ImageOptim.
• Lazy-load images to load them only when needed.

3. Leverage Browser Caching

Enable caching so browsers store static files like images, CSS, and JS locally, reducing server load on repeat visits.
Set proper cache headers to make the most of this technique.

4. Minify CSS and JavaScript

Minification removes unnecessary characters (spaces, comments) from your code, reducing file size and improving load time.

 

  • Why Minify CSS?

Improved Page Loading Speeds

Because minified CSS reduces file size, browsers can render pages faster, especially on slow connections, and download stylesheets more quickly.

  • Improved Performance in Rendering

Faster style parsing and application results from smaller CSS files, which raises First Contentful Paint (FCP) and Largest Contentful Paint (LCP) scores—two important metrics in Core Web Vitals.

  • Decreased Bandwidth Utilization

Minified CSS lowers the amount of data sent over the network, which is particularly helpful for mobile users or those with limited data plans.

  • Enhanced Effectiveness of Caching

Because minified files are frequently bundled, fewer HTTP requests are made, and browser caching is better utilized.

  • Why Minify JavaScript?

The number of bytes sent to the browser is decreased by minified JS files, which is particularly important for low-power or mobile device performance.

  • Decreased Rendering Blocking

JavaScript has the ability to prevent HTML rendering and parsing. By reducing the blocking time, minification enhances visual speed metrics such as First Input Delay (FID).

  • Improved Delivery Efficiency

Minification significantly reduces the size of JS payloads when used in conjunction with gzip compression, which speeds up network delivery.

5.  Optimize JavaScript Execution

Heavy JavaScript can block rendering and hurt performance.
Tips:
• Defer or async-load non-essential scripts.
• Code splitting: Break large JavaScript files into smaller chunks and load them as needed.
• Minimize use of third-party scripts and libraries.

6.  Monitor and Measure Performance

You can’t improve what you don’t measure.
Tools to monitor and audit your site:
• Google Lighthouse
• PageSpeed Insights
• WebPageTest
• Chrome DevTools
• Real User Monitoring (RUM) tools like New Relic or Datadog
Regularly review these metrics to catch issues before users do.

7. Use Placeholder UI (Skeleton Components)

For Example – Use skeleton component. It provides a visual representation of the layout and structure of the content that will eventually be displayed, helping to improve the user experience during loading times.

To learn more about Skeleton components, check my previous blog where I have explained its features and usage.

https://blogs.perficient.com/2023/12/13/understanding-skeleton-component-in-react/

https://blogs.perficient.com/2023/12/13/implementing-skeleton-components-in-react/

 

What Happens If You Ignore Performance?

Let’s be real — ignoring performance optimization has consequences:
• Slow loading makes users bounce before they engage.
• Laggy interactions frustrate users and break trust.
• Layout shifts (CLS) create poor experiences, causing accidental clicks.
• Accessibility issues lock out users on slower devices or weak connections.
In short, bad performance equals lost users and lost revenue.

Final Thoughts

Performance optimization is about more than just speed — it’s about creating a smooth, inclusive, and engaging experience for every user.
If you want people to love your product, share it, and come back, performance has to be a top priority — from the start.

“A great user experience starts with great performance.”

]]>
https://blogs.perficient.com/2025/06/20/importance-of-performance-adaptation-in-frontend-development/feed/ 0 383195