Sitecore Articles / Blogs / Perficient https://blogs.perficient.com/category/partners/sitecore/ Expert Digital Insights Tue, 15 Jul 2025 10:07:18 +0000 en-US hourly 1 https://blogs.perficient.com/files/favicon-194x194-1-150x150.png Sitecore Articles / Blogs / Perficient https://blogs.perficient.com/category/partners/sitecore/ 32 32 30508587 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
From Next.js to React (and Back): Navigating Sitecore JSS SDKs the Right Way https://blogs.perficient.com/2025/06/30/from-next-js-to-react-and-back-navigating-sitecore-jss-sdks-the-right-way/ https://blogs.perficient.com/2025/06/30/from-next-js-to-react-and-back-navigating-sitecore-jss-sdks-the-right-way/#comments Mon, 30 Jun 2025 18:29:33 +0000 https://blogs.perficient.com/?p=383723

When I first started working on Sitecore XM Cloud and headless Sitecore projects, it was always Next.js. It felt like the default choice – and honestly, for a good reason. But over the past year, I’ve have seen and worked on projects that have their JSS apps in React – the standalone version, without Next.js.

This got me curious. Why React? What’s missing when we move away from Next.js? And most importantly – what should we choose when starting a new Sitecore project?

This post breaks down everything I uncovered while switching between the React and Next.js JSS SDKs – from core concepts to Sitecore-specific implementation differences. If you’re gearing up for a new Sitecore XM Cloud build or architecting a headless Sitecore app, this will help you make informed technical decisions.

 React vs Next.js – A Quick Overview

Before we compare the Sitecore JSS SDKs, it helps to understand the difference between React and Next.js, since these form the foundation for the SDKs.

React

React is a JavaScript library for building interactive user interfaces, primarily using a component-based approach.

It handles the view layer only and leaves routing, SSR, and other features up to you.

  • Created by Facebook
  • Ideal for Single Page Applications (SPAs)
  • Works entirely on the client side by default
  • Needs manual setup for routing, SSR, etc.

In short, React is flexible, but requires more manual effort.

Next.js

Next.js is a React framework that extends React by adding routing, server-side rendering, static generation, and much more – right out of the box.

  • Created by Vercel
  • Supports both SSR and SSG
  • Offers file-based routing and API routes
  • Optimized for SEO and performance
  • Often used for JAMstack or hybrid sites

In short, Next.js is React with superpowers – especially useful for performance and SEO.

React vs Next.js – Core Differences

FeatureReactNext.js
TypeLibraryFramework
RoutingManual (react-router-dom)Built-in file-based
RenderingCSR onlyCSR, SSR, SSG, ISR
SEOManual setupBuilt-in support
Image OptimizationManualBuilt-in (next/image)
API RoutesNot availableAvailable (/pages/api/)
Developer ControlHighBalanced

Sitecore JSS SDKs – What Are Your Options?

Sitecore’s JSS (JavaScript Services) offering is what enables developers to build fully headless front-end applications that communicate with Sitecore via APIs, mainly the Layout Service. JSS supports multiple front-end frameworks  – but they’re not all on equal footing when it comes to features, support, or long-term viability.

Let’s walk through each major option available, with a special focus on their corresponding packages and real-world suitability.

Supported frameworks:

  • React
  • Next.js
  • Angular (legacy support)
  • Vue.js (legacy support)

Next.js SDK for Sitecore

Package: @sitecore-jss/sitecore-jss-nextjs

This is Sitecore’s officially recommended SDK for building headless applications – especially when you’re working with Sitecore XM Cloud or public-facing websites that need server-side rendering, SEO, or personalization.

It’s built specifically to work with the Next.js framework and tightly integrates with its rendering strategies like SSR, SSG, and ISR.

Key Features:

  • Built-in support for Server-Side Rendering (SSR) and Static Site Generation (SSG)
  • Native integration with Experience Editor and Preview Mode
  • Works seamlessly with personalization, multilingual/multisite setups, and Experience Edge
  • Uses file-based routing, so Sitecore routes map easily to Next.js pages
  • Excellent performance with ISR (Incremental Static Regeneration) to update static content on demand
  • Supports middleware, API routes, and hybrid rendering patterns out-of-the-box

Ideal for: Content-heavy websites, SEO-focused applications, XM Cloud implementations, and teams that need a balance between performance and editorial flexibility.

React SDK for Sitecore

Package: @sitecore-jss/sitecore-jss-react

This SDK enables you to build headless Sitecore applications using React – without the Next.js framework. It’s typically used with Create React App (CRA), Vite, or any custom React setup.

Unlike the Next.js SDK, this one is designed for client-side rendering (CSR) only. That means you won’t get built-in SSR or SSG unless you integrate additional tools or custom server-side rendering mechanisms.

Key Features:

  • Pure React support with no dependency on a specific build tool
  • Manual routing setup using react-router-dom or other libraries
  • Layout data must be fetched manually using hooks like useEffect
  • You handle loading states, errors, and transitions manually
  • Limited or workaround-based support for Experience Editor and preview functionality
  • Still works well with Sitecore’s Layout Service, component factory, and placeholders

Ideal for: SPAs, internal tools, admin dashboards, or lightweight projects where SEO and editing support aren’t top priorities.

 While you can get the job done with this SDK, it requires significantly more boilerplate and configuration compared to Next.js –  especially for features like personalization, preview, or SSR.

Angular SDK for Sitecore

Package:  @sitecore-jss/sitecore-jss-angular

The Angular SDK allows you to build Sitecore headless applications using Angular. While it still technically works, it’s no longer getting as much attention from Sitecore. Most of the ecosystem and tutorials are focused on React and Next.js.

Key Features:

  • Angular support with Sitecore’s Layout Service integration
  • Requires more setup to enable routing and layout rendering
  • Experience Editor support is possible but less stable than React/Next.js
  • Documentation and examples are limited or outdated

Ideal for: Teams heavily invested in Angular with a legacy project that needs to interface with Sitecore in a headless manner. Not recommended for new XM Cloud projects due to limited support and community activity.

Vue SDK for Sitecore

Package: @sitecore-jss/sitecore-jss-vue

Like the Angular SDK, the Vue SDK was created to allow Vue.js developers to build JSS-based front-end apps for Sitecore. However, this SDK is largely legacy and isn’t actively maintained for new capabilities or integrations like personalization or Experience Edge.

Key Features:

  • Vue-based rendering of Sitecore Layout Service JSON
  • Basic placeholder and component support
  • Routing and SSR require additional setup
  • Experience Editor integration is limited and clunky

Ideal for: Experimental or legacy Vue-based front ends. Avoid using for XM Cloud or future-facing Sitecore work.

React Native SDK for Sitecore

Package:  @sitecore-jss/sitecore-jss-react-native

This experimental SDK is meant to enable mobile applications built in React Native to consume Sitecore layout and content via the Layout Service. While an exciting idea, this SDK is not production-ready and lacks many features you’d expect in a full headless implementation.

Key Features:

  • Allows mobile apps to render Sitecore content using components mapped from layout JSON
  • No official Experience Editor or personalization support
  • Minimal documentation and sample apps
  • Not tested against XM Cloud

Ideal for: Prototyping or experimental mobile projects. Not suitable for stable production use.

Next.js vs React SDK: A Comparison

Here’s how the two officially supported Sitecore JSS SDKs stack

FeatureReact JSS SDKNext.js JSS SDK
Rendering SupportCSR onlyCSR, SSR, SSG, ISR
RoutingManual via react-router-domFile-based routing
SEONeeds manual setupBuilt-in
Layout FetchingClient-side with useEffectIn getStaticProps / getServerSideProps
Experience EditorLimitedFully supported
Preview ModeCustom setupOut-of-the-box
PersonalizationPartialFull support
PerformanceLightweight SPAOptimized with ISR/SSG
HostingStatic (Netlify, Vercel, Azure Blob)SSR-capable platforms (Vercel, Azure App Service)

 Final Thoughts

When I first started working with Sitecore headless projects, I’ll admit – I thought Next.js was the only way. It had everything: built-in routing, SSR, Experience Editor support — and it just worked with XM Cloud.

But over time, as I got to work with the React JSS SDK, I realized it brings its own set of strengths. It gives you more control, fewer constraints, and is actually a great fit for lightweight apps, internal tools, or scenarios where SSR isn’t a must-have.

That said, if you’re building a full-blown customer-facing site with personalization, multilingual support, and editorial workflows – Next.js is still the best fit.

So no, it’s not about which one is better. It’s about picking what’s right for your project goals, team setup, and future roadmap. Both SDKs have their place – and knowing when to use what is where the real engineering choice lies.

]]>
https://blogs.perficient.com/2025/06/30/from-next-js-to-react-and-back-navigating-sitecore-jss-sdks-the-right-way/feed/ 1 383723
Martech is Exploding – Where Does Sitecore Fit In? https://blogs.perficient.com/2025/06/20/martech-is-exploding-where-does-sitecore-fit-in/ https://blogs.perficient.com/2025/06/20/martech-is-exploding-where-does-sitecore-fit-in/#respond Fri, 20 Jun 2025 19:08:18 +0000 https://blogs.perficient.com/?p=380476

I remember using a slide in a presentation around a Sitecore implementation I was working on ~7 years ago. It showed something to the effect of the Martech ecosystem 10 years prior to this and how much it had exploded during that time frame (so basically highlighting the growth in Martech between ~2008-2018). Fast forward to 2025 and that same slide would likely need a whole deck worth of slides to cover the exponential expansion in the market since then. Needless to say, if you need something done, there is a Martech platform or AI tool for it. SO, where is Sitecore as relevant as ever in this crazy world of Martech today, and how can it help drive your organization’s digital experience forward?

Here are the six key areas Sitecore products excel in and how they are leading the way regarding building digital experiences of the future.

Content Management (CMS)

Arguably the bread and butter of the Sitecore offering, and the capability that allowed the platform to grow into what it is today, Sitecore remains a leader in all things content management. With XM Cloud, Sitecore takes this one step further, allowing marketers to drive more of the experience creation through page builder and component building. Ultimately this allows marketing teams to bring content to market faster and at scale.

AI-powered Search

Tools like ChatGPT, Claude, Gemini and Copilot are changing the way users search for and consume content. Nothing is set in stone yet, but some industry experts are beginning to circulate the idea that in the not-so-distant future site search functionality will outright replace traditional website navigation menus as a user’s preference for how to get to the content they need. Enter: Sitecore Search. Sitecore Search operates on sophisticated artificial intelligence (AI) and machine learning (ML) algorithms that factor in location, user preferences, interaction and purchase history to populate intent-driven and personalized search results in real time.

E-Commerce

Does your brand sell goods and/or services from digital storefront? While Sitecore’s OrderCloud solution offers a wide range of technical benefits, it also offers a lot to marketers as well. OrderCloud helps marketers to build commerce experiences once and deploy them in omnichannel fashion without hindering the experience for customers. It also implements seamlessly with other Sitecore products but also with third party platforms. Lastly, it allows for tiered pricing strategies, personalized offer bundles and loyalty incentives to be offered.

AI-enabled Workflow Management

What is every marketer’s favorite activity? If you said writing a creative brief, you might be the only one. If you’re like me and wish you had a filter that could help you make sure any new piece of content aligns with brand guidelines and tone, you’re in luck, because Sitecore Stream was launched at Symposium in 2024. With brand-aware AI that learns your brand inside and out based on brand documentation that you upload, and agentic AI workflows that help with everything from content and campaign ideation to accelerating production workflows. You can also keep your legal team sleeping at night knowing that the data you upload to Sitecore Stream is never used to train the LLM’s that Stream runs on and that content is only generated through Retrieval-augmented generation. This means that the only information you will get is directly being populated from the data that you upload.

Customer Data Management & Personalization

Today, more than ever, customers are coming to expect experiences that are unique to their interests and needs. Customer Data Management at a very high level is the concept of collecting, organizing and applying data from various touchpoints of a customer journey in an effort to build meaningful experiences for customers in the digital and physical realm. Sitecore’s CDP offering is able to unify customer data in real-time and leverages AI to deliver personalized experiences at scale. With the ability to apply segmentation, experimentation, and ultimately personalization, Sitecore enables marketers and business users orchestrate customer journeys that are impactful.

Digital Asset Management

The art of content operations goes so much further than simply managing a database of images and visual assets, but at the heart of it all is a digital asset management (DAM) platform. Beyond having a DAM in place, modern marketing teams need to truly embrace thoughtfully and strategically planning content workflows. This includes identifying different roles within the team, orchestrating distribution of content so that one piece of content can be used in meaningful ways across multiple channels, review processes and more. Sitecore Content Hub connects DAM with Content Marketing Platform (CMP), Product Content Management (PCM) all under one roof. This enables content and marketing teams to create meaningful content, review and adjust, scale for omnichannel delivery and distribute across multiple platforms. It incorporates the ability to version control and ensure usage rights management along the way as well.

Conclusion

In a world where the options are seemingly endless, look no further than Sitecore for a large portion of your digital experience stack. Looking to BYOT (Bring Your Own Tools)? Sitecore’s flexibility allows for plug and play options at every step as well. Looking for help building out digital experiences that wow customers and drive revenue? Reach out to the team at Perficient.

]]>
https://blogs.perficient.com/2025/06/20/martech-is-exploding-where-does-sitecore-fit-in/feed/ 0 380476
Why AI-Led Experiences Are the Future — And How Sitecore Stream Delivers Them https://blogs.perficient.com/2025/06/12/why-ai-led-experiences-are-the-future-and-how-sitecore-stream-delivers-them/ https://blogs.perficient.com/2025/06/12/why-ai-led-experiences-are-the-future-and-how-sitecore-stream-delivers-them/#respond Thu, 12 Jun 2025 11:08:30 +0000 https://blogs.perficient.com/?p=382748

In a world that’s moving at lightning speed, customers expect brands to keep up — to understand them instantly, respond to their behavior in real-time, and offer relevant, helpful experiences wherever they are. This is where Artificial Intelligence (AI) has become not just useful, but absolutely essential.

The Growing Power of AI in Today’s World

AI is revolutionizing how businesses operate and how brands engage with customers. What started as automation is now intelligent orchestration:

  • Recommending the right product at the right time
  • Automatically generating content in your brand voice
  • Detecting patterns in real-time behavior
  • Personalizing experiences across every channel

From e-commerce to healthcare, entertainment to education, AI is making every industry smarter, faster, and more responsive. And customer expectations are rising accordingly.

Why Sitecore Has Embraced AI

As a leader in digital experience platforms, Sitecore understands that personalization, content delivery, and customer journey orchestration can’t rely on manual processes.

That’s why Sitecore has integrated AI deeply into its product ecosystem — not just to enhance content workflows, but to transform how real-time experiences are built and delivered.

At the heart of this transformation is Sitecore Stream.

Introducing Sitecore Stream

Sitecore Stream introduces AI capabilities to Sitecore products, specifically tailored for marketers. It empowers smarter, faster end-to-end content creation and distribution at scale, unlocking remarkable efficiency gains. Featuring brand-aware AI, intelligent copilots, autonomous agents, and streamlined agentic workflows, Sitecore Stream transforms marketing effectiveness by helping you speed up time-to-market, lower costs, and deliver compelling, consistent digital experiences across all channels.

But Sitecore Stream doesn’t just work fast — it works intelligently and brand-safely.

Sitecore Stream automates all tasks and deliverables in a marketing workflow, utilizing AI to make them faster, easier, and more consistent. Through copilots, agents, content ideation and creation, and then optimizing the customer experience.

Stream is built on the Microsoft Azure OpenAI Service, utilizing advanced large language model (LLM) technology to help teams of all sizes ideate, create, and refine on-brand content more strategically and securely.

What is an LLM?

A large language model (LLM) is a type of machine learning model designed for natural language processing tasks such as language generation. LLMs are language models with many parameters and are trained with self-supervised learning on a vast amount of text.

Large Language Models (LLMs) are a cornerstone of generative AI, powering a wide array of natural language processing tasks, including:

  • Searching, translating, and summarizing text
  • Answering questions with contextual understanding
  • Creating new content—ranging from written text and images to music and software code

What truly sets LLMs apart is their ability to synthesize information, analyze complex data, and identify patterns and trends. This enables them to go beyond simple text generation and adapt seamlessly to diverse, specialized use cases across industries

Core Concepts & Capabilities of Sitecore Stream

Sitecore Stream transforms your marketing stack by combining:

  • Brand intelligence
  • AI automation
  • Real-time decisioning

It’s designed to help marketers do more, faster, with less manual effort—while maintaining creative control and brand integrity. Let’s look at how Sitecore Stream makes it possible with the following capabilities:

  1. Brand-Aware AI

Unlike generic AI tools, Stream uses RAG to anchor every response in the organization’s brand knowledge.

Retrieval-augmented generation (RAG) grounds AI outputs by pulling brand-specific information directly from documents uploaded by the organization. This ensures that content generation is informed by accurate, contextual brand knowledge.

Brand-aware AI is an advanced capability designed to maintain brand consistency across all Sitecore products. It leverages large language models (LLMs) and retrieves relevant information from brand resources to ensure alignment with the brand’s identity.

When brand documents are uploaded—detailing brand values, messaging, tone, visual identity, and the intended customer experience—brand knowledge is created through a process known as brand ingestion. This process organizes and optimizes the uploaded information, making it readily accessible to AI copilots across the platform.

As a result, AI-powered tools within Sitecore Stream consistently generate or suggest content that reflects the brand’s voice, tone, and guidelines. This enables marketers to scale content creation confidently, knowing all output remains true to the brand.

  1. Copilots and Agents

Stream introduces AI copilots that assist marketers in real-time, offering intelligent suggestions for content, layout, targeting, and workflows. Agents go further, autonomously executing tasks like campaign personalization, journey orchestration, or data segmentation.

Copilots provide intelligent guidance to support strategic decisions, while agents handle routine actions autonomously, freeing marketers to focus on high-value strategy and creative execution.

Both copilots and agents understand natural language and predefined prompts, seamlessly assisting throughout the content creation process and minimizing repetitive work. Marketers can effortlessly request content drafts, campaign ideas, or personalized experiences, all with simple, intuitive commands.

Fully integrated into Sitecore products, these tools deliver chat-based interactions, one-click workflows, and autonomous operations, making marketing smarter, faster, and more efficient.

Sitecore Stream currently offers 3 copilots

  • Brand Copilot – Helps marketers create content that matches the brand using tools for brand-aware chat, idea generation, and content briefs.
  • Content Copilot – Supports content tasks like writing, refining, translating, generating content with AI in Experience Platform, and optimizing/personalizing content in Sitecore.
  • Experience Copilot – Improves search with features like visual search in Content Hub and Q&A generation in Sitecore Search.
  1. Agentic Workflows

What is Agentic AI?

Agentic AI refers to artificial intelligence systems that can act autonomously, pursue goals, and make decisions proactively, almost like an “agent” with a mission.

In simple terms:

Agentic AI is AI that doesn’t just respond to commands—it plans, decides, and takes initiative to achieve a goal on its own. AI that doesn’t just assist—it acts.

Stream enables agentic workflows, where AI agents execute actions (e.g., publish content, trigger campaigns) based on real-time customer behavior or campaign goals.

Successful project management starts with a clear, organized plan that prioritizes tasks and involves the right team members at the right time. By setting defined goals, monitoring progress, and fostering collaboration, teams can ensure projects stay aligned and deliver desired outcomes.

Sitecore Stream’s orchestration capability takes project management to the next level by integrating AI-driven automation tailored for marketing teams. Whether managing campaigns, product launches, or digital advertising strategies, this feature helps coordinate efforts seamlessly across teams and Sitecore products.

By introducing early-stage AI agents, orchestration supports smarter task execution and informed decision-making. This paves the way for advanced agentic workflows within Sitecore, where AI systems can autonomously drive actions, make decisions, and dynamically respond to evolving project demands.

Conclusion

AI is no longer a future investment — it’s a present necessity. Customers demand relevance, speed, and brand coherence. Sitecore Stream is Sitecore’s answer to that demand: A real-time, AI-powered platform that combines behavioral insight, brand knowledge, and automation to help brands engage customers intelligently and instantly.

This is the future of digital experience. And with Sitecore Stream, it’s already here.

]]>
https://blogs.perficient.com/2025/06/12/why-ai-led-experiences-are-the-future-and-how-sitecore-stream-delivers-them/feed/ 0 382748
How to Optimize Sitecore Headless and Next.js on Vercel https://blogs.perficient.com/2025/05/22/how-to-optimize-sitecore-headless-and-next-js-on-vercel/ https://blogs.perficient.com/2025/05/22/how-to-optimize-sitecore-headless-and-next-js-on-vercel/#respond Thu, 22 May 2025 16:47:13 +0000 https://blogs.perficient.com/?p=381796

Maybe you’ve already made the switch to XM Cloud, or maybe you’re still evaluating it as the answer to all your digital delivery challenges. Spoiler alert: it won’t magically solve everything — but with the right setup and smart optimizations, it can absolutely deliver fast, scalable, and maintainable experiences.

If you’re using Sitecore Headless with Next.js, you’re already building on a modern and flexible foundation. Add in a deployment platform like Vercel, and you’ve got serious power at your fingertips. But unlocking that potential requires knowing where to fine-tune — both at the application and platform level.

Streamline Your Layout and API Payloads

The Sitecore Layout Service is versatile but can return bulky JSON payloads if left unchecked. Clean up your responses by:

  • Removing unused placeholders and renderings

  • Filtering out internal tracking or analytics fields unless explicitly needed

  • Configuring the Layout Service to tailor the response to your frontend needs

If you’re using Sitecore Search or XM Cloud with GraphQL, concise queries will help keep your pages fast and predictable

  • Request only the fields you need

  • Use first: or limit: to control result size
  • Organize queries into reusable fragments for maintainability and performance

Smaller payloads result in faster hydration, quicker time-to-interactive, and lower bandwidth usage — all especially valuable for mobile-heavy audiences.

Use Webhooks for Smarter Publishing (On-demand Revalidation or ODR)

Don’t rely on manual rebuilds or blanket cache clears. XM Cloud supports webhooks on publish, which opens the door to smarter automation:

  • Trigger on-demand ISR revalidation for updated pages

  • Push new content to Edge Config, CDNs, or search indexes

  • Notify external systems (e.g., analytics, commerce, personalization) immediately

It’s the best way to keep content fresh without sacrificing performance or rebuilding the entire site.

Choose the Right Rendering Method: SSR, SSG, or ISR?

Not every page needs to be dynamic, and not every page should be static. Picking the right rendering strategy is critical — especially in a Sitecore headless app where you’re mixing marketing content with personalization and real-time updates.

Here’s how to decide:

Use SSR (Server-Side Rendering) when:

  • The page depends on the user session or request (e.g., personalization, authenticated pages)

  • You’re rendering in preview mode for content authors

Use SSG (Static Site Generation) when:

  • The content rarely changes (e.g., static landing pages or campaigns)

  • You want instant load times and no server cost

Use ISR (Incremental Static Regeneration) when:

  • Content changes periodically, but not per-request

  • You want to combine the speed of static with the freshness of dynamic

Use next/link with Prefetching

If you’re still using regular <a> tags or not thinking about navigation performance, this one’s for you. The next/link component enables fast, client-side routing and automatic prefetching of pages in the background.

Example:

import Link from 'next/link';

<Link href="/products" prefetch={true}>About Us</Link>
  • Use it for all internal links

  • Set prefetch={true} on high-priority routes

  • Check behavior in your browser’s network tab — look for .json page data being fetched in advance

This alone can make your site feel instantly faster to users.

Optimize Fonts with next/font

Sitecore headless apps don’t include next/font by default, but it’s worth integrating. It allows you to self-host fonts in a performance-optimized way and avoid layout shifts.

Example:

import { Inter } from 'next/font/google';

const inter = Inter({ subsets: ['latin'] });

Apply fonts globally or per-page to improve loading consistency and avoid FOUT (Flash of Unstyled Text). Better fonts = better user experience.

Clean Up Your Codebase

Performance isn’t just about server-side logic — it’s also about keeping your codebase lean and clean.

What to review:

  • Old personalization plugins that are no longer used

  • Middleware that’s too permissive or generic in its matching

  • Outdated multisite logic if you’ve already split into multiple Vercel projects

  • Unused components or fetch logic in shared utilities

Use Vercel performance insights to track slow routes and spot cold starts.

Enable Fluid Compute

Fluid Compute lets Vercel reuse idle time across your serverless functions. That means better performance and lower costs — without any code changes.

To enable it:

  • Go to your Vercel project settings

  • Navigate to Functions

  • Toggle Fluid Compute on

You can monitor the impact under Observability → Logs in your dashboard. It’s a low-effort win. Read more details about Fluid Compute in my previous blog!

Be Selective with Middleware

Next.js middleware is powerful but potentially expensive in performance terms. Use it wisely:

  • Limit middleware to only essential routes

  • Avoid using fetch() inside middleware — use Edge Config instead

  • Replace multisite plugins with separate Vercel projects

  • Audit unused or legacy logic, especially leftover personalization

Track middleware behavior through the Middleware tab in Vercel Logs.

Manage Redirects with Edge Config

For the fastest possible redirects, manage them directly in Vercel using Edge Config. This keeps Sitecore out of the request path and ensures instant resolution at the edge.

  • Store all redirect data in Edge Config
  • Deploy updates as part of your app or via external config tools
  • Avoid real-time fetches from Sitecore for redirect logic

If you’re managing a large volume of redirects, consider using a bloom filter to optimize memory usage. Just note that bloom filters introduce a small delay due to redirect verification.

Conclusion

Optimizing a Sitecore Headless application, especially one deployed on Vercel, is about making dozens of small, smart decisions that add up to big wins in performance, scalability, and developer happiness. Whether it’s pruning your Layout Service output or toggling a setting in your Vercel dashboard, each move brings you closer to a faster, more responsive site.

XM Cloud doesn’t come pre-optimized — but that’s actually a good thing. It gives you the power and flexibility to build the way you want. Just make sure you’re building it right.

Optimization Checklist

Sitecore & XM Cloud

  • Prune Layout Service JSON (remove unused placeholders and fields)

  • Use GraphQL efficiently (limit queries, use fragments)

  • Set up publish webhooks for on-demand rendering or cache purging

Rendering Strategy

  • Use SSR for personalized/authenticated content

  • Use SSG for static pages

  • Use ISR for hybrid performance/freshness

Next.js

  • Replace <a> with next/link and enable prefetching

  • Add next/font for consistent and fast font rendering

Vercel

  • Enable Fluid Compute for better serverless efficiency

  • Use middleware only where necessary and avoid fetch inside

  • Use Edge Config for fast redirect handling

  • Monitor logs and performance insights for slow routes and cold starts

]]>
https://blogs.perficient.com/2025/05/22/how-to-optimize-sitecore-headless-and-next-js-on-vercel/feed/ 0 381796
Sitecore Personalize: Advanced Page Targeting https://blogs.perficient.com/2025/05/21/sitecore-personalize-advanced-page-targeting/ https://blogs.perficient.com/2025/05/21/sitecore-personalize-advanced-page-targeting/#respond Wed, 21 May 2025 15:57:14 +0000 https://blogs.perficient.com/?p=381706

In my previous blog https://blogs.perficient.com/2024/07/01/sitecore-personalize-close-event-logic/, I shared a method for using cookies to enable the user to dismiss an alert banner.  This process involved writing the cookie when the user clicks the close icon and checking for the cookie when the experience is displayed.  This approach worked well because the entirety of the javascript code could be stored in the web template.  This ensures the code to check for the cookie can’t be missed or forgotten when the template was used.  Unfortunately, this had an unintended side effect.  Personalize still executed the experience and counted it in the analytics and performance metrics even though the javascript never added the elements to the screen.  This lead to overinflated metrics and the inability to use the data for accurate forecasting.  This problem can be overcome with advanced page targeting.

Advanced Page Targeting

Advanced page targeting allows you to run client side javascript to decide if an experience should execute.  Since the javascript runs client side, you can read the url and query string parameters, you can access the console to log messages, you can access the document object to query selectors on the page, and of course read cookies.  Advanced page targeting javascript runs after the page loads, but before the experience loads which allows us to prevent the experience from executing and overinflating analytics.  Be sure to keep your script as lean and performant as possible to reduce the possible screen flicker of loading the experience after the page has loaded.

Checking Cookies with Advanced Page Targeting

In order to use advanced page targeting, you must select the “specific pages” setting under “Page Targeting”.

Pers Apt Enable

Enable page targeting on specific pages to enable advanced page targeting

In the flyout window for page targeting, add any filters for pages where you want the experience to display.  If you want the experience to display on all pages, simply use the contains “/” rule.  In the advanced targeting section, click the “add script” button.

Pers Apt Configure

Configure advanced page targeting

In the advanced targeting code editor, enter the following code.

(function() {
   // console.log(new Error().stack);

    var cookies = document.cookie.split(';');
    for (var i = 0; i < cookies.length; i++) {
        var cookie = cookies[i].trim();
        if (cookie.indexOf('pers-' + selectedVariant.ref + '=clicked') === 0) {
            return false;
        }
    }

    targetingPassed();
})();

 

In my previous blog, I created the cookie using the variant.ref as part of the cookie name.  This adds the guid of the current experience id to the name of the cookie making it unique even when the web template was reused.  Advanced targeting does not have access to the variant.ref property.  So it doesn’t work with the close event logic idea I came up with before.  However, there is a selectedVariant.ref property that you can use.  Using selectedVariant.ref works for both experiences and experiments as it can dynamically get the correct guid of the current variant at run time.

When personalize evaluates this block of javascript code, it only continues processing the flow of execution for the experience if the “targetingPassed()” function is called.  If you want to stop the flow of execution, return false.  In our case, we want to stop the flow of execution if the cookie is found.  Otherwise we can call the targetingPassed() function and allow the experience to display to the user.

Once you have added advanced targeting javascript, you can edit the script by clicking the pencil icon.

Pers Apt Edit

Edit advanced page targeting settings

 

Pers Apt Editscript

Edit advanced page targeting script

Things to Know About Advanced Page Targeting

As mentioned, this solution solves the problem of overinflating analytics.  The downside is the advanced page targeting settings and code cannot be saved with the web template.  So the marketer or content author must remember to enable this setting and add the javascript code to the experience.  If the code is not added, the user will be able to close the experience, but it will display on the next page load since the code to check for the cookie is missing.  One other thing to note, if you change your page targeting settings back to “all pages”, the advanced targeting script is deleted from the experience.  In both cases, ensure that it is easy for content authors to find and reuse.

]]>
https://blogs.perficient.com/2025/05/21/sitecore-personalize-advanced-page-targeting/feed/ 0 381706
Getting Started with Personalization in Sitecore XM Cloud: Enable, Extend, and Execute https://blogs.perficient.com/2025/05/20/getting-started-with-personalization-in-sitecore-xm-cloud-enable-extend-and-execute/ https://blogs.perficient.com/2025/05/20/getting-started-with-personalization-in-sitecore-xm-cloud-enable-extend-and-execute/#respond Tue, 20 May 2025 07:47:48 +0000 https://blogs.perficient.com/?p=381481

 

In my previous blog – Personalization in Sitecore XM Cloud: What’s New, What’s Different, and What It’s Built On!, I explored what makes personalization in Sitecore XM Cloud so powerful – from its cloud-native infrastructure and headless architecture to the built-in rule-based targeting engine. Now, I’m shifting from concepts to implementation. In this post, I’ll walk you through how to enable personalization using analytics identifiers that track and categorize visitor behavior in real time. Then, I’ll show how to use Page Builder to create audience-specific page variants, and personalize components – all with a few clicks, not code.

In Sitecore XM Cloud, personalization happens primarily at the page level. The process revolves around creating page variants and personalizing components. This functionality is fully integrated into Page Builder, allowing you to define variations of the page based on different personalization criteria.

Key Points:

  • Personalization is configured directly within Page Builder on a per-page basis.
  • You can create page variants – each tailored to specific audiences or conditions.
    • Individual components on the page can be personalized : swapped, hidden and can be edited to show different content
  • All of this is managed via the Personalize tab available on the page within Page Builder.

How to Check if Personalization is Enabled:

To determine whether personalization is set up:

  • Go to the Page Builder for the desired page.
  • Click on the Personalize tab.

Personalization Notenabled

 

If personalization is not enabled, you will see :

  • No variant options available.
  • A prompt or empty state indicating no personalization rules are define.

 

Personalization Enabled

If personalization is enabled, you’ll see:

  • Variants listed based on configured rules.
  • Options to add/edit rules and personalize individual components.

 

 

Adding Analytics Identifiers to Enable Personalization

Analytics identifiers are essential for enabling personalization in Sitecore XM Cloud. They help track visitors, manage sessions, and unify data across sites for a complete view of user behavior. Without them, personalization rules and targeted content delivery won’t function. Assigning the same identifier to multiple sites allows for consolidated analytics, providing a holistic view of user engagement across different sites.

Step 1: Access Site Settings

  1. Navigate to the XM Cloud Portal: Log in to your XM Cloud environment.
  2. Open the Sites Dashboard: In the top navigation bar, click on Sites to view all your sites.
  3. Select the Desired Site: Locate the site you wish to configure. Click on the Actions menu (three dots) associated with that site and select Settings.
  4. Select the Site hosts: Browse through the options on the left side and select Site hosts option and then select the desired host

Personalization Site Hosts

Step 2: Add or Assign an Analytics Identifier

  1. Navigate to the Analytics and Personalization Tab: Within the site settings, click on the Analytics and Personalization tab.
  2. Add Identifier for a Language: In the list of languages associated with the site, click the plus (+) icon next to the language you want to configure

Personalization Analytics And Personalization Tab

Step 3: Choose Identifier Type:

    • Create a New Identifier: Select the Create new tab.
      • Name the Identifier: Provide a unique name for the analytics identifier.
      • Set Session Timeout: Define the session timeout duration (default is 30 minutes).
    • Assign an Existing Identifier: Select the Assign existing tab.
      • Select Identifier: Choose from the list of existing identifiers available in your environment.

Personalization Add Analytics Identifier

Let’s Personalize a Page in Sitecore XM Cloud

  1. Navigate to the Page in the Page Builder
  • From the XM Cloud portal, open your site and select the page you want to personalize.
  • Once it loads in Page Builder, you’ll see a “Personalize” tab at the top navigation bar if personalization is enabled.

Personalize Tab

  1. Create a Page Variant
  • Click on the Personalize tab.
  • Select Create Variant.
  • Provide a name for the variant (e.g. “Every Monday Campaign”)

Create Variant

  • Click Next to proceed to audience configuration.

Create Audience

  1. Define the Audience for the Variant

Available Condition Categories

 

Click Add first condition to define who should see this variant.

Choose from the available conditions such of different tags

 

 

  • Configure the selected condition using the provided fields.

Condition

  • You can add multiple conditions using AND/OR logic.

Multiple Conditions

 

 

Personalization Options Available

 

  1. Customize the Variant
  • Once you click on Save, your variant is created and the audience is defined, you can now edit the variant.
  • On the side is a screenshot of the Page Builder that lists down all that we can do with personalization on the page.

 

 

 

 

Personalized Component

  • You’ll see a color-coded border or indicator showing that you’re editing a personalized version.
  • Each change you make is isolated to that variant and won’t affect the default view.

 

  1. Preview the Variant
  • Use the Preview feature to see what the page will look like for the targeted audience.
  1. Publish the Variant
  • When satisfied, click Publish to activate your personalized variant.
  • Sitecore XM Cloud will now automatically show the appropriate variant to users matching the defined audience.

 

Personalization in Sitecore XM Cloud isn’t just a feature – it’s a strategic advantage. By enabling analytics identifiers and using Page Builder to create tailored experiences, you can deliver the right content to the right audience at the right time. With this setup in place, you’re well on your way to building smarter, more engaging digital experiences.

In the next blog, I’ll take you behind the scenes of how personalized content is actually delivered in Sitecore XM Cloud. We’ll explore the request lifecycle, how the Cloud SDK plays a role in fetching and rendering personalized variants, and the technical flow that powers real-time targeting. This deeper dive will help you understand not just what personalization looks like, but how it works under the hood.

 

]]>
https://blogs.perficient.com/2025/05/20/getting-started-with-personalization-in-sitecore-xm-cloud-enable-extend-and-execute/feed/ 0 381481
Sitecore PowerShell commands – XM Cloud Content Migration https://blogs.perficient.com/2025/05/07/xm-cloud-content-migration-powershell-commands/ https://blogs.perficient.com/2025/05/07/xm-cloud-content-migration-powershell-commands/#comments Wed, 07 May 2025 06:46:42 +0000 https://blogs.perficient.com/?p=380770

In this post, I’ve listed the most commonly used Sitecore PowerShell commands for content migration. This blog continues from my earlier post: Sitecore XM Cloud Content Migration: Plan and Strategy.

During migration, we created several PowerShell scripts to extract data from the legacy database to CSVs. We then used those CSVs to import content into XM Cloud instances. Based on those scripts, I organized the commands into two groups: Working with Sitecore items and Working with Sitecore renderings. These commands aim to help developers handle similar Sitecore to XM Cloud migrations.

The command snippets are also available as a public GitHub Gist – Most widely used PowerShell SPE commands in Sitecore XM Cloud content migration

Working With Sitecore Items

Create a New Item Using the Template ID

$item = New-Item -Path $path -Name $itemName -ItemType $itemTemplateId -Language "en"

Sometimes, you may need to create an item with the same ID as in the legacy system to avoid numerous reconfigurations. Especially if those items are being used as the data source. In such a use case, we could use CreateItem from Sitecore.Data.Managers.ItemManager. This method takes the item name, parent item, template ID, and item ID. The passed $id will be the ID of the newly created Sitecore Item. 

$item = [Sitecore.Data.Managers.ItemManager]::CreateItem($name, $parentItem, $templateItem.ID, $id)

Also, there is a ForceId param supported by the ‘New Item‘ function

New-Item -Path $path -Name $name -ItemType "Blog Page" -ForceId "3904b0bf-b10b-4fbb-9ced-3de87dfa3d48"

Create a New Item Using the Branch Template

$item = [Sitecore.Data.Managers.ItemManager]::AddFromTemplate($itemName, $branchTemplateId, $parentItem)

Checking if the Path Exists in the Content Tree

In use cases, we need to check whether the path exists before creating an item on that path. 

$pathExists = Test-Path -Path $path
if($pathExists)
{
  //logic
}

Copying Items

Copy-Item -Path $sourcePath -Destination $targetPath

Working with Sitecore Renderings

Get All Renderings for an Item

This script was used to analyze an item’s legacy renderings, map them with new XM cloud renderings (components), and map fields. 

$item = Get-Item -Path $path -Version "latest"
$resultObj = @()
$defaultLayout = Get-LayoutDevice "Default"
Get-Rendering -Item $item -Device $defaultLayout -FinalLayout | ForEach {
    $renderingItem = Get-Item -Path master: -ID $_.ItemID
    $Obj = @{
        RenderingName =  $renderingItem.Name
        RenderingId =  $_.ItemID
        DataSource = $_.Datasource
        Placeholder = $_.Placeholder
        PageItem = $_.OwnerItemID
}
    $resultObj += New-Object psobject -Property $Obj
}
$resultObj | Format-Table RenderingName, RenderingId, DataSource, Placeholder, PageItem

Create and Set Rendering for an Item

When importing data from CSV, we often need to create and set a data source to render an item.  For this use case, I created a function that takes the rendering ID, the placeholder to add the rendering, and the data source ID. 

function CreateAndSetRendering{
    param([String]$id,[String]$placeholder,[String]$dsid
        )
        
        $renderingId = [Sitecore.Data.ID]::Parse($id)
        $rendering = get-item -path master: -id $renderingId
        $renderinginstance = $rendering | new-rendering -placeholder $placeholder
        if($dsid -ne "")
        {
            $datasourceId = [Sitecore.Data.ID]::Parse($dsid)
            $renderinginstance.datasource = $datasourceId
        }
        add-rendering -item $item -placeholder $placeholder -instance $renderinginstance -finallayout
        $item.editing.beginedit()
        $item.editing.endedit() | out-null
}

Retrieve the Rendering and Remove From the Presentation

{3904b0bf-b10b-4fbb-9ced-3de87dfa3d48} is the Sitecore Item ID of the rendering item we wish to retrieve

$defaultLayout = Get-LayoutDevice "Default"
$rendering = Get-Rendering -Item $item -Device $defaultLayout -FinalLayout | Where-Object { $_.ItemID -eq "{3904b0bf-b10b-4fbb-9ced-3de87dfa3d48}"}
Remove-Rendering -Item $item -Instance $rendering -Device $defaultLayout -FinalLayout

Getting a Specific Rendering Parameter Value

$paraName is the rendering parameter name, for example, “Styles”.

$rendering = Get-Item -Path master: -Id "{3904b0bf-b10b-4fbb-9ced-3de87dfa3d48}"
$renderingItem = Get-Rendering -Item $item -Device $defaultLayout -Rendering $rendering -FinalLayout
$parameterValue = Get-RenderingParameter -Rendering $renderingItem -Name $paramName

Updating Rendering Parameter Value

If there are more than one rendering of the same type, the returned $renderingItem will be an array so you can access the first rendering parameters $renderingItem[0].Parameters: This will return all parameters, and then you will have to check for a specific parameter.

$rendering = Get-Item -Path master: -Id "{3904b0bf-b10b-4fbb-9ced-3de87dfa3d48}"
$renderingItem = Get-Rendering -Item $item -Device $defaultLayout -Rendering $rendering -FinalLayout
$renedringParams = $renderingItem[0].Parameters
$styles = "Styles"
 if ($renedringParams.Contains($styles)) {
      $renedringParams = @{
            Styles = "%7B3904b0bf-b10b-4fbb-9ced-3de87dfa3d48%7D"
    }
    }
Set-RenderingParameter -Instance $renderingItem[0] -Parameter $renedringParams | Out-Null
Set-Rendering -Item $item -Instance $renderingItem[0] -FinalLayout

Note: We must embed Sitecore ID for your required style between %7B and %7D. For multiple values, the separator is %7D%7C%7B. It’s how Sitecore stores params values.

You can store multiple values like this: Styles = “%7B3904b0bf-b10b-4fbb-9ced-3de87dfa3d48%7D%7C%7B936219ee-a03b-49c5-8eff-8b877b5c1319%7D”

Conclusion

So, this is the consolidated list of Sitecore PowerShell commands for content migration. The IDs used in the above snippets were not valid Sitecore item IDs. Replace them with valid Sitecore item IDs based on the Sitecore items used in your project.

Keep learning!

]]>
https://blogs.perficient.com/2025/05/07/xm-cloud-content-migration-powershell-commands/feed/ 3 380770
Sitecore XM Cloud Content Migration: Plan and Strategy https://blogs.perficient.com/2025/05/06/xm-cloud-content-migration-plan/ https://blogs.perficient.com/2025/05/06/xm-cloud-content-migration-plan/#respond Tue, 06 May 2025 09:13:10 +0000 https://blogs.perficient.com/?p=380152

Sitecore XM cloud content migration can be approached in various ways. The first thing that comes to mind when working on the Sitecore upgrade project to XM Cloud is content migration. Choosing the right method helps reduce migration time and avoid errors. I will outline the approach that best meets our client’s needs in this blog. We were provided with a master database backup that had all the content. Our task was to move Sitecore data, including media, from Sitecore 9.3 to XM Cloud.

We connected the legacy Sitecore database to the XM Cloud instance for migration. My colleague Martin Miles wrote a detailed blog on XM Cloud content migration: connecting the external database

Sitecore Items Data Migration to XM Cloud

Extracting items and their field data was relatively straightforward. We used PowerShell scripts to export item field data into CSV files. These CSVs were later imported into the XM Cloud using import scripts, building different page types.

We chose this approach due to a complete redesign of templates and renderings. The new XM Cloud setup did not reuse old templates, fields, or renderings. XM Cloud included fresh templates, fields, and renderings. This allowed us to map legacy page templates and fields to the new XM Cloud templates. This mapping helped us to import field values for different page types accordingly.

Our import scripts created key page types and populated the fields using field mappings. We created some standardized renderings for key page templates like Rich Texts, Accordion, etc. The scripts assigned data sources automatically to save content authors’ time. Only a few pages, like home, landing, and search, were created manually, which were unique. Most other pages were created using automation scripts.

XM Cloud runs in Docker containers in the local environment. So, we couldn’t access CSV files directly from the local file system. However, we have this covered by copying CSVs into \docker\deploy\platform\App_Data. This folder is part of the project’s root directory. These CSVs then became accessible within the local XM Cloud instance. We leveraged Sitecore Package Designer to package the CSV files to be installed in higher environments to run import scripts.

Sitecore Package Designer - Files Statically

Media Migration to XM Cloud

We already have a legacy Sitecore database connected to the XM Cloud instance. Using Sitecore’s out-of-the-box UI for bulk content migration between databases, we locally transferred media from the legacy database to the XM Cloud.

Controlpanel Moveitemtootherdb

Once the media folder with all the subfolders moved to XM Cloud, we have used a script to create media packages. My colleague Nick has written thorough blog on Exporting Media Items with Sitecore PowerShell Extensions to create packages of media.

The number of media packages depends on your database size. We had approximately 5GB of media items to migrate, so we created around 190 media packages for this migration. Package count also depends on the size of each media package. We limited each media package size to 25MB. Larger media packages take more time to upload and install. Sometimes, big packages get stuck without showing installation progress, which is frustrating.

In higher environments, we used the script below to upload and install the packages created locally.

$filepath = Receive-File -Path "C:\inetpub\wwwroot\App_Data\packages\"
Write-Host "Uploaded package Succesfully : " $filepath

# get file size in MB in PowerShell   
$size = (Get-Item -Path $filepath).Length/1MB
Write-Host $size "MB"
Write-Host "Installation Started......"
Install-Package -Path $filepath -InstallMode Merge -MergeMode Merge
Write-Host "Installation Completed - Package installed successfully"

In this way, we had migrated a whole media library to XM Cloud. This process was tedious and took a day to create and upload all packages.

I am sharing sample PowerShell scripts for extracting and importing Sitecore item data. The Sitecore IDs used in the scripts are not valid; you need to replace them as per your project’s Sitecore item IDs.

The PowerShell scripts are also available as a public GitHub Gist Export-Import SitecoreItemData SPE Scripts

Sitecore Item Data Extraction Script

<#
    .SYNOPSIS
       Generic Page data extraction
        
    .DESCRIPTION
        Gets Sitecore Items from legacy database and extracts field values.
        List could be exported to csv by OOTB feature of List View in SPE.
        
    .NOTES
        Akash Borkar | Perficient 
#>

function Write-LogExtended {
    param(
        [string]$Message,
        [System.ConsoleColor]$ForegroundColor = $host.UI.RawUI.ForegroundColor,
        [System.ConsoleColor]$BackgroundColor = $host.UI.RawUI.BackgroundColor
    )

    Write-Log -Object $message
    Write-Host -Object $message -ForegroundColor $ForegroundColor -BackgroundColor $backgroundColor
}

# Function for getting item names from pipe-separated item ids
function GetItemNamesFromIds {
    param(
        [System.String] $ids
    )
    
    if($ids.Contains("|"))
    {
        # Split the string by pipe and clean up each GUID
        $guids = $ids.Split("|") | ForEach-Object { $_.Trim(' {}') }
        [Sitecore.Text.ListString]$nameArr = ""

        foreach ($id in $guids) {
            $formattedId = "{0}{1}{2}" -f '{', $id, '}'
    
            $Id = [Sitecore.Data.ID]::Parse($formattedId) 
            $item = Get-Item -Path xyz: -ID $Id
                    
            if ($item -ne $null -and !$nameArr.Contains($item.Name)) {
                $nameArr.Add($item.Name) | Out-Null
            }
        }
        
        # Join the names with pipe separator and return the result
        $names = [System.String]::Join("|", $nameArr)
        return $names
    }
    else
    {
        $item = Get-Item -Path xyz: -ID $ids
            return $item.Name
    }
}

#Function for getting datasource item, which is further used for extracting field value & assigning to new rendering
function Get-DatasourceItem{
    param(
         [System.String] $path
        )
        $datasourceItem = $sourceDatabase.GetItem($path)
        return $datasourceItem
}


Write-LogExtended " "
Write-LogExtended "Generic Pages Data Extraction"
Write-LogExtended "-----------------------------------------------------------------"

$processedItems = [System.Collections.Generic.List[PSCustomObject]]::new()
$nonprocessedItems = [System.Collections.Generic.List[PSCustomObject]]::new()
$sourceDatabase = Get-Database "xyz"

$parentPath = Show-Input -Prompt "Please enter the Sitecore item path for getting children"
if($parentPath -ne $null)
{
    Write-Host "Selected path: $parentPath"

    #Get all child items based on provided path. /sitecore/content/XYZ/Home/Generic
    $nodePath = "xyz:" + $parentPath
    $items = Get-ChildItem -Path $nodePath -Recurse | Where-Object { $_.TemplateName -eq 'Generic Page'}
    
    Write-LogExtended "Total child items: $($items.Count)  Path: $($nodePath)" -ForegroundColor Green
    
    foreach($sourceItem in $items)
    {
        if($sourceItem -ne $null){
            
            #Retrieve RTE
            $rts = Get-Rendering -Item $sourceItem -Device $defaultLayout -FinalLayout | Where-Object { $_.ItemID -eq "{278F7B0D-98F4-4873-9B7B-940082158E4A}"}
            [Sitecore.Text.ListString]$rtArr = ""
            
            if($rts -ne $null)
            {
                foreach($rt in $rts)
                { 
                  $item = $sourceDatabase.GetItem($rt.Datasource)
                  if($item -ne $null -and $item["Text"] -ne "")
                  {
                      $rtArr.Add($item["Text"]) | Out-Null
                  }
                }
            }
            
            
            #Retrieve Accordion
            $accordion = Get-Rendering -Item $sourceItem -Device $defaultLayout -FinalLayout | Where-Object { $_.ItemID -eq "{165B5ECC-E6A0-4B41-AA23-D28FA5A9BF68}"}
            $accordionCount = 0
            [Sitecore.Text.ListString]$titleArr = ""
            [Sitecore.Text.ListString]$descArr = ""
            
            if($accordion -ne $null)
            {
                foreach ($renderingItem in $accordion) 
                {
                    if($renderingItem.Datasource -ne "")
                    {
                        $rendering = Get-Item -Path xyz: -Id $renderingItem.Datasource
                        if($rendering.HasChildren)
                        {
                            $accdChildItems = Get-ChildItem -Path xyz: -ID $rendering.ID
                            foreach($item in $accdChildItems)
                            {
                                if($item["Title"] -ne "" -and $item["Description"] -ne "")
                                {
                                      $titleArr.Add($item["Title"]) | Out-Null
                                      $descArr.Add($item["Description"]) | Out-Null
                                }
                            }
                        $accordionCount++;
                        }
                    }
                }
            }
                
            #Retrieve values of multilist field named Categories
            $categories = $sourceitem["Categories"]
            $categoriesnames = ""
            if($categories -ne "" -and $categories -ne $null)
            {
                $categoriesnames = GetItemNamesFromIds -ids $categories
            }
            
            
            try{
                $processedItems.Add(
                    [PSCustomObject]@{
                        Name = $sourceItem.Name
                        Id = $sourceItem.Id
                        Path = $sourceItem.Paths.FullPath
                        Title = $sourceItem["Title"]
                        HeaderTitle = $sourceItem["Header Title"]
                        Summary = $sourceItem["Summary"]
                        Image = $sourceItem["Image"]
                        OGImage = $sourceItem["Media Image"]
                        Categories = $categoriesnames
                        HasRTE = $rtArr.Count
                        RichText1 = $richText
                        RichText2 = $rtArr[1]
                        RichText3 = $rtArr[2]
                        
                        HasAccordion = $accordionCount
                        AccTitle1 = $titleArr[0]
                        AccDesc1 = $descArr[0]
                        AccTitle2 = $titleArr[1]
                        AccDesc2 = $descArr[1]
                        AccTitle3 = $titleArr[2]
                        AccDesc3 = $descArr[2]
                        AccTitle4 = $titleArr[3]
                        AccDesc4 = $descArr[3]
                        
                    }
                )
                        
            Write-LogExtended "Added data for $($sourceItem.Name), Path: $($sourceItem.Paths.FullPath) " -ForegroundColor Green
            }
            catch{
                Write-Host "Error occured" -BackgroundColor DarkRed
                            
                $nonprocessedItems.Add(
                    [PSCustomObject]@{
                        Name = $sourceItem.Name
                        Id = $sourceItem.Id
                        Path = $sourceItem.Paths.FullPath
                    }
                )
            }
        }
        else
        {
            Write-LogExtended "No Item found in csv for SourceURL: $($row.SourceURL)" -ForegroundColor RED
        }
    }
    
    $processedItems | Show-ListView -PageSize 15000 -Property  Name, Id, Path, Title, HeaderTitle, Summary, Categories, Image, OGImage, 
                                                                HasRTE, RichText1, RichText2, RichText3, HasAccordion, AccTitle1, AccDesc1, AccTitle2, AccDesc2, AccTitle3, 
 AccDesc3, AccTitle4, AccDesc4
                                                             
    $processedItems | export-csv -Path "C:\inetpub\wwwroot\App_Data\Process.csv" -NoTypeInformation                                                  
    $nonprocessedItems | Show-ListView -PageSize 15000 -Property  Name, Id, Path
}
else
{
        Write-Host "Path is not provided : $parentPath"
}

Sitecore Item Import Script

<#
    .SYNOPSIS
       Generic Pages Import
        
    .DESCRIPTION
        Iterate through CSV, create siteore items for generic pages and Populate fields. Generate List of processed and Non processed items.
        
    .NOTES
        Akash Borkar | Perficient 
#>

function Write-LogExtended {
    param(
        [string]$Message,
        [System.ConsoleColor]$ForegroundColor = $host.UI.RawUI.ForegroundColor,
        [System.ConsoleColor]$BackgroundColor = $host.UI.RawUI.BackgroundColor
    )

    Write-Log -Object $message
    Write-Host -Object $message -ForegroundColor $ForegroundColor -BackgroundColor $backgroundColor
}


Write-LogExtended " "
Write-LogExtended "Generic Pages Import"
Write-LogExtended "-----------------------------------------------------------------"

# Prompt for the file path
$filePath = Show-Input -Prompt "Please enter the full path to the CSV file"
if($filePath -ne $null)
{
Write-Host "Selected file: $filePath"

# Import the CSV file
$csvData = Import-Csv -Path $filePath | Where-Object { -join $_.psobject.Properties.Value }

Write-LogExtended "CSV file read successfully" -ForegroundColor Green

    if($csvData -ne $null)
    {
        $processedItems = [System.Collections.Generic.List[PSCustomObject]]::new()
        $NonProcessedItems = [System.Collections.Generic.List[PSCustomObject]]::new()
        $database = Get-Database "master"
        $placeholder = "/headless-main/container-1"
        
        foreach ($row in $csvData){
            
            #Generic Page branch
            $branchTemplateId = [Sitecore.Data.ID]::Parse("{8032FE9E-3CD1-4E80-8377-66BBF74F839E}")
            
            # Extract the desired item name, parent item and template id from the URL
            $itemName = $row.Name
            $parentItemPath = $row.Path -Replace $itemName, ""

            # Get the parent item
            $parentItem = $database.GetItem($parentItemPath)
            
            if ($parentItem){
                # Check if the item already exists
                $existingItemPath = "$($parentItem.Paths.FullPath)/$itemName"
                $itemExists = Test-Path -Path $existingItemPath
                
                if (-not $itemExists){
                    $item = [Sitecore.Data.Managers.ItemManager]::AddFromTemplate($itemName, $branchTemplateId, $parentItem)
                    
                    if ($item -eq $null) {
                    Write-LogExtended "Unable to create new item - $($itemName) - in Language en" -ForegroundColor Red
                    
                        $NonProcessedItems.Add(
                        [PSCustomObject]@{
                            ID = $row.ID
                            Name    = $row.Name
                            Path = $row.Path
                        })
                    }
                    
                    if($item -ne $null){
                        $item.Editing.BeginEdit()
                        
                        $item["Title"] = $row.Title
                        
                        #Meta Properties/OG
                        $item["OpenGraphTitle"] = $row.Title
                        $item["OpenGraphDescription"] = $row.Summary
                        $item["MetaDescription"] = $row.Summary
                        $item["TwitterDescription"] = $row.Summary 
                        $item["TwitterImage"] = $row.OGImage
                        
                        $item.Editing.EndEdit() | Out-Null
                        
                        
                        $datasourcePath =  $item.Paths.FullPath + "/Data/"
                        #Create and Populate Rich Text (Max RT are 3 as we had extracted 3 RTEs)
                        if($row.RichText1 -ne "")
                        {
                             For($i=1; $i -lt 4; $i++) 
                                { 
                                    $propname = "RichText$i"
                                    if($row.$propname -ne "")
                                    {
                                        $dsitem = New-Item -Path $datasourcePath -Name "Text $i" -ItemType "{4FBDBF79-C7D6-42F1-8048-D5E70D6167D5}"
                                        $dsitem.Editing.BeginEdit()
                                        $dsitem.Text =  $row.$propname
                                        $dsitem.Editing.EndEdit() | Out-Null
                                        
                                        #Create and Set Rich text Rendering
                                        $rendering = get-item -path master: -id {EF82E4AE-C274-40D4-837C-B3E1BF180CCC}
                                        $renderinginstance = $rendering | new-rendering -placeholder $placeholder
                                        $renderinginstance.datasource = $dsitem.id
                                        Add-Rendering -Item $item -placeholder $placeholder -instance $renderinginstance -finallayout
                                        $item.Editing.beginedit()
                                        $item.Editing.endedit() | out-null
                                    }
                                }
                        }
                        
                        
                        #Create and Populate Accrd datasource item (Max Acc are 4)
                        if($row.AccTitle1 -ne "" -and $row.AccDesc1 -ne "")
                        {
                            $accDatasourcePath =  $item.Paths.FullPath + "/Data/"
                            #Accordion
                            $Accitem = New-Item -Path $accDatasourcePath -Name "Accordion" -ItemType "{D482D45C-4248-46C8-BDD5-DE7C2255C52A}"
                            $Accitem.Editing.BeginEdit()
                            $Accitem.Title =  "Accordion"
                            $Accitem.Editing.EndEdit() | Out-Null
                            
                            #Create and Set Acc rendering
                            $rendering = Get-Item -Path master: -ID {3341A94D-42C9-4EE3-8A25-51D8B437982B} #Accordion
                            $renderingInstance = $rendering | New-Rendering -Placeholder $placeholder
                            $renderingInstance.Datasource = $Accitem.ID
                            Add-Rendering -Item $item -PlaceHolder $placeholder -Instance $renderingInstance -FinalLayout
                            
                            For($i=1; $i -lt 5; $i++) 
                            { 
                                $titlename = "AccTitle$i"
                                $descname = "AccDesc$i"
                                if($row.$titlename -ne "" -and $row.$descname -ne "")
                                {
                                    #Acc Panel
                                    $dsitem = New-Item -Path $Accitem.Paths.FullPath -Name $row.$titlename -ItemType "{B50C502C-2740-44C8-A63E-E9E4AF4BAA4B}"
                                    $dsitem.Editing.BeginEdit()
                                    $dsitem.Title =  $row.$titlename
                                    $dsitem.Content =  $row.$descname
                                    $dsitem.Editing.EndEdit() | Out-Null
                                    
                                    #Create and Set Acc panel rendering
                                    $rendering = Get-Item -Path master: -ID {7614DFFF-6735-4BA5-929A-A82FBC91DB25} #Acc Panel
                                    $renderingInstance = $rendering | New-Rendering -Placeholder "/headless-main/container-1/accordion-panels-1"
                                    $renderingInstance.Datasource = $dsitem.ID
                                    Add-Rendering -Item $item -PlaceHolder "/headless-main/container-1/accordion-panels-1" -Instance $renderingInstance -FinalLayout
                                    $item.Editing.BeginEdit()
                                    $item.Editing.EndEdit() | Out-Null
                                    
                                    Write-LogExtended "Added Accordion datasource to New Item - $($item.Name) at $($dsitem.Paths.FullPath)" -ForegroundColor Green
                                }
                            }
                        }
                        
                        $ManualWork = "No"
                        if(($row.HasRTE -gt 3) -or ($row.HasAccordion -gt 4))
                        {
                            $ManualWork = "Yes"
                        }
                        
                        Write-LogExtended "Created New Item - $($itemName) at $($parentItemPath)" -ForegroundColor Green
                        $processedItems.Add(
                        [PSCustomObject]@{
                            Name    = $item.Name
                            Id = $item.ID
                            NewPath = $item.Paths.FullPath
                            HasRTE = $row.HasRTE
                            HasAccordion = $row.HasAccordion
                            ManualWork = $ManualWork 
                        })
                    }
                }
                else 
                {
                    Write-LogExtended "Item $($itemName) already exists at $($parentItemPath) " -ForegroundColor Yellow
                }
            }
            else 
            {
                Write-LogExtended "Parent item not found: $parentItemPath" -ForegroundColor Red
            }
        }
        
    $processedItems | Show-ListView -PageSize 2000 -InfoTitle "Processed Items" -Property  Name, Id, NewPath, HasRTE, HasAccordion, ManualWork
        $processedItems | export-csv -Path "C:\inetpub\wwwroot\App_Data\GenericPagesReport.csv" -NoTypeInformation
    $NonProcessedItems | Show-ListView -PageSize 2000 -InfoTitle "Non Processed Items" -Property  ID, Name, Path
    }
}
else
{
    Write-Host "No file selected : $filePath"
}

I kept the script limited to extracting some fields and renderings; however, it gives a fair idea of how to extract data and import.

Conclusion

The PowerShell scripts you will write will be based on project requirements, template naming, rendering, and field mappings for your key page templates. When we first started migrating, we had a hard time figuring out the approach and connecting the dots. In this blog, I wanted to make sure the plan is clear. In my next blog Sitecore PowerShell commands – XM Cloud Content Migration, I will give the code snippets of the most widely used PSE commands used in Sitecore content migration.

]]>
https://blogs.perficient.com/2025/05/06/xm-cloud-content-migration-plan/feed/ 0 380152
Using Sitecore Connect and OpenAI: A Practical Example for Page Metadata Enhancement https://blogs.perficient.com/2025/04/29/using-sitecore-connect-and-openai-a-practical-example-for-page-metadata-enhancement/ https://blogs.perficient.com/2025/04/29/using-sitecore-connect-and-openai-a-practical-example-for-page-metadata-enhancement/#respond Tue, 29 Apr 2025 10:09:44 +0000 https://blogs.perficient.com/?p=380646

Sitecore Connect is Sitecore’s low-code integration platform designed to easily automate workflows between Sitecore and external systems, without heavy custom coding. If you’re new to Sitecore Connect or want a deeper understanding of when and how to use it, check out these helpful resources:

In this practical example, we’ll demonstrate how to use Sitecore Connect together with OpenAI to send a page URL and fetch AI-generated meta tags (like meta title and meta description) to enrich the page’s SEO.

We will walk through:

  • Setting up a connection to OpenAI using Sitecore Connect’s HTTP app
  • Building a recipe that:
    • Triggers when a page is created or updated
    • Sends the page URL to OpenAI with a prompt asking for meta tags
    • Receives and processes AI-generated meta title and meta description

This approach enhances your content creation workflows by generating smart SEO metadata at scale, using minimal manual effort and maximum AI power.

Step 1: Creating a Connection with OpenAI

To start integrating OpenAI with Sitecore Connect, the first step is to create a connection using your OpenAI API key.

Follow these steps:

  1. Obtain the API Key:
    • Login to your OpenAI account (such as through OpenAI portal).
    • Navigate to your account settings and generate an API key.
      (Keep this key safe as you will need it for authentication.)
  2. Create a New Connection:
    • In Sitecore Connect, click on the Create Connection button.
  3. Choose OpenAI from the App Library:
    • A list of available apps will be displayed.
    • Use the search bar to find “OpenAI” and select it.
    • Click on Create Connection.
  4. Configure the Connection:
    • Enter the following details:
      • Name: Provide a meaningful name for your connection (e.g., “OpenAI Meta Tag Generator”).
      • Location: Select the workspace or folder where you want the connection saved.
      • API Key: Paste the API key you copied from your OpenAI account.Create A Connection
  5. Authenticate and Test:
    • Click on the Connect button.
    • Sitecore Connect will attempt to authenticate with OpenAI using the provided API key.
    • If the authentication is successful, your connection will be created and ready to use.

With the OpenAI connection established, we can now move on to building a recipe to send page URLs and retrieve meta tag suggestions!

Step 2: Building the Recipe Function to Send Page URL and Fetch Meta Tags

Now that the connection to OpenAI is ready, let’s create a Recipe Function in Sitecore Connect.
This allows you to call the function from anywhere (like another recipe or an external system) by passing the page URL dynamically.

Follow these updated steps:

  1. Create a New Recipe Function:
    • In Sitecore Connect, go to the Recipes section.
    • Click on Create Recipe.
    • In the trigger selection screen, choose Build a Recipe Function.
      (This creates a callable function, not a direct event-based recipe.)
  2. Add Input Parameter for Page URL:
    • After creating the function, Sitecore Connect will prompt you to define input parameters.
    • Add a new parameter:
      • Name: Page URL
      • Type: Text / String
    • This parameter will allow the function to receive any page URL dynamically.
  3. Select App and Action:
    • Once the function is ready, click on Add an Action.
    • The App Library will open.
    • Using the connection you created earlier,select OpenAI from the available apps.Select App
  4. Choose the Action Type:
    • After selecting OpenAI, you will see a list of available actions.
    • Select the Send a Message action.Action Creation
    • It provides 2 options Single message and Chat transcript.
    • I chose Single Message as the message type for this case.
    • Message Type

Now, in the Message Content to OpenAI, configure it carefully:

Prompt to OpenAI:

Message

  • Here, {Page URL} dynamically uses the Page URL input parameter you defined in Step 2.

This ensures that OpenAI receives the correct URL, understands the task, and responds in a structured JSON output ready for further processing.

After setting this message, you will be ready to handle and use the response in the next steps!

Step 3: Handling the OpenAI Response

Once OpenAI processes the URL and sends back a response, we need to parse the result and map it to usable fields inside Sitecore Connect.
This step ensures the meta title and meta description are correctly extracted and available for further use.

Follow these steps:

  1. Parse the JSON Response:
    • After the OpenAI action, add a Parse JSON step.
    • Configure it to parse the body of the response you get from OpenAI.
    • Define the expected schema based on the format you instructed OpenAI to return:
    • {
    •   “meta_title”: “string”,
    •   “meta_description”: “string”
    • }
    • Sitecore Connect will now recognize meta_title and meta_description as separate variables you can use.
  2. Use the Parsed Data:
    • After parsing, you can now:
      • Return the meta title and meta description as the output of the Recipe Function.
      • OR, if part of a larger automation, map these fields directly into your Sitecore items.
  3. Test the Flow:
    • Use the Test function inside Sitecore Connect.
    • Provide a sample Page URL as input.
    • Run the recipe function and validate that:
      • OpenAI is called correctly.
      • The JSON response contains the expected meta title and meta description.
      • The fields are parsed and mapped properly.

 

Final

Conclusion

By using Sitecore Connect and OpenAI together, you can create powerful, scalable automations that enhance your content operations.
In this example, it is showed how to send a page URL to OpenAI, fetch SEO metadata, and integrate it seamlessly into Sitecore workflows — all without writing heavy custom code.

This type of automation opens new possibilities for smarter, faster content management at enterprise scale.

]]>
https://blogs.perficient.com/2025/04/29/using-sitecore-connect-and-openai-a-practical-example-for-page-metadata-enhancement/feed/ 0 380646
What’s the point of Headless? https://blogs.perficient.com/2025/04/23/whats-the-point-of-headless/ https://blogs.perficient.com/2025/04/23/whats-the-point-of-headless/#respond Wed, 23 Apr 2025 17:49:11 +0000 https://blogs.perficient.com/?p=379825

In the ever-evolving world of web development, the term “headless” is as popular today as it ever has been. But what does it really mean, and why should you care? Let’s dive into the concept of headless architecture, its benefits, and why Sitecore is leading the charge in this space.

What is Headless?

At its core, a headless CMS is a software design approach that separates the front-end (what users see) from the back-end (where content is managed). Unlike traditional CMS platforms that tightly couple content management with presentation, headless CMS’s use APIs to deliver content anywhere—web, mobile app, kiosk, or a smart device. In many ways, the originator of headless architecture is Jamstack – which stands for JavaScript, APIs, and Markup. Instead of relying on traditional monolithic architectures, Jamstack applications decouple the web experience from the back-end, making them more scalable, flexible, and high-performing. JavaScript handles dynamic interactions on the front-end, allowing developers to build fast and modern user experiences. API’s provide a way to pull in content and services from various sources and the website can also push data to API’s such as form submissions, custom analytics events and other user driven data. Markup refers to pre-built HTML that can be served efficiently, often generated using static site generators or frameworks like Next.js.

Why Go Headless?

You might be wondering, “Why would I build my website entirely in JavaScript when it’s mostly content?” That’s a valid question and I thought the same when Sitecore JSS first came out. Headless though is less about “building your site in JavaScript” and more about the benefits of the architecture.

Flexibility

Headless CMS’s allow developers to work with any front-end framework they choose, whether it’s React, Vue, Angular, or whatever your favorite framework might be. This means teams are not locked into the templating system of a traditional CMS or the underlying backend technology.

Performance

Speed is everything in today’s digital landscape. Studies show that even a slight delay in page load time can significantly impact user engagement and conversion rates. Headless CMS’s improve performance by enabling static site generation (SSG) and incremental static regeneration (ISR)—both of which ensure lightning-fast load times. Instead of a server processing each request from a user, static content can be served from a global CDN – which is a modern composable architecture. Of course, server side rendering is also still an option and can also by very performant with the right caching strategy.

Omnichannel Delivery

Content today is consumed on more than just websites. Whether it’s a mobile app, smart device, digital kiosk, or even a wearable, headless architecture ensures content can be delivered anywhere through API’s. This makes it easier for brands to maintain a consistent digital experience across multiple platforms without duplicating content.

Security

Traditional CMS’s are often vulnerable to security threats because they expose both the content management system and the front-end to potential attacks. In contrast, headless CMS’s separate these layers, reducing the attack surface. With content served via APIs and front-end files hosted on secure CDNs, businesses benefit from enhanced security and fewer maintenance headaches.

Scalability

Handling high traffic volumes is a challenge for traditional CMS platforms, especially during peak times. Since headless solutions rely on cloud-based infrastructure, they can scale dynamically without requiring expensive hardware upgrades. Whether you’re serving thousands or millions of users, headless architecture ensures your site remains stable and responsive.

Why Sitecore for Headless?

There are plenty of options in the headless CMS market, but Sitecore offers a unique blend of features that make it stand out. With XM Cloud, Sitecore provides a fully SaaS-based solution—no more infrastructure headaches, no more costly upgrades, and uptime and reliability are now handled by Sitecore.

Sitecore’s hybrid headless approach allows organizations to transition at their own pace, leveraging the benefits of headless while maintaining familiar content management workflows. Hybrid headless gives content authors complete freedom and flexibility to build content however they’d like – where most purely headless content management systems are more rigid on how pages are built.

As digital experiences become more dynamic and user expectations continue to rise, headless CMS solutions offer the agility businesses need. If you’re looking to modernize your digital strategy, now is the time to embrace headless.

]]>
https://blogs.perficient.com/2025/04/23/whats-the-point-of-headless/feed/ 0 379825
How the Change to TLS Certificate Lifetimes Will Affect Sitecore Projects (and How to Prepare) https://blogs.perficient.com/2025/04/18/how-the-change-to-tls-certificate-lifetimes-will-affect-sitecore-projects-and-how-to-prepare/ https://blogs.perficient.com/2025/04/18/how-the-change-to-tls-certificate-lifetimes-will-affect-sitecore-projects-and-how-to-prepare/#respond Fri, 18 Apr 2025 13:54:17 +0000 https://blogs.perficient.com/?p=380286

TLS certificate lifetimes are being significantly reduced over the next few years as part of an industry-wide push toward greater security and automation. Here’s the phased timeline currently in place:

  • Now through March 15, 2026: Maximum lifetime is 398 days

  • Starting March 15, 2026: Reduced to 200 days

  • Starting March 15, 2027: Further reduced to 100 days

  • Starting March 15, 2029: Reduced again to just 47 days

For teams managing Sitecore implementations, this is more than a policy shift—it introduces operational urgency. As certificates begin expiring more frequently, any reliance on manual tracking or last-minute renewals could result in costly downtime or broken integrations.

If your Sitecore environment includes secure endpoints, custom domains, or external integrations, now is the time to assess your certificate strategy and move toward automation.

Why This Matters for Sitecore

Sitecore projects often involve:

  • Multiple environments (development, staging, production) with different certificates

  • Custom domains or subdomains used for CDNs, APIs, headless apps, or marketing campaigns

  • Third-party integrations that require secure connections

  • Marketing and personalization features that rely on seamless uptime

A single expired certificate can lead to downtime, loss of customer trust, or failed integrations—any of which could severely impact your digital experience delivery.

Key Risks of Shorter TLS Lifetimes

  • Increased risk of missed renewals if teams rely on manual tracking

  • Broken environments due to expired certs in Azure, IIS, or Kubernetes configurations

  • Delayed deployments when certificates must be re-issued last minute

  • SEO and trust damage if browsers start flagging your site as insecure

How to Prepare Your Sitecore Project Teams

To stay ahead of the TLS certificate lifecycle changes, here are concrete steps you should take:

1. Inventory All TLS Certificates

  • Audit all environments and domains using certificates

  • Include internal services, custom endpoints, and non-production domains

  • Use a centralized tracking tool (e.g., Azure Key Vault, HashiCorp Vault, or a certificate management platform)

2. Automate Certificate Renewals

  • Wherever possible, switch to automated certificate issuance and renewal

  • Use services like:

    • Azure App Service Managed Certificates

    • Let’s Encrypt with automation scripts

    • ACME protocol integrations for Kubernetes

  • For Azure-hosted Sitecore instances, leverage Key Vault and App Gateway integrations

3. Establish Certificate Ownership

  • Assign clear ownership of certificate management per environment or domain

  • Document who is responsible for renewals and updates

  • Add certificate health checks to your DevOps dashboards

4. Integrate Certificate Checks into CI/CD Pipelines

  • Validate certificate validity before deployments

  • Fail builds if certificates are nearing expiration

  • Include certificate management tasks as part of environment provisioning

5. Educate Your Team

  • Hold knowledge-sharing sessions with developers, infrastructure engineers, and marketers

  • Make sure everyone understands the impact of expired certificates on the Sitecore experience

6. Test Expiry Scenarios

  • Simulate certificate expiry in non-production environments

  • Monitor behavior in Sitecore XP and XM environments, including CD and CM roles

  • Validate external systems (e.g., CDNs, integrations, identity providers) against cert failures

Final Thoughts

TLS certificate management is no longer a “set it and forget it” task. With shorter lifetimes becoming the norm, proactive planning is essential to avoid downtime and ensure secure, uninterrupted experiences for your users.

Start by auditing your current certificates and work toward automating renewals. Make certificate monitoring part of your DevOps practice, and ensure your Sitecore teams are aware of the upcoming changes.

Action Items for This Week:

  • Identify all TLS certificates in your Sitecore environments

  • Document renewal dates and responsible owners

  • Begin automating renewals for at least one domain

  • Review Azure and Sitecore documentation for certificate integration options

]]>
https://blogs.perficient.com/2025/04/18/how-the-change-to-tls-certificate-lifetimes-will-affect-sitecore-projects-and-how-to-prepare/feed/ 0 380286