# Gowthamaraja > Expert tutorials on Sitecore XM Cloud, Next.js, .NET, and AI integration. Real-world guides by Gowtham — a full-stack developer solving hard problems in the Sitecore ecosystem. Public Ghost content for AI and LLM tooling. This file includes a bounded export of public pages first, then recent public posts. Append `.md` to any post or page URL to get the content in Markdown (for example, `/example-post.md`). ## Pages ### About Gowthamaraja Eswaramoorthy URL: https://www.gowthamaraja.com/about/ Last updated: 2026-04-27T09:42:42.000Z Hey, I'm Gowtham, a Sitecore Architect and Senior Developer at [XCentium](https://www.xcentium.com/?ref=gowthamaraja.com), based in Tamil Nadu, India. I build solutions that sit at the intersection of modern CMS architecture, headless commerce, and emerging AI capabilities. I'm a **Sitecore Technology MVP (2024)**, a **commercetools Certified Composable Commerce Developer**, and co-founder of [SUGCBE](https://www.linkedin.com/groups/14208028/?ref=gowthamaraja.com), the Sitecore User Group for Coimbatore and the broader South India region. --- ## Professional Summary I've spent several years progressing through the full arc of the Sitecore ecosystem, from deep Sitecore XP implementations to leading headless SitecoreAI architectures on enterprise projects. At XCentium, I work with clients to design scalable, composable digital experience platforms using Sitecore, Next.js, and modern headless commerce stacks. My work regularly touches GraphQL API design, multisite deployments, Sitecore Marketplace SDK integrations, and AI agent patterns inside Sitecore's Agentic Studio. I like the hard problems, the ones that aren't in the docs. --- ## Key Skills and Expertise ### CMS and DXP - SitecoreAI, Sitecore XP (8.x through 10.x) - Sitecore JSS, SXA, Experience Editor - Headless architecture, multisite configuration, GraphQL API design - Sitecore Marketplace SDK and app publishing ### Headless Commerce - Commercetools (composable commerce) - Sitecore OrderCloud - Headless commerce integration patterns and API design ### Development Stack - Next.js, React, TypeScript - .NET / C#, REST and GraphQL APIs - OAuth 2.0, Azure App Services, Vercel deployments ### AI and Content Automation - AI Agents, RAG pipelines, and Agentic AI in CMS workflows - Sitecore Agentic Studio - LLM integrations for content automation and translation --- ## Certifications and Recognitions | Credential | Issuer | Year | | ----------------------------- | ------------- | ---- | | Sitecore Technology MVP | Sitecore | 2024 | | SitecoreAI CMS for Developers | Sitecore | 2025 | | Sitecore XM Cloud Developer | Sitecore | 2023 | | Composable Commerce Developer | commercetools | 2025 | Verify my credentials directly: - [Sitecore Technology MVP 2024](https://www.credly.com/badges/e3f757a8-f441-440d-923f-2af57141f531?ref=gowthamaraja.com) - [SitecoreAI CMS for Developers Certification (2025)](https://www.credly.com/badges/68394435-78f4-437e-9129-bfa7920a01e4/public%5Furl?ref=gowthamaraja.com) - [Sitecore XM Cloud Developer Certification (2023)](https://www.credly.com/badges/eba4d767-34ad-4134-a93f-c9916e0007a3/public%5Furl?ref=gowthamaraja.com) - [commercetools Certified Composable Commerce Developer (2025)](https://docs.commercetools.com/docs/learning/badges/db95dcf1147aa21ede59c47db0e63796ac94db6f?ref=gowthamaraja.com) --- ## What I've Built I'm the author of the **Universal Plug and Play Content Translation** app that helps teams automate multilingual content workflows inside SitecoreAI. Building and shipping it gave me ground-level experience with the Marketplace SDK, SitecoreAI APIs, OAuth 2.0 flows, and what it genuinely takes to get a production app into the hands of Sitecore editors. I've also written extensively about a v2 extension of that app, exploring a Coverage Dashboard and Bulk Campaign Translator as next-generation capabilities for enterprise content teams. --- ## Community Contributions I co-founded **SUGCBE**, the Sitecore User Group for Coimbatore, bringing together Sitecore practitioners across South India for knowledge sharing, hands-on workshops, and community building. This blog is part of that same commitment. I write about edge cases in SitecoreAI deployments, GraphQL quirks in multisite setups, Marketplace SDK patterns, and AI agent architectures applied to real Sitecore projects. No fluff, no recycled documentation. Just real implementation notes from the field. Topics I cover regularly: - SitecoreAI and JSS development - Sitecore Marketplace app development - AI Agents, RAG, and Agentic AI in CMS workflows - Practical Next.js patterns for headless Sitecore - Composable commerce with Commercetools and OrderCloud --- ## Let's Connect I'm most active on [LinkedIn](https://www.linkedin.com/in/gowthamarajaeswaramoorthy/?ref=gowthamaraja.com) and always open to connecting with other Sitecore developers, headless CMS architects, and anyone working in the composable commerce space. If you've found something useful here, subscribe below. I write when I have something genuinely worth sharing, not on a forced schedule. ### My Contribution to Sitecore - 2025 URL: https://www.gowthamaraja.com/my-contribution-to-sitecore-2025/ Last updated: 2025-11-25T10:44:05.000Z I’m excited to share and highlight my contributions to the Sitecore community throughout 2025! After a quieter 2024 due to personal commitments, I returned in 2025 with full focus and delivered consistent, high-impact, developer-centric contributions across modern Sitecore stack (XM Cloud, Sitecore AI, Search, Headless, Next.js). ## Key 2025 Contributions at a Glance - 5 in-depth technical blog posts with complete, reproducible code samples and local setup guides - Organized and hosted 5 high-quality SUGCBE virtual sessions featuring global MVPs and experts - Delivered 1 Public speaking events in Sitecore User Group - Daily active contributor on Sitecore Slack, Stack Exchange and LinkedIn (Sitecore-related posts/reposts) - Raised 2 official product-feedback tickets that were accepted/acted upon by Sitecore I remain deeply grateful for the 2024 recognition, and I would be honored to continue contributing to this vibrant community. --- ## **Technical Blogs (2025)** This year, I authored multiple technical blogs covering a wide range of Sitecore topics—Sitecore AI, XM Cloud, Headless, migration strategies, and more. Below is the full list: ### 1\. Migrating from JSS to Sitecore Content SDK 1.x in SitecoreAI (XM Cloud) – SDK Lifecycle Deep Dive A complete guide for migrating from JSS to Content SDK 1.x using PLAY! Summit on Next.js, including Node.js 22 fixes, pitfalls, and improvements. [Migrating from JSS to Sitecore Content SDK 1.x in SitecoreAI (XM Cloud) – SDK Lifecycle Deep DiveJSS to Content SDK 1.x migration using PLAY! Summit on Next.js: proven steps, Node.js 22 fixes, pitfalls & big wins for XM Cloud/SitecoreAI apps.![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/IMG_6818-5.JPG)GowthamarajaGowtham![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/IMG_1879-2-1.JPG)](https://www.gowthamaraja.com/migrating-from-jss-to-sitecore-content-sdk-1-x-in-sitecoreai-xm-cloud-sdk-lifecycle-deep-dive/) ### **2\. How to Integrate Gradial with Sitecore XM Cloud – AI-Powered Campaign Automation (2025)** Step-by-step tutorial on connecting Gradial to XM Cloud, API configuration, campaign automation, and troubleshooting. [How to Integrate Gradial with Sitecore XM Cloud: AI-Powered Campaign Automation Guide (2025)Full tutorial: Connect Gradial to XM Cloud, configure APIs, automate personalized campaigns, and troubleshoot common issues.![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/IMG_6818-6.JPG)GowthamarajaGowtham![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/Sitecore-Gradial-Lockup-2-1.webp)](https://www.gowthamaraja.com/how-to-integrate-gradial-with-sitecore-xm-cloud-a-practical-guide-for-faster-campaign-automation/) ### **3\. SitecoreAI & Sitecore Studio – A Game Changer for Developers** How SitecoreAI and Studio transform digital experience development with AI-driven workflows and composable SaaS. [SitecoreAI and Sitecore Studio: A Game-Changer for Developers in the Digital Experience SpaceSitecoreAI and Sitecore Studio redefine digital experience creation with AI-driven workflows, composable SaaS, and developer flexibility.![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/IMG_6818-7.JPG)GowthamarajaGowtham![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/SitecoreAI-logo-horizontal-black-txt-2-2.svg)](https://www.gowthamaraja.com/sitecoreai-and-sitecore-studio-a-game-changer-for-developers-in-the-digital-experience-space/) ### **4\. XM Cloud’s New Publishing Jobs Table UI & API** A breakdown of the new Publishing Jobs interface and REST API for automation, visibility, and optimization. [Sitecore XM Cloud Just Got the New Publishing Jobs Table UI and APISitecore XM Cloud’s new Publishing Jobs UI and REST API bring real-time tracking, automation, and control. Publish smarter, faster, easier.![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/IMG_6818-8.JPG)GowthamarajaGowtham![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/sitecore-xm-cloud-logo-1.webp)](https://www.gowthamaraja.com/sitecore-xm-cloud-just-got-the-new-publishing-jobs-table-ui-and-api/) ### **5\. How to Implement Bulk Deletion for Push Source Documents in Sitecore Search** Automate bulk deletion with PowerShell and skip manual Injection API steps. [How to Implement Bulk Deletion for Push Source Documents in Sitecore Search?Automate bulk document deletion in Sitecore Search with PowerShell. Skip manual Injection API steps and efficiently delete from Push Sources.![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/IMG_6818-9.JPG)GowthamarajaGowtham![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/sitecore-search-1.png)](https://www.gowthamaraja.com/how-to-implement-bulk-deletion-for-push-source-documents-in-sitecore-search/) --- ## **Sitecore User Group Coimbatore (SUGCBE) Contributions** I’ve been actively contributing to the community by organizing multiple sessions through **Sitecore User Group Coimbatore**. We bring experts from across the world to share knowledge and help developers stay updated with the latest in Sitecore. This year, we hosted **five high-quality sessions**, featuring both MVPs and non-MVPs. All recordings are available on our YouTube channel. Below is the event I presented this year. While it was a single session, I believe its depth, uniqueness, and quality made a strong impact on the audience. [LinkedIn Login, Sign in | LinkedInLogin to LinkedIn to keep in touch with people you know, share ideas, and build your career.![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/55ggxxse8uyjdh2x78ht3j40q-1)LinkedIn![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/favicon-1.ico)](https://www.linkedin.com/events/7396774870992392192/?ref=gowthamaraja.com) I also co-presented a session on **Sitecore XM Cloud** and **Gradial** with my friend **Prabhu Ranganathan**, where we discussed: - XM Cloud as the cloud-native future of Sitecore - “Gradual” – the intelligent migration strategy - Gradial – an AI-driven accelerator for content operations --- Below are key session highlights and LinkedIn announcements: - OpenAI API Integration in Sitecore [#sugcbe | Gowthamaraja EswaramoorthyJoin us for an exciting session organized by #SUGCBE on Integrating Open AI API Models in Sitecore! Artificial Intelligence is revolutionizing digital experience management, and this session will show you how. With AI adoption in enterprise software growing exponentially, Mohamed Sirajudeen will take you through the practical integration of ChatGPT within Sitecore CMS. Discover how to evaluate AI’s fit for your business needs, explore real-world use cases that simplify complex content management tasks, and witness live demonstrations of ChatGPT enhancing efficiency in content delivery. You’ll learn strategic approaches to AI integration, understand the tangible business value it brings, and see firsthand how AI can transform your Sitecore implementation beyond traditional capabilities. Don’t miss this opportunity to explore how AI integration can elevate your content management strategy and deliver exceptional digital experiences! Team SUGCBE: Prabhu Ranganathan Vignesh Jothikumar Event Sponsor: https://lnkd.in/gQWUrEsH Join us on WhatsApp for further updates: https://lnkd.in/geGw47iA![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/al2o9zrvru7aqj8e1x2rzsrca-8)LinkedInGowthamaraja Eswaramoorthy![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/c45fy346jw096z9pbphyyhdz7-7)](https://www.linkedin.com/posts/gowthamarajaeswaramoorthy%5Fsugcbe-activity-7396415679958171649-hBSN?ref=gowthamaraja.com) - XM Cloud & Gradial Deep Dive [#sugcbe | Gowthamaraja EswaramoorthyJoin us for an exciting #SUGCBE session on Sitecore XM Cloud & Gradial! Discover the future of Sitecore: cloud-native XM Cloud (the platform), “Gradual” (the smart migration strategy), and Gradial (the powerful AI accelerator for content operations). Learn the key differences, see real-world use cases, and watch live demos that show how these innovations boost productivity and deliver personalized experiences. Speakers: Prabhu Ranganathan, Gowthamaraja Eswaramoorthy Team SUGCBE: Prabhu Ranganathan, Gowthamaraja Eswaramoorthy, Vignesh Jothikumar Event Sponsor: https://lnkd.in/gQWUrEsH WhatsApp updates: https://lnkd.in/geGw47iA![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/al2o9zrvru7aqj8e1x2rzsrca-9)LinkedInGowthamaraja Eswaramoorthy![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/c45fy346jw096z9pbphyyhdz7-8)](https://www.linkedin.com/posts/gowthamarajaeswaramoorthy%5Fsugcbe-activity-7396774874536501248-LMp-?ref=gowthamaraja.com) - Session on Sitecore Search [| Gowthamaraja Eswaramoorthy![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/al2o9zrvru7aqj8e1x2rzsrca-10)LinkedInGowthamaraja Eswaramoorthy![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/c45fy346jw096z9pbphyyhdz7-9)](https://www.linkedin.com/posts/gowthamarajaeswaramoorthy%5Factivity-7368264839233720321-EU2v?ref=gowthamaraja.com) - XM Cloud Migration Tool – What’s New [#sugcbe | Gowthamaraja EswaramoorthyJoin us for an insightful session organized by #SUGCBE on XM Cloud Migration Tool: What’s New and Improved? Our Speaker Nehemiah Jeyakumar will takes you through the latest Sitecore XM to XM Cloud Migration Tool enhancements. We’ll examine key improvements, discuss how they streamline the migration process and compare the current version to its predecessor. Team SUGCBE: Prabhu Ranganathan, Vignesh Jothikumar Event Sponsor: https://lnkd.in/gQWUrEsH Join us on WhatsApp for further updates: https://lnkd.in/geGw47iA![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/al2o9zrvru7aqj8e1x2rzsrca-11)LinkedInGowthamaraja Eswaramoorthy![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/c45fy346jw096z9pbphyyhdz7-10)](https://www.linkedin.com/posts/gowthamarajaeswaramoorthy%5Fsugcbe-activity-7315309952313577472-aSE1?ref=gowthamaraja.com) - GenAI’s Untapped Potential for Sitecore [#sugcbe | Gowthamaraja EswaramoorthyJoin us for an insightful session organized by #SUGCBE on Challenging the Narrative: GenAI’s Untapped Potential for Sitecore beyond text and media! Discover how AI is transforming content management systems, with over 65% of organizations now regularly using generative AI (McKinsey, 2024). Pushpaganan N will guide you through AI’s evolution, Sitecore DXP integration strategies, and innovative approaches like training LLMs on your Sitecore Content Tree. You’ll learn about Sitecore Stream’s brand-aware AI capabilities and how to teach your agent to perform CRUD operations in Sitecore and much more. Don’t miss this opportunity to explore GenAI applications that go far beyond basic content creation and stay ahead of the digital experience curve! Team SUGCBE: Prabhu Ranganathan Vignesh Jothikumar Event Sponsor: https://lnkd.in/gQWUrEsH Join us on WhatsApp for further updates: https://lnkd.in/geGw47iA![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/al2o9zrvru7aqj8e1x2rzsrca-14)LinkedInGowthamaraja Eswaramoorthy![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/c45fy346jw096z9pbphyyhdz7-13)](https://www.linkedin.com/posts/gowthamarajaeswaramoorthy%5Fsugcbe-activity-7307364356420251648-zYNv?ref=gowthamaraja.com) --- ## Session Recordings: --- ## **Engagement** I stay consistently active across: - **LinkedIn** - **Sitecore Community Slack** - **Sitecore Stack Exchange** I regularly share insights, answer queries, and provide solutions based on my experience. My contributions help developers troubleshoot issues, adopt new features, and stay aligned with Sitecore’s evolving ecosystem. ### LinkedIn: [Gowthamaraja Eswaramoorthy - XCentium | LinkedInTechnical Lead | Sitecore Expert | Certified Sitecore 10, XM Cloud & OrderCloud… · Experience: XCentium · Education: Nandha Engineering College - Company · Location: Dharapuram · 500+ connections on LinkedIn. View Gowthamaraja Eswaramoorthy’s profile on LinkedIn, a professional community of 1 billion members.![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/al2o9zrvru7aqj8e1x2rzsrca-15)LinkedInGowthamaraja Eswaramoorthy![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/1599139029940-1)](https://www.linkedin.com/in/gowthamarajaeswaramoorthy/?ref=gowthamaraja.com) ### **Sitecore Stack Exchange:** This year, I raised three questions on [Sitecore Stack Exchange](https://sitecore.stackexchange.com/users/976/gowthamaraja-eswaramoorthy?ref=gowthamaraja.com) and actively contributed to the community. I also earned more reputation points compared to last year. In the coming year, I plan to focus more on answering questions to further support the Sitecore community. ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2025/11/image.png) --- ### Product Feedback & Support Tickets (2025) - **SEARCH-2130** – Documentation URL mismatch for Push Source deletion endpoint - **SXA-8754** – Feature request: Automatic Tailwind config propagation when switching site config - **PGS-3317 -** Ability to add custom classes to the new CKEditor within XM Cloud --- ## Goals for 2026 - Publish 12+ deep-dive, fully reproducible technical blogs (focus: Sitecore AI Agents, XM Cloud Deploy pipelines, Search v2, OrderCloud + XM Cloud) - Organize 10 SUGCBE sessions featuring global MVPs and new voices - Contribute pull requests to official Sitecore GitHub repositories (XM Cloud starters, SDK samples) - Mentor at least 3 aspiring community members toward their first MVP nomination - Continue daily Slack/Stack Exchange support and grow SUGCBE YouTube channel to 5,000+ subscribers I am immensely grateful for the 2024 Technology MVP award and the continued support from the global Sitecore community. I remain fully committed to helping developers master modern Sitecore solutions through practical, code-first content and real-world guidance. Happy learning!! Happy sharing!! ## Posts ### Building with Sitecore Agentic Studio: A Developer's Deep Dive URL: https://www.gowthamaraja.com/sitecore-agentic-studio-developer-deep-dive/ Last updated: 2026-04-30T07:28:38.000Z I recently published a post on the XCentium blog covering what Sitecore Agentic Studio is, the types of agents available, and how marketing teams can use it. If you haven't read that yet, its a good starting point for the full picture. This post is the extended version. Its written specifically for developers who want to go beyond the overview and actually build something. I'll cover what I learned hands-on while building workflow agents inside Agentic Studio, the real problems I hit, how I solved them, and the decisions I'd make differently now. This post extends the original article published at [XCentium](https://www.xcentium.com/blogs/sitecore-agentic-studio-how-ai-agents-are-changing-the-way-we-build-and-market-with-sitecore?ref=gowthamaraja.com). ## What I Built and Why To get hands-on with Agentic Studio, I built a content brief generator. The use case is something most Sitecore teams deal with regularly. A content strategist needs a structured brief before any page or campaign asset goes into production. Collecting the right inputs, formatting them consistently, and making sure nothing is missed is repetitive work that's pretty easy to automate. The idea was simple. Give the agent a topic, a target audience, and a few context inputs, and get back a fully structured content brief ready for the team to work from. No back and forth, no inconsistent formats, no missing fields. What I thought would take a few hours ended up teaching me a lot more than I expected about how Agentic Studio actually behaves under the hood. ## Choosing the Right Agent Type The first real decision you'll make as a developer is which agent type to use. The XCentium post covers all three at a high level. Here's how I actually think about the choice from a builder's perspective. **Standard agents** are conversational. They're flexible and respond dynamically, but that flexibility works against you when you need a repeatable, structured output every single time. For anything with a fixed pipeline, a standard agent will drift. Users can steer it in unexpected directions and the output format becomes inconsistent. **Workflow agents** are structured pipelines. You define the steps, the data flows, and the output format explicitly. There's very little room for the agent to go off script because you're controlling the execution path with the Workflow Editor. For a content brief generator, Workflow was the obvious choice. I needed the same structure every single time. Consistent sections, consistent formatting, no conversational drift. My rule of thumb now is this. If you're building something a user will run repeatedly with structured inputs and need predictable outputs, use a Workflow agent. If you're building something exploratory where the user needs to ask follow-up questions and collaborate with the agent across multiple turns, use a Standard agent. ## Building the Workflow: Step by Step Here's how I structured the content brief generator workflow. ### Step 1: Context Parameters The first action in almost every workflow I build now is a Context Parameters step. This is where you extract and normalize user input before passing it anywhere else. The user provides the topic, target audience, campaign goal, and any additional context. The Context Parameters step extracts these into a structured format, validates that required fields are present, and normalizes any inconsistencies in how different users might phrase their inputs. Getting this step right saves you a lot of headaches later. If your downstream Content Generation steps receive inconsistent input, your outputs will be inconsistent too. Treat this like input validation in application code. ### Step 2: Research and Context Enrichment Before generating the brief, I added a Research step that enriches the user's input with relevant context. This might include pulling in relevant keyword data, understanding the competitive landscape for the topic, or identifying the right content format for the audience. This is a separate step from the final output generation. I found that asking a single step to both research and format everything at once produced lower quality results than breaking it into two focused steps. The model does better when each step has a single, clear responsibility. ### Step 3: Output Generation with JSON Schema This is where most of my early pain came from. The output generation step takes the enriched context and produces the formatted brief. I configured it with a JSON schema to enforce a structured output, because I wanted to render the brief through a HTML template downstream. Here's the problem I ran into. The model I was using kept ignoring the schema. It would add conversational text before and after the JSON, include markdown code fences around it, or just produce free-form text that looked like a brief but wasn't valid JSON. I tried tightening the system prompt first. I added explicit instructions like "respond only with valid JSON, no preamble, no markdown, no explanation." It helped partially but wasn't fully reliable. The real fix came from two changes. First I switched to a different model that respected structured output constraints more consistently. Second I rewrote the system prompt to be much more explicit, specifying the exact schema fields, what each field should contain, the expected data types, and what the agent should do if a field had no data. The lesson here is worth repeating. The model you select matters a lot. The faster models are tempting because the workflow runs quicker, but if your use case depends on strict output formatting, test your schema enforcement carefully before committing to a model. A slower, more controlled model that produces reliable JSON is worth more than a fast model that requires manual cleanup. ### Step 4: Conditional Sections One thing I added later was a Flow Control step that checks whether certain optional inputs were provided. If the user didn't supply competitive context, that section of the brief is skipped entirely rather than rendering an empty placeholder. This kind of conditional logic is where Workflow agents start feeling genuinely powerful. You're not just prompting an AI. You're building a real pipeline with branching logic, and the output adapts based on the actual data coming in. ### Step 5: HTML Template Rendering The final step passes the structured JSON through a HTML template that produces a clean, formatted brief document. The template handles all the visual structure so the output is ready to share or drop into a project management tool directly. One practical tip here. Keep your HTML template simple. I initially tried to make it too clever, with conditional rendering inside the template itself. That gets complicated fast. Better to push the conditional logic into Flow Control steps upstream and keep the template as a straightforward renderer. ## Prompt Engineering is Production Code This is the thing I underestimated most going in. In a standard application, you write code, test it, and deploy it. Your business logic lives in the code and behaves predictably because code does exactly what you write. In an Agentic Studio workflow, a significant part of your business logic lives in your prompts. And prompts don't behave like code. They're instructions to a probabilistic model, which means the same prompt can produce slightly different outputs on different runs, and a prompt that works with one model may not work with another. Here's how I now approach prompts in Agentic Studio workflows. **Be specific about format.** Don't say "format the output as JSON." Say exactly what the JSON should look like, field by field, including what to do when a field has no data. **Use plain language, not jargon.** I initially wrote prompts in technical shorthand. Switching to plain, explicit instructions improved consistency significantly. **Tell the model what not to do.** "Do not add any text before or after the JSON object. Do not wrap the output in markdown code fences. Do not include any explanation." Explicit negative instructions really help here. **Version your prompts.** Copy your working prompt somewhere before you change it. I learned this the hard way after a quick tweak made things worse and I couldn't remember what the previous version said. **Test with edge cases early.** What happens when the user skips an optional field? What if the topic is too vague to research meaningfully? Test those cases before you consider the workflow done. ## When to Chain Agents The content brief generator is a single workflow agent. But Agentic Studio also supports chaining agents together, where the output of one agent becomes the input of the next. I can see exactly where chaining would apply for more complex use cases. Imagine a pipeline where: 1. A Research agent pulls market data, competitor content, and keyword opportunities for a given topic 2. A Brief Generator agent takes that research and produces a structured content brief 3. A QA agent checks the brief against a brand style guide and flags anything that doesn't meet the standards That's a multi-agent flow, and each agent in that chain has a single responsibility. Its the same principle as clean code. Small, focused components that compose well are easier to build, debug, and improve than large monolithic ones. ## MCP Integration: The Part That Changes Everything The Sitecore Marketer MCP server is worth paying attention to if you haven't looked at it yet. MCP, or Model Context Protocol, is the standard that allows agents to connect with external tools and data sources. With the Marketer MCP, agents can interact directly with SitecoreAI workflows, which means you can start bridging Agentic Studio with the broader Sitecore ecosystem. The scenarios this unlocks are significant. An agent that pulls content from Content Hub, enriches it with CRM context, and pushes it back into a workflow is no longer science fiction. Its a configuration problem. The plumbing is already there. For developers, this is the area I'd invest time in understanding deeply. The Agent API and MCP integrations are where Agentic Studio stops being a standalone tool and starts becoming an orchestration layer for your entire Sitecore stack. ## Become a Sharper Sitecore Developer ****Join a growing community of Sitecore developers**. Get practical XM Cloud and SitecoreAI content straight to your inbox. Certification tips, Architecture deep dives, and things the official docs don't tell you. Subscribe Email sent! Check your inbox to complete your signup. No spam. Unsubscribe anytime. ## Things I'd Do Differently Looking back at my first workflow agent builds, a few things stand out as lessons I'd apply from day one next time. **Start with the output and work backwards.** Before building a single workflow step, I'd define exactly what the final output should look like. Then I'd design the workflow to produce that output. I did the opposite initially and ended up refactoring the middle steps multiple times. **Don't fight the model, change the model.** When a model consistently ignores your constraints, switching models is faster than trying to out-prompt the problem. I spent too long trying to force one model to behave before I just switched to something that actually respected the schema. **Use descriptive action names.** The Workflow Editor shows action names in the canvas. When you have ten steps and they're all named "Content Generation 1," "Content Generation 2," debugging becomes really painful. Name every action to reflect what it actually does. **Build and test one step at a time.** Its tempting to build the whole workflow and then test it end to end. Don't. Add one step, test it with real inputs, confirm the output is what you expect, then add the next step. This makes debugging much faster. ## Where to Start If You Haven't Yet If you're a Sitecore developer who hasn't touched Agentic Studio yet, here's where I'd suggest starting. Run the built-in agents first. The Bulk Content Generator and AEO/SEO Researcher are solid examples of well-structured agents. Running them and looking at the inputs they accept and the outputs they produce gives you a good mental model of what a well-designed workflow looks like before you build your own. Then build something small. A content formatter, a brief generator, or a simple summarizer. Something with two or three workflow steps that you can get working quickly. The goal is to get your hands on the Workflow Editor and understand how variable passing works in practice. Once you've done that, you're ready to build something real. The learning curve is manageable. The upside in terms of speed, consistency, and scale is genuinely significant. And right now very few Sitecore developers are building here, which means there's a real first-mover advantage for those who invest the time. Good luck, and feel free to connect with me on LinkedIn if you're building with Agentic Studio and want to compare notes. [LinkedIn ](https://linkedin.com/in/gowthamaraja?ref=gowthamaraja.com) ### The Sitecore AI CMS Developer Certification is Easier Than You Think URL: https://www.gowthamaraja.com/sitecore-ai-cms-developer-certification/ Last updated: 2026-04-24T08:59:49.000Z I recently cleared the **Sitecore AI CMS Developer Certification**, and if you're an XM Cloud developer eyeing this one, I have good news for you. It's very achievable. This post covers what the exam looks like, what competency areas to focus on, and a few tips straight from my exam day experience. ## In this Article 1. [What Is the Sitecore AI CMS Developer Certification?](#what-is-the-sitecore-ai-cms-developer-certification) 2. [Exam Structure](#exam-structure) 3. [The 9 Competency Areas](#the-9-competency-areas) 4. [My Tips From Exam Day](#my-tips-from-exam-day) 5. [Should You Take It?](#should-you-take-it) 6. [Key Points to Remember Before Your Exam](#key-points-to-remember-before-your-exam) 7. [Final Thoughts](#final-thoughts) ## What Is the Sitecore AI CMS Developer Certification? This is Sitecore's developer certification for the SitecoreAI CMS platform, which is the next evolution of XM Cloud that brings AI-native capabilities directly into the authoring, content modelling, and developer workflow experience. If you've worked on XM Cloud or JSS projects, a lot of this terrain will feel familiar. The official learning path is available at: [Sitecore Learning - Introduction to SitecoreAI](https://learning.sitecore.com/partners/learn/learning-plans/130/introduction-to-sitecoreai?ref=gowthamaraja.com) ## Exam Structure Before diving into the content areas, here's what to expect logistically: - **60 questions** across 9 competency areas - **2 hours** to complete - **80% passing score** (you need 48 out of 60 correct) - **Online proctored** \- you will be monitored throughout the entire exam session, so have your environment ready before you start Prepare your space, your ID, and your setup before you hit "Begin." Don't leave that to the last minute. ## The 9 Competency Areas The exam covers the following domains. The weightings below are taken from the [official exam page](https://shop.learning.sitecore.com/products/01tHu00000QPOa9IAH?ref=gowthamaraja.com) and tell you exactly where to focus your study time. I've added my own notes based on what came up in my exam. **1\. SitecoreAI CMS Architecture and Developer Workflow (6%)** Covers the overall platform architecture and how developers set up and work within the SitecoreAI ecosystem. If you understand XM Cloud's headless-first architecture, environment setup, CLI, and the developer loop, you're already ahead here. Its a smaller slice of the exam so don't over-index on it. **2\. Deployment of SitecoreAI CMS Projects (10%)** Focuses on deploying SitecoreAI projects to cloud environments. Think CI/CD pipelines, environment variables, and deploy hooks. Experience with Vercel-based deployments for XM Cloud projects will serve you well. **3\. Sitecore APIs and Webhooks (15%)** One of the heavier sections. Practical experience pays off here. Understanding the Edge Delivery APIs, GraphQL endpoint structures, and how webhooks trigger workflows in response to content events will help you navigate the scenario-based questions. **4\. Content Modelling (17%)** One of the three highest weighted areas. Know your templates, template inheritance, and how content models translate to component datasource structures in a headless context. This area had some nuanced scenario questions in my exam so spend good time here. **5\. Renderings and Layout (17%)** Another high weight area. Covers how renderings are defined and how layout is managed in the SitecoreAI Pages editor. Component Variants came up in my exam, so make sure you understand how variants are configured and surfaced in Pages. **6\. SitecoreAI CMS Pages (6%)** The Pages editor is central to the SitecoreAI authoring experience. Questions here touch on how Pages works, how authors interact with it, and how developers support it. If you've worked hands-on in the Pages editor, this section should feel comfortable. Smaller weighting but don't skip it. **7\. Web Development with SitecoreAI CMS (17%)** Tied for the highest weighting along with Content Modelling and Renderings. Covers JSS integration, Next.js implementation patterns, and SSG (Static Site Generation), which was explicitly tested in my exam. Make sure you understand the rendering strategies available in Next.js-based Sitecore projects and when each one applies. **8\. Sitecore Content Serialization (6%)** Smaller weighting but the questions here are precise. Know your serialization configuration files, what goes in `sitecore.json`, how modules are defined, and how items are included or excluded. The configuration syntax matters. **9\. Security for Developers (6%)** Covers API key management, environment-level security considerations, and access control patterns relevant to developers. Not the heaviest section, but don't skip it. The three areas you should spend the most time on are Content Modelling, Renderings and Layout, and Web Development with SitecoreAI CMS. Together they make up 51% of the exam. ## My Tips From Exam Day **Read every question twice.** I cannot stress this enough. During my exam, I answered one question incorrectly on my first pass. When I came back to review it, I noticed a single qualifier in the question, just one word, that completely changed the right answer. I caught it and corrected it, but it was a good reminder that these questions are precise by design. Slow down and read carefully. **Use the review mode.** The exam allows you to flag and review questions. Use it. You have two full hours for 60 questions, so there's no need to rush. Flag anything you're uncertain about and revisit before submitting. **Don't panic.** If you've shipped XM Cloud or SitecoreAI projects, you already know the material. The exam tests practical understanding, not memorization of obscure documentation. Trust your experience. **Go through the official learning material.** Some questions are drawn directly from the Sitecore Learning portal content. Working through it before the exam is worth the time, not just for those specific questions, but because it fills in gaps you might have from relying solely on hands-on project work. ## Become a Sharper Sitecore Developer ****Join a growing community of Sitecore developers**. Get practical XM Cloud and SitecoreAI content straight to your inbox. Certification tips, Architecture deep dives, and things the official docs don't tell you. Subscribe Email sent! Check your inbox to complete your signup. No spam. Unsubscribe anytime. ## Should You Take It? If you're actively working on XM Cloud or SitecoreAI projects, yes, take the exam. The certification validates knowledge you already have, the content maps closely to real project work, and it carries genuine signal in the Sitecore partner ecosystem. If you've already cleared the **Sitecore XM Cloud Developer Certification**, this one will feel like a natural next step. Most of the architecture, tooling, and deployment concepts overlap. The SitecoreAI certification builds on that foundation rather than replacing it. ## Key Points to Remember Before Your Exam Here are some of the concepts that are worth locking in before you sit the exam. These come from my own experience going through the material, with a few pointers from the Sitecore community as well. Varalakshmi from [V-In Sitecore](https://vinsitecore.wordpress.com/2026/02/18/sitecore-ai-cms-developer-certification/?ref=gowthamaraja.com) also put together a solid revision sheet that's worth reading alongside the official learning material. **Architecture and Deployment** - XM Cloud environments can be created via the Deploy App, CLI, or REST API - The deployment lifecycle follows this order: Provision, Build, Deploy, Post-actions - XM Cloud hierarchy goes Organization, then Project, then Environment - Default frontend framework is React JS - CLI deployment is the way to go when your organisation doesn't use GitHub for source control **Serialization** - Serialization field exclusions are configured in `sitecore.json` or module configuration files - The `Scope` property controls child item inclusion and defaults to `ItemAndDescendants` - The `pull` command serializes items into YAML files - Use `validate` to check and auto-correct serialization integrity - Missing module path means items won't be serialized, so double check your paths **Content Modelling** - Templates must live under `/sitecore/templates` to appear in the Experience Edge schema - Modifying templates after content has been created can cause data loss, be careful here - Standard values control layout, workflow, tokens, and insert options - Cyclic inheritance is a known cause of missing fields, worth knowing for scenario questions **GraphQL and APIs** - Experience Edge GraphQL is read-only for frontend delivery - Authoring API item creation uses the `createItem` mutation - Authorization errors usually mean an invalid API key header - Pagination in GraphQL uses `first` with a default value of 10 - To view or create webhooks you need a developer or admin role - There are three webhook types: event handler, submit action, and validation action **Renderings and Layout** - Do not add components directly to page designs, they won't render. Use partial designs instead - Placeholder restrictions apply to all pages using that placeholder, not just one - Missing header or footer usually means a partial design hasn't been assigned - Headless variants let you create multiple visual styles from a single component **Security** - Assign permissions to roles rather than individual users - A security account can only belong to one domain - To show hidden items in Content Editor you need Administrator, Sitecore Client Developing, or Sitecore Client Maintaining role - Authoring and Management APIs require the Sitecore Client Users role These aren't exhaustive but they cover the areas I found most tested in scenario-based questions. Go through the official learning path too, some questions pull directly from that content. ## Final Thoughts The Sitecore AI CMS Developer Certification is a well-structured exam that rewards practical, hands-on Sitecore experience. It's not a trick exam. It's a fair test of whether you understand how to build, deploy, and maintain SitecoreAI projects as a developer. Go through the official learning plan, brush up on serialization configs, SSG rendering strategies, and component variants, and you'll be in good shape. Good luck, and feel free to connect with me on LinkedIn if you have questions before your exam. [LinkedIn ](https://linkedin.com/in/gowthamaraja?ref=gowthamaraja.com) ### Building a Content Scheduling Marketplace App for XM Cloud URL: https://www.gowthamaraja.com/xm-cloud-content-scheduling-marketplace-app/ Last updated: 2026-04-13T03:06:47.000Z I kept getting pinged by marketers asking me to manually publish pages at specific times. XM Cloud has `__Publish Date` and `__Unpublish Date` fields on every item, but writing to them alone doesn't do anything you still need to trigger a publish job separately. And marketers can't do either without developer help. So I built a Marketplace App that adds a scheduling panel directly inside XM Cloud Pages. Pick a date, click publish, done. ![Scheduling panel inside XM Cloud Pages](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/04/image-1.png) Scheduling panel inside XM Cloud Pages Code is [on GitHub](https://github.com/GowthamPersonal/content-scheduling-marketplace-app?ref=gowthamaraja.com). This post covers how it works and what tripped me up. --- ## Quick Answer: How Does Content Scheduling Work in XM Cloud? > **Short version:** Write `__Publish Date` to the item. For a future date, the panel saves the schedule to `localStorage` and sets a client-side timer. When the timer fires, it calls `publishItem` only then does the item reach Experience Edge. For a past date, `publishItem` is called immediately. The scheduling is enforced by the browser timer, not by Experience Edge. --- ## How Does Scheduled Publishing Actually Work in XM Cloud? The key thing to understand: `__Publish Date` does **not** trigger a publish. It is just a field. **The schedule fields:** | Field | GUID | | ------------------ | -------------------------------------- | | \_\_Publish Date | {D9CF14B1-FA16-4BA6-9288-E8A174D4D522} | | \_\_Unpublish Date | {975170FC-3DC4-4CAE-BF03-634DB8B73D11} | These are standard fields on every Sitecore item. Writing to them stores metadata. Nothing else happens. **The actual publish:** You need to call the `publishItem` mutation on the Authoring GraphQL API. That sends a job to the Publishing Engine, which pushes content to Experience Edge. Without that mutation, the date fields are decoration. **The complete flow:** 1. Write `__Publish Date` / `__Unpublish Date` to the item via `updateItem` 2. If the date is in the future: save to `localStorage`, start a client-side timer 3. When the timer fires (or on page reload if the tab was closed): call `publishItem` > **How the scheduling actually works:** `publishItem` is deliberately not called immediately for future dates doing so would push the item to Experience Edge right away, with no delay. Instead, the panel holds the schedule client-side: a `setTimeout` fires `publishItem` at the exact scheduled time. If the tab is closed before then, `localStorage` records the pending schedule; on next reload the panel detects the missed time and triggers `publishItem` immediately. Experience Edge is not what enforces the schedule the browser timer is. This means the publish only happens reliably if the panel is open (or gets reopened) around the scheduled time. --- ## What Is the App Architecture? Three layers, two APIs: ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/04/OrderCreated-Email-Flow-2026-04-12-053426.png) The React panel uses the Marketplace SDK to read and write item fields. For publish jobs that need a CM token, it goes through a Next.js API route that handles token exchange server-side. Tokens never reach the browser. --- ## How Does Authentication Work in a Marketplace App? The Marketplace SDK proxies all HTTP calls through the host XM Cloud window via `postMessage`. The token lives in the host your app never sees it. That is why `xmc.authoring.graphql` mutations just work without any token setup on your end. One SDK method for both reads and writes. The SDK exposes a single `client.mutate("xmc.authoring.graphql", ...)` method for the Authoring GraphQL channel it handles both queries and mutations. There is no separate `client.query()` path for Authoring GraphQL. The `params.body` takes the standard `{ query, variables }` GraphQL request shape regardless of operation type. Where you **do** need a token: checking the status of a specific publish job by operation ID. That is handled server-side with a `client_credentials` exchange: [**src/lib/publishing.ts**](https://git+.vscode-resource.vscode-cdn.net/c%3A/1-Playground/marketplace/content-scheduling-marketplace-app/src/lib/publishing.ts?ref=gowthamaraja.com) ```typescript let tokenCache: CachedToken | null = null; export async function getAccessToken( clientId: string, clientSecret: string, ): Promise { const now = Date.now(); if (tokenCache && tokenCache.expiresAt - now > 30_000) { return tokenCache.accessToken; } const response = await fetch("https://auth.sitecorecloud.io/oauth/token", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ client_id: clientId, client_secret: clientSecret, audience: "https://api.sitecorecloud.io", grant_type: "client_credentials", }), }); const data = await response.json(); tokenCache = { accessToken: data.access_token, expiresAt: now + (data.expires_in ?? 86400) * 1000, }; return tokenCache.accessToken; } ``` The 30-second buffer means you almost always hit cache. First request per server process pays the \~200ms exchange cost; everything after is free. Your `.env.local`: ``` PUBLISHING_API_URL=https://xmc-yourinstance.sitecorecloud.io AUTOMATION_CLIENT_ID=your-client-id AUTOMATION_CLIENT_SECRET=your-client-secret ``` Get these from XM Cloud Portal → your environment → Automation. --- ## How Do You Write Schedule Fields and Trigger a Publish? **Step 1: Write the schedule fields:** ```typescript const UPDATE_ITEM_SCHEDULE_MUTATION = /* GraphQL */ ` mutation UpdateItemScheduleFields( $itemId: ID! $language: String! $version: Int! $fields: [FieldUpdateInput!]! ) { updateItem( input: { itemId: $itemId language: $language version: $version fields: $fields } ) { item { id name } } } `; ``` **Step 2: Trigger the publish:** ```typescript function buildPublishItemMutation( publishMode: "SMART" | "FULL", publishSubItems: boolean, ) { return /* GraphQL */ ` mutation PublishItem( $rootItemId: ID! $languages: [String!]! $targetDatabases: [String!]! ) { publishItem(input: { rootItemIds: [$rootItemId] languages: $languages targetDatabases: $targetDatabases publishItemMode: ${publishMode} publishSubItems: ${publishSubItems} publishRelatedItems: false }) { operationId } } `; } ``` --- ## How Do You Handle Timezones in a Scheduling UI? `datetime-local` inputs return values like `2026-04-10T09:00` no timezone info at all. If you pass that directly to your API, you have no idea what timezone the user was in. **Fix:** treat it as the user's local time, convert to UTC immediately, store UTC. ```typescript // User picks 9:00 AM local (e.g. BST = UTC+1) const localString = "2026-04-10T09:00"; // parseISO treats this as local time, formatISO adds the offset const utcIso = formatISO(parseISO(localString), { representation: "complete" }); // → "2026-04-10T08:00:00+00:00" ``` Displaying it back: `parseISO` respects the stored offset and `format` renders in the browser's local timezone automatically. ```typescript format(parseISO("2026-04-10T08:00:00Z"), "yyyy-MM-dd'T'HH:mm"); // → "2026-04-10T09:00" (in a BST browser) ``` Use `date-fns` for both directions and this stops being a problem. --- ## How Do You Show Version and Publish Status? The Marketplace SDK's `pages.context` subscription gives you `isLatestPublishableVersion` directly on `pageInfo`. No extra query needed. ```typescript client.query("pages.context", { subscribe: true, onSuccess: (res: PagesContext) => setPagesContext(res), }); ``` The panel uses this to show two states: - **`v3` · `Published`** \- this version is live on Experience Edge - **`v3` · `Unpublished changes`** \- there are edits that have not been pushed Editors stop asking "is my draft live?" which accounts for most scheduling-related support requests. ![Published vs unpublished version badge](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/04/image-3.png) Published vs unpublished version badge --- ## What Happens If the Publish Date Is in the Past? `publishItem` publishes immediately regardless of what date you write to `__Publish Date`. So if an editor enters a date that has already passed, the item publishes the moment they click the button with no delay. The panel detects this and shows a warning before the editor submits: ```tsx {publishDateInPast && (
This date is in the past. The item will publish immediately when you click Schedule Publish.
)} ``` The success message also distinguishes between a future-dated and a past-dated submit: ```typescript const scheduledFor = isPast(schedule.publishDate) ? `${format(schedule.publishDate, "PPpp")} - published immediately (date is in the past)` : format(schedule.publishDate, "PPpp"); ``` This is especially useful for editors migrating existing content who might set historical dates accidentally. --- ## Does It Support Publishing Child Items? Yes. Default is single item only most scheduling is for one page and you do not want to kick off a full subtree publish every time. But sometimes you do, so there is a checkbox: ```tsx setPublishSubItems(e.target.checked)} /> ``` Maps directly to `publishSubItems: true/false` in the mutation. --- ## Setup ```bash git clone https://github.com/gowthamaraja/xmc-content-scheduler.git cd xmc-content-scheduler npm install ``` `.env.local`: ``` PUBLISHING_API_URL=https://xmc-yourinstance.sitecorecloud.io AUTOMATION_CLIENT_ID=your-automation-client-id AUTOMATION_CLIENT_SECRET=your-automation-client-secret ``` ```bash npm run dev ``` To use inside XM Cloud Pages: deploy to Vercel (or any Next.js host), then register the app in the Sitecore Marketplace with your Pages Context Panel extension point URL. **Project structure:** ``` src/ ├── app/ │ ├── api/publish/ │ │ ├── trigger-job/route.ts ← publish mutation + token exchange │ │ └── job-status/route.ts ← publishing status query │ ├── pages-contextpanel-extension/page.tsx │ └── layout.tsx ├── components/ │ └── SchedulerPanel.tsx ← the panel UI ├── lib/ │ ├── publishing.ts ← GraphQL + token logic │ └── utils.ts └── utils/ └── hooks/ └── useMarketplaceClient.ts ← SDK init with retry + singleton ``` --- ## What Is Missing / What Could Be Added? - **Server-side schedule persistence:** the panel currently uses `localStorage` to remember the scheduled date across page reloads. This is browser-local, not multi-user, and silently breaks in strict iframe/cookie contexts. A lightweight server-side key-value store (e.g. Vercel KV) exposed via an API route would make the state persistent, multi-user, and browser-independent without requiring any changes to the Sitecore content template. Tracked as a future improvement. - **Unpublish enforcement:** `__Unpublish Date` is stored and respected by Experience Edge, but this app has no reminder or audit trail for upcoming unpublish events. A background job or webhook that alerts editors when content is about to expire would round this out. - **Approval workflow:** hook into XM Cloud workflow states before allowing a schedule. - **Bulk scheduling:** schedule multiple items from a list view. --- ## Can I Reschedule a Published Item? Yes and it works without any extra code. The panel does not lock after a successful schedule. **How it works:** 1. After clicking Schedule Publish, the success alert appears but the date inputs remain editable. 2. Change the publish date (or unpublish date). The moment you do, the success state clears and the Schedule Publish button re-activates. 3. Click Schedule Publish again. The panel overwrites `__Publish Date` on the item with the new date and fires a fresh `publishItem` job. **One thing to understand:** if the original publish date was in the future, `publishItem` has not fired yet the item has not reached Experience Edge. Rescheduling overwrites `__Publish Date` on the item, clears the old timer, saves the new date to `localStorage`, and starts a fresh countdown. The new `publishItem` call will fire when the updated date arrives. **What the code does under the hood:** ```typescript // handlePublishDateChange resets status on every edit after a successful schedule function handlePublishDateChange(value: string) { setSchedule((prev) => ({ ...prev, publishDate: parseDatetimeLocal(value) })); if (status.type === "success" || status.type === "error") { setStatus({ type: "idle" }); // ← re-enables the Schedule Publish button } } ``` The button's disabled state is `!canSchedule`, and `canSchedule` is true as long as a publish date is set and no request is in flight so any edit after success immediately re-enables it. --- ## Frequently Asked Questions #### ****Does** **`__Publish Date`** **automatically trigger a publish in XM Cloud?** No. `__Publish Date` is a metadata field. It stores the intended publish date but does not trigger anything. You must call the `publishItem` mutation separately to push the item to Experience Edge. #### ****What is the correct** **`targetDatabases`** **value for XM** Always `["experienceedge"]`. XM Cloud does not have a "web" or "master" target database for publishing. Using anything else results in a 500 error about missing database configuration. #### ****Can I call** **`publishItem`** **from the browser directly?** Not in this implementation. `publishItem` requires a CM Bearer token, which must be obtained server-side via a `client_credentials` exchange. This app routes it through a Next.js API route (`/api/publish/trigger-job`) that handles the token exchange and fires the mutation. The Marketplace SDK proxy (which handles auth transparently via `postMessage`) is used only for `updateItem` field reads and writes that don't need a separate token. #### ****Why does my GraphQL mutation fail with a type mismatch on** **`publishItemMode`** **?** `publishItemMode` is a GraphQL enum (`SMART`, `FULL`), not a string. You cannot pass it as a variable, it must be inlined into the mutation string. #### ****How do I get the Automation Client ID and Secret for XM Cloud?** Go to XM Cloud Portal → select your environment → Automation. The client ID and secret for `client_credentials` token exchange are generated there. #### ****Can this app do true scheduled publishing (e.g. publish at a future time automatically)?** Yes, with an important caveat: scheduling is enforced client-side, not server-side. When you pick a future date and click Schedule Publish, the panel writes the date fields to the item and sets a browser `setTimeout`. When the timer fires, it calls `publishItem` only then does the item reach Experience Edge. If the panel tab is closed before the scheduled time, the publish won't fire until an editor reopens the panel (the missed schedule is detected via `localStorage` and the job triggers on reload). For guaranteed unattended publishing you would need a server-side cron job that calls `publishItem` at the right time. #### ****Can I reschedule an item after it has already been scheduled?** Yes. The panel does not lock after a successful schedule, the date inputs stay editable. Change the publish (or unpublish) date, and the button re-activates. Clicking Schedule Publish again overwrites `__Publish Date` on the item and triggers a new publish job with the updated date. See the "Can I Reschedule a Published Item?" section above for the full walkthrough. #### ****What happens if I enter a publish date that is already in the past?** The panel detects this and shows a warning before you submit. When you click Schedule Publish, the item is published immediately (not at the past date). The success message also notes "published immediately (date is in the past)" so there is no ambiguity. #### ****Why does** **`client.mutate()`** **handle both queries and mutations?** The Marketplace SDK exposes a single `client.mutate("xmc.authoring.graphql", ...)` method for the Authoring GraphQL channel. It accepts a standard `{ query, variables }` body and works for both read and write operations. There is no separate `client.query()` path. --- The patterns here SDK proxy for field mutations, server-side token exchange, `"experienceedge"` as the only publish target apply to any Marketplace App touching the publishing layer. Code is open in [Github](https://github.com/GowthamPersonal/content-scheduling-marketplace-app?ref=gowthamaraja.com). Fork it, raise issues, send PRs. If you are building something in the Marketplace ecosystem or running into scheduling pain on XM Cloud, drop a comment or reach out on [LinkedIn](https://linkedin.com/in/gowthamaraja?ref=gowthamaraja.com). ### LLM vs RAG vs AI Agent vs Agentic AI - What's Actually Different? URL: https://www.gowthamaraja.com/llm-vs-rag-vs-ai-agent-vs-agentic-ai/ Last updated: 2026-04-22T09:00:28.000Z ## LLM vs RAG vs AI Agent vs Agentic AI - What's Actually Different? Every week there's a new term flying around LinkedIn, Twitter, and tech blogs. LLM, RAG, AI Agents, Agentic AI... and unless you've been deep in this space, it can feel like everyone else is in on a secret you're not. But here's the thing - these aren't just marketing buzzwords. They represent genuinely different architectures, different capabilities, and very different cost profiles. Understanding the distinction will make you a sharper developer, a better decision-maker, and honestly, just someone who knows what they're talking about at the next team meeting. So let's cut through the noise. --- ## The One Analogy to Rule Them All: The Office Hiring Scenario Before I throw definitions at you, I want you to picture something. You're a company that needs to handle customer inquiries, research competitors, run marketing campaigns, and manage internal processes. You have four different "hires" you could make. Each one is capable, but they're not the same. By the end of this post, you'll see exactly how LLM, RAG, AI Agent, and Agentic AI map to these four types of hires. It'll click faster than any chart can show you. --- ## 1\. LLM - The Brilliant Freelancer Who's Been Living Off the Grid **What it is:** A Large Language Model is, at its core, a very sophisticated text prediction machine. You give it a prompt, it predicts the most statistically likely and coherent response based on everything it was trained on. That's it. No internet connection. No memory. No tools. Just the knowledge it absorbed before training ended. Think of it like a brilliant freelancer who studied obsessively for years, passed every certification, read every book and then went completely off the grid. No phone, no email, no news. When you call them in for a job, they give you an incredibly well-reasoned answer based on everything they knew *before* they went dark. **A real-world example:** You open ChatGPT and ask, "What's the best way to structure a Next.js project for a large enterprise app?" It gives you a detailed, thoughtful answer. Now you ask, "What did Sitecore announce last week?" Crickets or worse, a confident-sounding wrong answer. That's an LLM doing what LLMs do. **Where it shines:** Writing emails, drafting documentation, explaining concepts, summarising content you paste in, generating boilerplate code. Anything that lives within the boundary of its training data. **The catch:** Its knowledge has a cutoff. It has no memory between sessions. It cannot access your files, your database, or the live internet. Every conversation starts completely fresh. **Cost profile:** This is the cheapest option. You're essentially paying per token (input + output), and since there's no retrieval layer or tool infrastructure, the overhead is minimal. --- ## 2\. RAG - The Consultant Who Actually Does Their Homework **What it is:** RAG stands for Retrieval-Augmented Generation. The idea is elegant before the LLM generates a response, it first *retrieves* relevant information from a connected knowledge source (your documents, databases, wikis, PDFs), and then uses that retrieved content to inform its answer. You're not changing the LLM's brain. You're giving it a briefing packet before it walks into the room. **A real-world example:** Imagine you're a Sitecore developer and your company has hundreds of internal runbooks, architecture decisions, and Confluence pages. You build a RAG system that points to all of that. Now when someone on the team asks, "How do we handle multisite middleware in our XM Cloud setup?", the AI doesn't guess it pulls your actual internal documentation and answers based on *your* context. That's the game-changer. It's not hallucinating. It's referencing your sources. **Where it shines:** Customer support bots that need accurate product info, internal knowledge management tools, research assistants that reference company documentation, compliance Q&A systems where getting the answer wrong actually matters. **The catch:** RAG is only as good as your retrieval. If your documents are badly organised, your embeddings are weak, or your chunking strategy is off, the AI will retrieve the wrong context and produce a confident-but-wrong answer. Garbage in, garbage out just faster. **Cost profile:** Medium. You're paying for the LLM *plus* a retrieval infrastructure vector databases, embedding models, indexing pipelines. It's more expensive than a vanilla LLM, but significantly cheaper than what comes next. --- ## 3\. AI Agent - The New Hire Who Gets Stuff Done Autonomously **What it is:** An AI Agent is an LLM that has been given *tools* and the ability to *take actions*. It doesn't just generate text it can browse the web, write and execute code, call APIs, read files, and send emails. The critical shift here is that the agent decides *what to do next* based on its goal, not just what to *say* next. Think of it as a new hire who doesn't need hand-holding. You give them a goal "Research our top three competitors and produce a comparison report" and they figure out the steps themselves. They open a browser, search, take notes, analyse the data, and hand you back the finished report. You didn't micromanage every step. **A real-world example:** You're building a content automation pipeline. Instead of manually pulling analytics, identifying low-performing pages, rewriting the copy, and pushing updates, you set up an AI Agent with access to your CMS API, Google Analytics, and a writing tool. You define the goal. The agent breaks it into steps, executes each one, checks whether it worked, adjusts if needed, and completes the task with you checking in only at the end. That's the shift from *question-answering* to *task execution*. **Where it shines:** Research projects that require multiple steps, automating repetitive data workflows, organising large amounts of information across systems, anything that would take a junior team member a few hours of methodical work. **The catch:** Agents can go wrong in interesting ways. They make multi-step decisions, and errors can compound. An agent that misinterprets the goal at step one might confidently execute steps two through ten in entirely the wrong direction. Good guardrails, logging, and human checkpoints matter a lot here. **Cost profile:** High. Agents make multiple LLM calls within a single task, use tools that have their own API costs, and take longer to complete. You're not paying for one answer you're paying for a sequence of reasoning steps plus actions. --- ## 4\. Agentic AI - The Whole Department Running in Parallel **What it is:** Agentic AI is where things get truly powerful and where the bill gets truly painful. Instead of one agent working through a task sequentially, Agentic AI orchestrates *multiple specialised agents* working simultaneously, each with its own role, each with its own tools, all coordinated toward a shared outcome. Think of it like a full department, not a single employee. You've got a Researcher agent pulling data, a Writer agent drafting content, a Manager agent reviewing and routing tasks, and maybe a QA agent validating outputs all running at the same time. The collective output is something no single agent could produce alone, and it happens faster than if one agent did everything sequentially. **A real-world example:** Imagine a marketing team running on Agentic AI. The moment a new product is approved, one agent begins competitive research, another starts drafting copy, another pulls brand guidelines and begins designing assets, and another schedules social posts all in parallel, all coordinated. What used to take a team of five people a week gets done in hours. In the developer world, think about something like a full code review pipeline: one agent reads the PR and identifies potential bugs, another checks for security vulnerabilities, another validates against your coding standards, and a Manager agent synthesises all the feedback into a single review comment. Simultaneously. **Where it shines:** Complex, multi-faceted workflows that benefit from parallelism. Marketing campaign execution, running business processes, autonomous software development pipelines, large-scale data transformation tasks. **The catch:** Complexity is the price of power. Orchestrating multiple agents means more failure surfaces, harder debugging, trickier prompt coordination, and significantly higher latency and cost. Some agents need tight human oversight; others can run solo. Getting the balance right takes real architectural thought. **Cost profile:** Highest. Full stop. You're running multiple LLMs, multiple tool calls, multiple API integrations simultaneously. As the infographic puts it best: Agentic AI runs multiple agents simultaneously, so your bill does too. --- ## Side-by-Side: The Quick Mental Model Here's how I like to think about all four together: **LLM** is your brilliant friend who knows everything as long as you don't need anything that happened after their PhD. Great for a quick, knowledgeable answer. Useless for anything that requires current data or action. **RAG** is that same friend, but now they've been briefed on your specific company docs before the meeting. They're still not taking any actions but their answers are grounded in *your* reality, not just their training. **AI Agent** is a capable new hire. You give them a goal, they figure out the steps, use the tools available to them, and get the job done. Still one person, still one thread of work. **Agentic AI** is the whole department. Multiple specialists, working in parallel, each doing what they're best at, all coordinated toward a single output. --- ## Which One Do You Actually Need? This is the question that matters most and the honest answer is: it depends on what problem you're solving. If you're building a simple chatbot for your website that answers FAQs, a well-prompted LLM might be entirely sufficient. If those FAQs need to be accurate and sourced from your actual product documentation, add RAG. If you need the system to actually *do things* book appointments, update records, send follow-up emails you need an Agent. And if you need all of that happening simultaneously across multiple workflows without human intervention for each step, that's when Agentic AI starts to make sense. The mistake most teams make is jumping straight to Agentic AI because it sounds impressive, only to discover they've built a complex system with complex costs for a problem that a well-configured RAG would have solved just fine. Start simple. Add complexity only when the simpler option genuinely hits a wall. --- ## Final Thoughts The pace of AI development right now is genuinely exciting and genuinely overwhelming. But underneath all the jargon, these four concepts follow a clear progression: from smart text generation, to context-aware generation, to autonomous task execution, to parallel multi-agent orchestration. Understanding where each one sits on that spectrum means you can have smarter conversations with your team, make better architectural decisions, and build things that actually match the problem you're trying to solve not the hype cycle you're caught up in. If you're working in the Sitecore or .NET space and thinking about how these architectures fit into headless CMS and digital experience platforms, that's a topic I'll be diving into soon. Stay tuned and as always, subscribe if you haven't already. --- *Have a take on where Agentic AI is heading, or a real project you've built using one of these patterns? Drop it in the comments. I'd genuinely love to hear what you're working on.* ### Deploying and Optimizing Sitecore Marketplace Apps: Production Best Practices URL: https://www.gowthamaraja.com/sitecore-marketplace-production-apps-nextjs/ Last updated: 2026-03-06T15:27:15.000Z We've built our Marketplace app, integrated it with XM Cloud APIs, and tested it locally. Now comes the most critical part—deploying to production and making sure it performs flawlessly for your users. This final part covers everything from deployment strategies to performance optimization, security best practices, and preparing for the public Marketplace. ## Table of Contents 1. [Preparing for Production](#preparing-for-production) 2. [Deployment Strategy Overview](#deployment-strategy-overview) 3. [Deploying to Vercel](#deploying-to-vercel) 4. [Deploying to Netlify](#deploying-to-netlify) 5. [Deploying to Azure Static Web Apps](#deploying-to-azure-static-web-apps) 6. [Updating Your App Registration](#updating-your-app-registration) 7. [Performance Optimization](#performance-optimization) 8. [Security Best Practices](#security-best-practices) 9. [Monitoring and Analytics](#monitoring-and-analytics) 10. [Common Production Issues](#common-production-issues) 11. [Publishing to Public Marketplace](#publishing-to-public-marketplace) 12. [Final Checklist](#final-checklist) --- ## Preparing for Production Before deploying, let's make sure your app is production-ready. ### Pre-Deployment Checklist **Code Quality:** - Remove all `console.log` statements (or use proper logging) - Fix all TypeScript errors and warnings - Run ESLint and fix issues - Test all features thoroughly - Handle edge cases and error states **Performance:** - Optimize images and assets - Implement code splitting where needed - Remove unused dependencies - Test bundle size (`npm run build`) **Security:** - No hardcoded secrets or API keys - Environment variables properly configured - Input validation on all user inputs - XSS protection in place **UX/UI:** - Loading states for all async operations - Error messages are user-friendly - Responsive design tested on mobile/tablet/desktop - Accessibility basics covered (keyboard navigation, ARIA labels) ### Environment Variables Setup Create `.env.production`: bash ```bash NEXT_PUBLIC_APP_ENV=production NEXT_PUBLIC_API_TIMEOUT=10000 NEXT_PUBLIC_SENTRY_DSN=your-sentry-dsn # if using Sentry ``` Add `.env.local` to `.gitignore`: bash ```bash # .gitignore .env.local .env.*.local node_modules/ .next/ ``` --- ## Deployment Strategy Overview You have three main hosting options: | Platform | Best For | Pros | Cons | | ----------- | ------------ | --------------------------------------------- | ------------------------- | | **Vercel** | Next.js apps | Zero config, automatic, great DX | Vendor lock-in | | **Netlify** | Static sites | Easy, good free tier | Less Next.js optimization | | **Azure** | Enterprise | Full control, integration with Azure services | More complex setup | For this guide, we'll cover all three, but **Vercel is recommended** for Next.js apps. --- ## Deploying to Vercel Vercel is built by the creators of Next.js, making it the smoothest option. ### Step 1: Push to GitHub bash ```bash # Initialize git if you haven't git init # Add all files git add . # Commit git commit -m "Production ready app" # Create repository on GitHub, then: git remote add origin https://github.com/yourusername/sitecore-analytics-app.git git push -u origin main ``` ### Step 2: Deploy to Vercel 1. Go to [vercel.com](https://vercel.com/?ref=gowthamaraja.com) 2. Click **"New Project"** 3. Import your GitHub repository 4. Vercel auto-detects Next.js settings: - Framework Preset: **Next.js** - Build Command: `npm run build` - Output Directory: `.next` 5. Add environment variables: - `NEXT_PUBLIC_APP_ENV`: `production` 6. Click **"Deploy"** ### Step 3: Get Your Production URL After deployment completes (usually 2-3 minutes), you'll get a URL like: ``` https://sitecore-analytics-app.vercel.app ``` ### Vercel-Specific Optimizations **1\. Enable Edge Functions (optional)** For global performance, enable edge runtime: typescript ```typescript // src/app/standalone/page.tsx export const runtime = 'edge'; // Run on the edge ``` **2\. Configure Caching** Add to `next.config.js`: javascript ```javascript /** @type {import('next').NextConfig} */ const nextConfig = { images: { domains: ['placehold.co'], // Add your image domains }, headers: async () => [ { source: '/:path*', headers: [ { key: 'Cache-Control', value: 'public, max-age=3600, must-revalidate', }, ], }, ], }; module.exports = nextConfig; ``` --- ## Deploying to Netlify Netlify is another excellent option with a generous free tier. ### Step 1: Push to GitHub Same as Vercel—push your code to GitHub. ### Step 2: Deploy to Netlify 1. Go to [netlify.com](https://netlify.com/?ref=gowthamaraja.com) 2. Click **"Add new site"** → **"Import an existing project"** 3. Connect your GitHub repository 4. Configure build settings: - Build command: `npm run build` - Publish directory: `.next` 5. Add environment variables in **Site settings → Environment variables** 6. Click **"Deploy site"** ### Step 3: Configure Next.js on Netlify Install the Netlify Next.js plugin: bash ```bash npm install -D @netlify/plugin-nextjs ``` Create `netlify.toml`: toml ```toml [build] command = "npm run build" publish = ".next" [[plugins]] package = "@netlify/plugin-nextjs" ``` Redeploy after adding this configuration. --- ## Deploying to Azure Static Web Apps For enterprise deployments, Azure provides robust infrastructure. ### Step 1: Create Azure Static Web App 1. Log into [Azure Portal](https://portal.azure.com/?ref=gowthamaraja.com) 2. Create **Static Web App** resource 3. Connect to GitHub repository 4. Configure build: - App location: `/` - API location: (leave empty) - Output location: `.next` ### Step 2: Configure GitHub Actions Azure automatically creates a GitHub Actions workflow. Update it: yaml ```yaml name: Azure Static Web Apps CI/CD on: push: branches: - main jobs: build_and_deploy_job: runs_on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Build And Deploy uses: Azure/static-web-apps-deploy@v1 with: azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }} action: "upload" app_location: "/" output_location: ".next" ``` ### Step 3: Add Environment Variables In Azure Portal: 1. Go to your Static Web App 2. Navigate to **Configuration** 3. Add application settings: - `NEXT_PUBLIC_APP_ENV`: `production` --- ## Updating Your App Registration Once deployed, update your app in Developer Studio. ### Step 1: Edit App Configuration 1. Log into Cloud Portal 2. Go to **Developer Studio** 3. Find your app and click **"Edit"** ### Step 2: Update Deployment URL Change from: ``` http://localhost:3000/standalone ``` To your production URL: ``` https://sitecore-analytics-app.vercel.app/standalone ``` ### Step 3: Add Production Logo Replace placeholder with your actual app logo: 1. Upload a 512x512px PNG to your hosting 2. Update **App Logo URL** with the production URL ### Step 4: Test Production App 1. Save changes 2. Open your app from Cloud Portal navigation 3. Verify everything works: - SDK initializes successfully - Data loads correctly - No console errors - All features functional --- ## Performance Optimization Let's make sure your app loads fast and runs smoothly. ### Bundle Size Optimization **1\. Analyze Your Bundle** bash ```bash npm install -D @next/bundle-analyzer ``` Update `next.config.js`: javascript ```javascript const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); module.exports = withBundleAnalyzer({ // your existing config }); ``` Run analysis: bash ```bash ANALYZE=true npm run build ``` **2\. Code Splitting** Split large components: typescript ```typescript import dynamic from 'next/dynamic'; // Lazy load heavy components const AnalyticsChart = dynamic(() => import('@/components/AnalyticsChart'), { loading: () =>
Loading chart...
, ssr: false, // Disable SSR for client-only components }); ``` **3\. Optimize Images** Use Next.js Image component: typescript ```typescript import Image from 'next/image'; App Logo ``` ### Data Fetching Optimization **1\. Implement Caching** typescript ```typescript // Simple in-memory cache const cache = new Map(); async function fetchWithCache(key: string, fetchFn: () => Promise, ttl = 300000) { const cached = cache.get(key); if (cached && Date.now() - cached.timestamp < ttl) { return cached.data; } const data = await fetchFn(); cache.set(key, { data, timestamp: Date.now() }); return data; } // Usage const stats = await fetchWithCache('content-stats', async () => { const xmc = await initializeXMC(client); return xmc.graphQL.query({ query }); }, 300000); // 5 minutes ``` **2\. Debounce API Calls** typescript ```typescript import { debounce } from 'lodash'; const debouncedSearch = debounce(async (searchTerm: string) => { const results = await searchContent(searchTerm); setSearchResults(results); }, 500); // Wait 500ms after user stops typing ``` ### Runtime Performance **1\. Memoize Expensive Calculations** typescript ```typescript import { useMemo } from 'react'; const expensiveCalculation = useMemo(() => { return items.reduce((acc, item) => { // Complex calculation return acc + item.value; }, 0); }, [items]); // Only recalculate when items change ``` **2\. Virtual Lists for Large Data** bash ```bash npm install react-window ``` typescript ```typescript import { FixedSizeList } from 'react-window'; function ItemList({ items }) { return ( {({ index, style }) => (
{items[index].name}
)}
); } ``` --- ## Security Best Practices Security is non-negotiable for production apps. ### Input Validation typescript ```typescript // Sanitize user input function sanitizeInput(input: string): string { return input .trim() .replace(/[<>]/g, '') // Remove HTML tags .substring(0, 200); // Limit length } // Validate before using function handleUserInput(value: string) { const sanitized = sanitizeInput(value); if (!/^[a-zA-Z0-9\s-]+$/.test(sanitized)) { throw new Error('Invalid characters in input'); } return sanitized; } ``` ### Content Security Policy Add to `next.config.js`: javascript ```javascript const nextConfig = { async headers() { return [ { source: '/:path*', headers: [ { key: 'Content-Security-Policy', value: [ "default-src 'self'", "script-src 'self' 'unsafe-inline' 'unsafe-eval'", "style-src 'self' 'unsafe-inline'", "img-src 'self' data: https:", "connect-src 'self' https://*.sitecore.com", ].join('; '), }, ], }, ]; }, }; ``` ### Rate Limiting Implement rate limiting for API calls: typescript ```typescript class RateLimiter { private requests: number[] = []; private limit: number; private window: number; constructor(limit: number, windowMs: number) { this.limit = limit; this.window = windowMs; } async checkLimit(): Promise { const now = Date.now(); this.requests = this.requests.filter(time => now - time < this.window); if (this.requests.length >= this.limit) { return false; } this.requests.push(now); return true; } } // Usage const limiter = new RateLimiter(10, 60000); // 10 requests per minute async function fetchData() { if (!await limiter.checkLimit()) { throw new Error('Rate limit exceeded. Please try again later.'); } // Make API call } ``` --- ## Monitoring and Analytics Track your app's performance and usage. ### Error Tracking with Sentry bash ```bash npm install @sentry/nextjs ``` Create `sentry.client.config.ts`: typescript ```typescript import * as Sentry from '@sentry/nextjs'; Sentry.init({ dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, environment: process.env.NEXT_PUBLIC_APP_ENV, tracesSampleRate: 1.0, }); ``` Wrap your app: typescript ```typescript import { ErrorBoundary } from '@sentry/nextjs'; export default function App({ Component, pageProps }: AppProps) { return ( }> ); } ``` ### Custom Analytics Track user interactions: typescript ```typescript // lib/analytics.ts export function trackEvent( event: string, properties?: Record ) { if (typeof window === 'undefined') return; // Send to your analytics service console.log('Event:', event, properties); // Example: Google Analytics if (window.gtag) { window.gtag('event', event, properties); } } // Usage trackEvent('content_exported', { format: 'csv', itemCount: 150, }); ``` --- ## Common Production Issues ### Issue 1: CORS Errors **Symptom:** API calls fail with CORS errors **Solution:** Ensure your deployment URL is added to allowed origins in API configuration. ### Issue 2: Environment Variables Not Working **Symptom:** `process.env.NEXT_PUBLIC_*` is undefined **Solution:** - Rebuild after adding environment variables - Verify variables start with `NEXT_PUBLIC_` - Check they're added in hosting platform settings ### Issue 3: Hydration Errors **Symptom:** "Hydration failed" errors in console **Solution:** typescript ```typescript // Use useEffect for client-only rendering const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); if (!mounted) return null; ``` ### Issue 4: Slow Initial Load **Symptom:** App takes 5+ seconds to load **Solution:** - Enable code splitting - Optimize bundle size - Use CDN for static assets - Implement proper caching headers --- ## Publishing to Public Marketplace Once the public Marketplace launches fully, you can publish your app. ### Requirements for Public Apps 1. **Documentation** - Clear README with setup instructions - Screenshots and demo video - Support contact information 2. **Quality Standards** - No critical bugs - Responsive design - Proper error handling - Accessibility compliance 3. **Pricing Model** - Free - Freemium (basic free, premium paid) - Paid subscription - One-time purchase ### Publishing Process 1. **Test Thoroughly** - Get beta users to test - Fix all reported issues - Document known limitations 2. **Create Marketing Materials** - App icon (512x512px) - Screenshots (various sizes) - Demo video (2-3 minutes) - Feature highlights - Use case examples 3. **Submit for Review** - In Developer Studio, change app type to "Public" - Complete listing information - Submit for Sitecore review - Wait for approval (typically 5-7 business days) 4. **Launch and Promote** - Announce on social media - Write blog post - Submit to Sitecore community - Engage with early adopters --- ## Final Checklist Before considering your app production-ready: ### Development - All features tested and working - No TypeScript errors - ESLint warnings resolved - Code reviewed and optimized ### Performance - Bundle size under 1MB initial load - First Contentful Paint < 2s - Time to Interactive < 5s - Lighthouse score > 90 ### Security - No hardcoded secrets - Input validation implemented - CSP headers configured - Rate limiting in place ### User Experience - Loading states for all async operations - Error messages are helpful - Responsive on all devices - Keyboard navigation works - Color contrast meets WCAG AA ### Deployment - Deployed to production hosting - Custom domain configured (optional) - SSL certificate active - Environment variables set - App registration updated in Developer Studio ### Monitoring - Error tracking configured - Analytics implemented - Performance monitoring active - Uptime monitoring setup --- ## Conclusion You've made it! You now have the complete knowledge to: 1. **Build** sophisticated Marketplace apps from scratch 2. **Integrate** with XM Cloud APIs and extension points 3. **Deploy** to production hosting platforms 4. **Optimize** for performance and security 5. **Monitor** and maintain your apps ### What's Next for You? **Immediate Actions:** - Deploy your first app to production - Share it with your team - Gather user feedback - Iterate and improve **Long-term Goals:** - Build apps for the public Marketplace - Create a portfolio of Sitecore extensions - Contribute to the Sitecore community - Potentially build a business around Marketplace apps ### Resources to Bookmark - [Sitecore Marketplace Documentation](https://doc.sitecore.com/mp/?ref=gowthamaraja.com) - [Marketplace SDK Reference](https://doc.sitecore.com/mp/en/developers/sdk/?ref=gowthamaraja.com) - [Sitecore Developer Portal](https://developers.sitecore.com/?ref=gowthamaraja.com) - [Marketplace Starter Kit](https://github.com/Sitecore/marketplace-starter?ref=gowthamaraja.com) - [Blok Design System](https://blok.sitecore.com/?ref=gowthamaraja.com) --- ## Thank You! This three-part series covered everything from "What is Sitecore Marketplace?" to "How do I deploy a production app?" If you found this helpful: - Share it with your developer community - Try building your own Marketplace app - Let me know what you build! **Questions? Feedback? Success stories?** Drop them in the comments below. I read every single one. Happy coding, and see you in the Marketplace! 🚀 --- **Missed the earlier parts?** - [Part 1: Getting Started with Sitecore Marketplace →](https://www.gowthamaraja.com/building-production-ready-sitecore-marketplace-apps-with-next-js) - [Part 2: Building Production-Ready Apps →](https://www.gowthamaraja.com/sitecore-marketplace-getting-started-nextjs) ### Building Production-Ready Sitecore Marketplace Apps with Next.js URL: https://www.gowthamaraja.com/building-production-ready-sitecore-marketplace-apps-with-next-js/ Last updated: 2026-03-06T15:28:55.000Z In [Part 1](https://www.gowthamaraja.com/sitecore-marketplace-getting-started-nextjs), we built our first Marketplace app and got it running in XM Cloud. Now it's time to take things to the next level—building production-ready apps that actually solve real problems. We'll explore all four extension types, integrate with XM Cloud APIs, and write code that you can confidently deploy to production. ## Table of Contents 1. [Recap: Where We Left Off](#recap-where-we-left-off) 2. [Understanding Extension Points in Depth](#understanding-extension-points-in-depth) 3. [Building a Standalone Application](#building-a-standalone-application) 4. [Creating Dashboard Widgets](#creating-dashboard-widgets) 5. [Building Custom Field Extensions](#building-custom-field-extensions) 6. [Working with XM Cloud APIs](#working-with-xm-cloud-apis) 7. [Fetching Real Content Data](#fetching-real-content-data) 8. [Handling API Errors Gracefully](#handling-api-errors-gracefully) 9. [State Management Best Practices](#state-management-best-practices) 10. [What's Next?](#whats-next) --- ## Recap: Where We Left Off In Part 1, we created a basic analytics dashboard that: - Initialized the Marketplace SDK - Fetched application context - Displayed mock statistics - Ran successfully in XM Cloud Portal Now we'll enhance this foundation with real functionality and explore other extension types. --- ## Understanding Extension Points in Depth Sitecore Marketplace offers four extension points. Each serves different use cases and user workflows. ![Sitecore Extension Points](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/02/extension-points-overview.webp) ### 1\. Standalone Application **Best For:** - Admin dashboards and reporting tools - Bulk content operations - Configuration interfaces - Complex workflows that need dedicated space **User Access:** Via "My Apps" in the main navigation **Screen Real Estate:** Full page within the portal ### 2\. Full-Screen Experience **Best For:** - Content migration tools - Immersive workflows - Multi-step wizards - Tasks requiring maximum focus **User Access:** Takes over the entire portal interface **Screen Real Estate:** Complete viewport ### 3\. Dashboard Widgets **Best For:** - At-a-glance metrics - Quick status indicators - Action buttons for common tasks - Real-time notifications **User Access:** Site dashboard cards **Screen Real Estate:** Compact cards (typically 300-400px wide) ### 4\. Page Builder Extensions **Custom Fields:** - New field types (color pickers, icon selectors, etc.) - Enhanced input controls - Validation and formatting **Context Panels:** - Content suggestions - SEO analysis - AI-powered recommendations - Workflow helpers **User Access:** Content editor sidebar or field locations **Screen Real Estate:** Varies by type --- ## Building a Standalone Application Let's enhance our analytics dashboard from Part 1 with real functionality. ### Advanced Features We'll add: - Real-time data updates - Multiple chart types - Date range filtering - Export functionality ### Enhanced Dashboard Component Update `src/app/standalone/page.tsx`: ```typescript "use client"; import { useMarketplaceClient } from "@/hooks/useMarketplaceClient"; import { ApplicationContext } from "@sitecore-marketplace-sdk/client"; import { useEffect, useState } from "react"; import { initializeXMC } from "@/lib/xmcClient"; interface ContentStats { totalItems: number; publishedToday: number; draftItems: number; scheduledPublishing: number; lastUpdated: Date; } interface ActivityItem { id: string; action: string; user: string; timestamp: Date; } export default function AnalyticsDashboard() { const { client, error, isInitialized, isLoading } = useMarketplaceClient(); const [appContext, setAppContext] = useState(null); const [stats, setStats] = useState(null); const [activity, setActivity] = useState([]); const [refreshing, setRefreshing] = useState(false); // Fetch application context useEffect(() => { if (!isInitialized || !client) return; async function fetchContext() { try { const response = await client.query("application.context"); setAppContext(response.data); } catch (err) { console.error("Failed to fetch context:", err); } } fetchContext(); }, [client, isInitialized]); // Fetch content statistics useEffect(() => { if (!appContext || !client) return; fetchStats(); // Auto-refresh every 30 seconds const interval = setInterval(fetchStats, 30000); return () => clearInterval(interval); }, [appContext, client]); async function fetchStats() { if (!client) return; setRefreshing(true); try { const xmc = await initializeXMC(client); // GraphQL query for content statistics const query = ` query GetContentStats { search( where: { AND: [ { name: "_path", value: "/sitecore/content/", operator: CONTAINS } ] } first: 1000 ) { total results { id name updated published: field(name: "__Published") { value } } } } `; const response = await xmc.graphQL.query({ query }); const items = response.data.search.results; // Calculate statistics const today = new Date(); today.setHours(0, 0, 0, 0); const publishedToday = items.filter((item: any) => { const updateDate = new Date(item.updated); return updateDate >= today; }).length; setStats({ totalItems: response.data.search.total, publishedToday, draftItems: items.filter((i: any) => !i.published?.value).length, scheduledPublishing: 0, // Would need workflow API lastUpdated: new Date(), }); // Fetch recent activity const recentItems = items .slice(0, 5) .map((item: any) => ({ id: item.id, action: "Updated", user: "Content Editor", timestamp: new Date(item.updated), })); setActivity(recentItems); } catch (err) { console.error("Failed to fetch stats:", err); // Fallback to mock data setStats({ totalItems: 1247, publishedToday: 23, draftItems: 156, scheduledPublishing: 8, lastUpdated: new Date(), }); } finally { setRefreshing(false); } } if (isLoading) { return ; } if (error) { return ; } return (
{/* Header with refresh */}

Content Analytics

{appContext?.organization?.name || "Your Organization"}

{/* Stats Grid */} {stats && ( <>

Last updated: {stats.lastUpdated.toLocaleTimeString()}

)} {/* Recent Activity */}

Recent Activity

{activity.map((item) => (

{item.action}

by {item.user}

{formatTimeAgo(item.timestamp)}

))}
); } // Helper components function StatCard({ title, value, icon, trend, trendUp }: any) { const trendColor = trendUp === true ? "text-green-600" : trendUp === false ? "text-red-600" : "text-gray-600"; return (
{icon} {trend}

{title}

{value}

); } function RefreshIcon({ className }: { className?: string }) { return ( ); } function formatTimeAgo(date: Date): string { const seconds = Math.floor((new Date().getTime() - date.getTime()) / 1000); if (seconds < 60) return "just now"; if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`; if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`; return `${Math.floor(seconds / 86400)}d ago`; } function LoadingScreen() { return (

Loading dashboard...

); } function ErrorScreen({ error }: { error: Error }) { return (

⚠️ Error Loading Dashboard

{error.message}

); } ``` --- ## Creating Dashboard Widgets Dashboard widgets are compact, focused components perfect for at-a-glance information. ### Widget Design Principles 1. **Keep it focused**: One primary metric or action 2. **Make it actionable**: Include a CTA button 3. **Update in real-time**: Show live data when possible 4. **Be responsive**: Work on different screen sizes ### Building a Content Approval Widget Create `src/app/dashboard-widget/page.tsx`: ```typescript "use client"; import { useMarketplaceClient } from "@/hooks/useMarketplaceClient"; import { useEffect, useState } from "react"; interface ApprovalStats { pending: number; approved: number; rejected: number; } export default function ApprovalWidget() { const { client, isInitialized } = useMarketplaceClient(); const [stats, setStats] = useState({ pending: 0, approved: 0, rejected: 0, }); useEffect(() => { if (!isInitialized || !client) return; async function fetchApprovals() { // In production, fetch from workflow API setStats({ pending: 8, approved: 45, rejected: 2, }); } fetchApprovals(); // Refresh every minute const interval = setInterval(fetchApprovals, 60000); return () => clearInterval(interval); }, [client, isInitialized]); return (

Content Approvals

📋
0} />
); } function ApprovalRow({ label, count, color, pulse }: any) { const colors = { orange: "bg-orange-100 text-orange-700", green: "bg-green-100 text-green-700", red: "bg-red-100 text-red-700", }; return (
{label} {count}
); } ``` **Register this widget:** - Extension point: Dashboard widgets - Deployment URL: `http://localhost:3000/dashboard-widget` --- ## Building Custom Field Extensions Custom fields let you add new input types to the content editor. ### Building a Color Picker Field Create `src/app/custom-field/page.tsx`: ```typescript "use client"; import { useMarketplaceClient } from "@/hooks/useMarketplaceClient"; import { useEffect, useState } from "react"; const PRESET_COLORS = [ { name: "Primary Blue", value: "#3B82F6" }, { name: "Success Green", value: "#10B981" }, { name: "Warning Orange", value: "#F59E0B" }, { name: "Danger Red", value: "#EF4444" }, { name: "Purple", value: "#8B5CF6" }, { name: "Pink", value: "#EC4899" }, { name: "Teal", value: "#14B8A6" }, { name: "Gray", value: "#6B7280" }, ]; export default function ColorPickerField() { const { client, isInitialized } = useMarketplaceClient(); const [selectedColor, setSelectedColor] = useState("#3B82F6"); const [customColor, setCustomColor] = useState("#3B82F6"); useEffect(() => { if (!isInitialized || !client) return; async function initField() { try { // Get current field value const context = await client.query("field.context"); if (context.data?.value) { setSelectedColor(context.data.value); setCustomColor(context.data.value); } } catch (err) { console.error("Failed to get field context:", err); } } initField(); }, [client, isInitialized]); const updateColor = async (color: string) => { setSelectedColor(color); setCustomColor(color); if (!client) return; try { // Update field value in Sitecore await client.query("field.setValue", { value: color }); } catch (err) { console.error("Failed to update field:", err); } }; return (
{/* Color Preview */}

{selectedColor}

{/* Preset Colors */}
{PRESET_COLORS.map((color) => (
{/* Custom Color Input */}
setCustomColor(e.target.value)} className="h-12 w-20 rounded-lg cursor-pointer" />
); } ``` **To use this field:** 1. Enable "Custom Field" extension point 2. In Sitecore, add field to content template 3. Set field type to "Marketplace Type → Plugin" 4. Select your app from dropdown --- ## Working with XM Cloud APIs The XMC package gives you access to powerful content operations. ### Initializing the XMC Client Create `src/lib/xmcClient.ts`: ```typescript import { XMC } from "@sitecore-marketplace-sdk/xmc"; import { ClientSDK } from "@sitecore-marketplace-sdk/client"; let xmcInstance: XMC | null = null; export async function initializeXMC(marketplaceClient: ClientSDK): Promise { if (xmcInstance) return xmcInstance; xmcInstance = new XMC({ client: marketplaceClient }); await xmcInstance.init(); console.log("✅ XM Cloud API client initialized"); return xmcInstance; } export function getXMC(): XMC { if (!xmcInstance) { throw new Error("XMC not initialized"); } return xmcInstance; } ``` ### Common API Operations ```typescript // Fetch content items const query = ` query GetItems { item(path: "/sitecore/content/home") { id name children { results { id name path } } } } `; const response = await xmc.graphQL.query({ query }); // Create a new item const createMutation = ` mutation CreateItem($input: CreateItemInput!) { createItem(input: $input) { id name } } `; await xmc.graphQL.query({ query: createMutation, variables: { input: { name: "New Page", templateId: "template-id-here", parent: "parent-item-id" } } }); ``` --- ## Fetching Real Content Data Let's implement a practical content browser component. ```typescript interface ContentItem { id: string; name: string; path: string; template: string; hasChildren: boolean; } export function ContentBrowser() { const { client } = useMarketplaceClient(); const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); const [currentPath, setCurrentPath] = useState("/sitecore/content"); async function loadItems(path: string) { if (!client) return; setLoading(true); try { const xmc = await initializeXMC(client); const query = ` query GetChildren($path: String!) { item(path: $path) { id name children { results { id name path template { name } hasChildren } } } } `; const response = await xmc.graphQL.query({ query, variables: { path } }); setItems(response.data.item.children.results); setCurrentPath(path); } catch (err) { console.error("Failed to load items:", err); } finally { setLoading(false); } } return (

Current: {currentPath}

{loading ? (
Loading...
) : (
{items.map((item) => (
item.hasChildren && loadItems(item.path)} className="p-3 bg-white rounded border hover:bg-gray-50 cursor-pointer" >

{item.name}

{item.template}

))}
)}
); } ``` --- ## Handling API Errors Gracefully Production apps need robust error handling. ### Error Boundary Component ```typescript import { Component, ReactNode } from 'react'; interface Props { children: ReactNode; } interface State { hasError: boolean; error: Error | null; } export class ErrorBoundary extends Component { constructor(props: Props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error: Error) { return { hasError: true, error }; } render() { if (this.state.hasError) { return (

Something went wrong

{this.state.error?.message}

); } return this.props.children; } } ``` ### API Error Handler ```typescript export async function handleAPICall( apiCall: () => Promise, fallbackValue?: T ): Promise { try { return await apiCall(); } catch (error) { console.error("API call failed:", error); if (fallbackValue !== undefined) { return fallbackValue; } throw error; } } // Usage const data = await handleAPICall( () => xmc.graphQL.query({ query }), [] // fallback to empty array ); ``` --- ## State Management Best Practices For complex apps, consider using a state management library. ### Using React Context ```typescript import { createContext, useContext, useState, ReactNode } from 'react'; interface AppState { stats: ContentStats | null; setStats: (stats: ContentStats) => void; refreshData: () => Promise; } const AppContext = createContext(null); export function AppProvider({ children }: { children: ReactNode }) { const [stats, setStats] = useState(null); const refreshData = async () => { // Refresh logic here }; return ( {children} ); } export function useAppState() { const context = useContext(AppContext); if (!context) throw new Error("useAppState must be used within AppProvider"); return context; } ``` --- ## What's Next? You now have the skills to build production-ready Marketplace apps with: - All four extension types - Real XM Cloud API integration - Proper error handling - State management In **Part 3**, we'll cover: - Deploying to production (Vercel, Netlify, Azure) - Performance optimization techniques - Security best practices - Monitoring and analytics - Publishing to public Marketplace ### Quick Checklist Before deploying, make sure you have: - Error boundaries in place - Loading states for all async operations - Fallback data for API failures - Responsive design tested - Console.log statements removed - TypeScript errors resolved **Next:** [Part 3 - Deploying and Optimizing Marketplace Apps →](https://www.gowthamaraja.com/sitecore-marketplace-production-apps-nextjs) --- *Found this helpful? Follow for Part 3 where we deploy to production!* *Have questions? Drop them in the comments below.* ### Getting Started with Sitecore Marketplace: Your First Next.js App URL: https://www.gowthamaraja.com/sitecore-marketplace-getting-started-nextjs/ Last updated: 2026-02-23T05:12:54.000Z Welcome to Sitecore Marketplace—the game-changer that lets you build custom apps just like adding plugins to WordPress, but way more powerful. In this three-part series, I'll walk you through building Sitecore Marketplace apps from scratch. By the end of Part 1, you'll have your first working app running inside XM Cloud. No fluff, just practical code and real-world insights. ## Table of Contents 1. [What is Sitecore Marketplace](#what-is-sitecore-marketplace)? 2. [Why Marketplace Apps Matter](#why-marketplace-apps-matter) 3. [Prerequisites](#prerequisites) 4. [Understanding the Architecture](#understanding-the-architecture) 5. [Setting Up Your Development Environment](#setting-up-your-development-environment) 6. [Creating Your First Next.js Marketplace App](#creating-your-first-next.js-marketplace-app) 7. [Understanding the Marketplace SDK](#understanding-the-marketplace-sdk) 8. [Registering Your App in XM Cloud](#registering-your-app-in-xm-cloud) 9. [Testing Your App](#testing-your-app) 10. [What's Next?](#whats-next) --- ## What is Sitecore Marketplace? Think of Sitecore Marketplace as an app store for your XM Cloud instance. Launched in August 2025, it's a platform that lets you extend Sitecore's capabilities through custom applications—without modifying the core system. You're not locked into any specific framework. As long as you're using JavaScript or TypeScript with npm, you're good to go. Next.js, React with Vite, Angular, Vue—all supported. ### The Core Components The Marketplace ecosystem consists of three main parts: **1\. Developer Studio** Your mission control inside XM Cloud Portal where you manage, configure, and activate apps. **2\. Marketplace SDK** The JavaScript/TypeScript toolkit that connects your app to Sitecore. It handles authentication, communication, and data exchange. **3\. Extension Points** Specific locations in XM Cloud where your apps can live—like standalone pages, dashboard widgets, or custom content fields. ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/02/sitecore-marketplace-ecosystem-1.webp) --- ## Why Marketplace Apps Matter Let me be honest—when I first heard about Marketplace apps, I thought, "Great, another thing to learn." But after building an application, I realized this is actually solving real problems: ### 1\. Keep Your Sitecore Instance Clean No more backend modifications for every custom feature. Your code lives separately, making upgrades and maintenance way easier. ### 2\. Faster Development Cycles Use React hooks, modern JavaScript, hot reloading—all the tooling you already know. No fighting with old-school development setups. ### 3\. Independent Deployment Update your app without redeploying Sitecore. If something breaks, it's isolated to your app, not the entire platform. ### 4\. Better Team Collaboration Frontend developers can work on Marketplace apps without needing deep Sitecore backend knowledge. Backend teams can focus on content modeling and workflows. ### 5\. Future Business Opportunities Once the public Marketplace fully launches, you can publish apps for the entire Sitecore community. Think selling WordPress plugins, but for enterprise CMS. --- ## Prerequisites Let's make sure you've got everything before we start building. ### Required - **Node.js v16 or later** `node --version` - **npm v10 or later** `npm --version` - **Sitecore Cloud Portal Access** \- You need an active XM Cloud organization either with Organization Admin or Owner privilege - **Basic React/Next.js Knowledge** \- Understanding of components, hooks, and state management - **Code Editor** --- ### Quick Setup Check Run these commands to verify your setup: ```bash # Check Node.js version (should be 16+) node --version # Check npm version (should be 10+) npm --version # If versions are older, install from nodejs.org ``` --- ## Understanding the Architecture Before writing code, let's understand how everything connects. ### How It Actually Works 1. **Your app runs in an iframe** inside XM Cloud Portal 2. **The Marketplace SDK establishes secure communication** using the postMessage API 3. **Your app queries application context** (user info, organization details, etc.) 4. **Your app can call XM Cloud APIs** with automatic authentication 5. **Everything happens client-side**—no server-side API keys needed ![Sitecore Marketplace SDK Communication Flow](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/02/sdk-communication-flow.webp) SDK Communication Flow ### Key Concepts **Application Context** Every Marketplace app gets context data like app ID, current user, organization info, and which extension point is active. **Secure Communication** The SDK uses a handshake mechanism. You don't handle API keys or tokens in your frontend—it's all managed transparently. **Query-Based API** Instead of traditional REST calls, you query the SDK: ```typescript // Get application context client.query("application.context") // Get user profile client.query("user.profile") ``` --- ## Setting Up Your Development Environment Time to get our hands dirty. Let's set up a proper development environment. ### Step 1: Access Developer Studio Log into your Sitecore Cloud Portal. In the navigation menu, you should see **Developer Studio**. If you don't see it, your organization might not have Marketplace access enabled yet. Contact your Sitecore admin. ### Step 2: Create a New Next.js Project Open your terminal and create a new Next.js app: ```bash # Navigate to your projects folder cd ~/projects # Create a new Next.js app with TypeScript npx create-next-app@latest sitecore-analytics-app # Answer the prompts: # ✔ Would you like to use TypeScript? → Yes # ✔ Would you like to use ESLint? → Yes # ✔ Would you like to use Tailwind CSS? → Yes # ✔ Would you like to use `src/` directory? → Yes # ✔ Would you like to use App Router? → Yes # ✔ Would you like to customize import alias? → No # Navigate into your new project cd sitecore-analytics-app ``` ### Step 3: Install Marketplace SDK Packages Install the required Sitecore packages: ```bash # Core client package (required for all apps) npm install @sitecore-marketplace-sdk/client # XM Cloud API package (optional, for content operations) npm install @sitecore-marketplace-sdk/xmc ``` **What these packages do:** - **@sitecore-marketplace-sdk/client**: Handles secure communication, authentication, and SDK initialization - **@sitecore-marketplace-sdk/xmc**: Provides access to XM Cloud APIs (content, publishing, search, etc.) --- ## Creating Your First Next.js Marketplace App Let's build a simple but practical app: a **Content Analytics Dashboard** that shows real-time statistics. ### Project Structure Here's how we'll organize our code: ``` sitecore-analytics-app/ ├── src/ │ ├── app/ │ │ ├── standalone/ │ │ │ └── page.tsx # Our main app page │ │ ├── layout.tsx │ │ └── page.tsx │ ├── hooks/ │ │ └── useMarketplaceClient.ts # SDK initialization hook │ └── types/ │ └── index.ts ├── public/ │ └── logo.png # App logo (512x512px) └── package.json ``` ### Creating the SDK Initialization Hook This is the heart of your Marketplace app. Create `src/hooks/useMarketplaceClient.ts`: ```typescript import { ClientSDK } from "@sitecore-marketplace-sdk/client"; import { useEffect, useState, useCallback, useRef } from "react"; export interface MarketplaceClientState { client: ClientSDK | null; error: Error | null; isLoading: boolean; isInitialized: boolean; } // Singleton to avoid re-initialization let clientInstance: ClientSDK | undefined = undefined; async function initializeClient(): Promise { if (clientInstance) return clientInstance; const client = new ClientSDK(); await client.init(); clientInstance = client; return client; } export function useMarketplaceClient(): MarketplaceClientState { const [state, setState] = useState({ client: clientInstance || null, error: null, isLoading: !clientInstance, isInitialized: !!clientInstance, }); const isInitializing = useRef(false); const initialize = useCallback(async () => { if (isInitializing.current || clientInstance) return; isInitializing.current = true; setState(prev => ({ ...prev, isLoading: true })); try { const client = await initializeClient(); setState({ client, error: null, isLoading: false, isInitialized: true, }); console.log("Marketplace SDK initialized"); } catch (error) { const err = error instanceof Error ? error : new Error(String(error)); console.error("SDK initialization failed:", err); setState({ client: null, error: err, isLoading: false, isInitialized: false, }); } finally { isInitializing.current = false; } }, []); useEffect(() => { if (!clientInstance && !isInitializing.current) { initialize(); } }, [initialize]); return state; } ``` **Why this matters:** - **Singleton pattern** prevents multiple SDK initializations - **Automatic retry** handles transient network issues - **Loading states** let your UI respond appropriately - **Error handling** shows users what went wrong ### Building the Dashboard Component Create `src/app/standalone/page.tsx`: ```typescript "use client"; import { useMarketplaceClient } from "@/hooks/useMarketplaceClient"; import { ApplicationContext } from "@sitecore-marketplace-sdk/client"; import { useEffect, useState } from "react"; export default function AnalyticsDashboard() { const { client, error, isInitialized, isLoading } = useMarketplaceClient(); const [appContext, setAppContext] = useState(null); useEffect(() => { if (!isInitialized || !client) return; async function fetchContext() { try { const response = await client.query("application.context"); console.log("📦 Application context:", response.data); setAppContext(response.data); } catch (err) { console.error("Failed to fetch context:", err); } } fetchContext(); }, [client, isInitialized]); // Loading state if (isLoading) { return (

Initializing...

); } // Error state if (error) { return (

Initialization Error

{error.message}

Make sure you're running this inside the XM Cloud Portal.

); } // Main content return (

Content Analytics Dashboard

Welcome to {appContext?.name || "your analytics app"}

{appContext?.organization && (

Organization: {appContext.organization.name}

)}

Quick Stats

); } // Stat card component interface StatCardProps { title: string; value: string; color: "blue" | "green" | "yellow"; } function StatCard({ title, value, color }: StatCardProps) { const colors = { blue: "bg-blue-50 text-blue-700", green: "bg-green-50 text-green-700", yellow: "bg-yellow-50 text-yellow-700", }; return (

{title}

{value}

); } ``` --- ## Understanding the Marketplace SDK Let's break down what's happening in our code. ### SDK Initialization Flow 1. App loads in XM Cloud iframe 2. SDK establishes secure handshake with the portal 3. Authentication happens automatically 4. Client is ready for queries ### The Application Context When you query `application.context`, you get: ```typescript { id: "app-123", name: "Content Analytics Dashboard", organization: { id: "org-456", name: "Your Company" }, user: { id: "user-789", email: "you@company.com" }, extensionPoint: "standalone" } ``` This context is **crucial**—it tells your app who's using it, where it's running, and what permissions it has. --- ## Registering Your App in XM Cloud Now let's get your app visible in XM Cloud Portal. ### Step 1: Run Your App Locally ```bash npm run dev ``` Your app should be running at `http://localhost:3000/standalone`. **Important:** Don't visit localhost directly—it won't work. The SDK requires the XM Cloud context. ### Step 2: Create App in Developer Studio 1. Log into Sitecore Cloud Portal 2. Navigate to **Developer Studio** 3. Click **"Create"** 4. Select **"Custom App"** ### Step 3: Configure Your App Fill in these details: **Basic Information:** - **App Name**: Content Analytics Dashboard - **Description**: Real-time content statistics and insights - **App Logo URL**: [https://delivery-sitecore.sitecorecontenthub.cloud/api/public/content/84e2fe0c5c864276982940181a1f0fe3?v=39975d16](https://delivery-sitecore.sitecorecontenthub.cloud/api/public/content/84e2fe0c5c864276982940181a1f0fe3?v=39975d16&ref=gowthamaraja.com) (use a proper logo later) **Extension Points:** - ✅ Standalone application - ☐ Full-screen experience - ☐ Site dashboard widgets - ☐ Custom fields **Deployment:** - **Deployment URL**: `http://localhost:3000/standalone` **API Access:** - For now, don't enable any APIs (we'll add this in Part 2) ### Step 4: Activate and Install 1. Click **"Save"** 2. Click **"Activate"** 3. Go to **"My Apps"** in the portal 4. Click **"Install"** on your app --- ## Testing Your App Once installed, you should see "Content Analytics Dashboard" in your Cloud Portal navigation. ### Troubleshooting Common Issues **Issue: SDK initialization fails** - Make sure you're accessing through Cloud Portal, not localhost directly - Check browser console for detailed errors **Issue: App doesn't appear in navigation** - Verify app is "Active" in Developer Studio - Make sure you clicked "Install" in My Apps **Issue: Blank screen** - Check that deployment URL matches your Next.js route - Ensure dev server is running (`npm run dev`) --- ## What's Next? Congratulations! You've just built and deployed your first Sitecore Marketplace app. In **Part 2** - Building all four extension types (standalone, full-screen, widgets, custom fields) - Integrating with XM Cloud APIs to fetch real content data - Creating production-ready components with proper error handling - Adding real-time data updates In **Part 3**, we'll cover: - Deploying to production (Vercel, Netlify, Azure) - Performance optimization and best practices - Security considerations and common pitfalls - Building apps for the public Marketplace ### Useful Resources - [Sitecore Marketplace Documentation](https://doc.sitecore.com/mp/?ref=gowthamaraja.com) - [Marketplace SDK Reference](https://doc.sitecore.com/mp/en/developers/sdk/?ref=gowthamaraja.com) - [Marketplace Starter Kit](https://github.com/Sitecore/marketplace-starter?ref=gowthamaraja.com) --- **Found this helpful?** Share it with your Sitecore developer community! Have questions? Drop them in the comments below. **Next:** [Part 2 - Building Production-Ready Marketplace Apps →](https://www.gowthamaraja.com/building-production-ready-sitecore-marketplace-apps-with-next-js) ### 5 Types of AI Agents Explained: From Reflex to Learning Agents URL: https://www.gowthamaraja.com/types-of-ai-agents-guide/ Last updated: 2026-02-20T02:04:49.000Z ## Table of Contents 1. [What Are AI Agents](#what-are-ai-agents)? 2. [Why Understanding AI Agent Types Matters](#why-understanding-ai-agent-types-matters) 3. [The 5 Main Types of AI Agents](#the-5-main-types-of-ai-agents) - [Simple Reflex Agents](#simple-reflex-agents) - [Model-Based Reflex Agents](#model-based-reflex-agents) - [Goal-Based Agents](#goal-based-agents) - [Utility-Based Agents](#utility-based-agents) - [Learning Agents](#learning-agents) 4. [Comparison Guide: Choosing the Right AI Agent](#comparison-guide-choosing-the-right-ai-agent) 5. [Common Challenges and Limitations](#common-challenges-and-limitations) 6. [The Future of AI Agents](#the-future-of-ai-agents) 7. [Frequently Asked Questions](#frequently-asked-questions) --- ## What Are AI Agents? Did you know that by 2026, over 80% of businesses are expected to deploy some form of AI agents in their operations? From the moment your smartphone's alarm wakes you up to the recommendations you see on Netflix before bed, AI agents are silently orchestrating our digital experiences. But what exactly is an AI agent? In simple terms, an **AI agent** is an intelligent system that perceives its environment through sensors, processes that information, and takes actions to achieve specific goals. Think of it as a digital decision-maker that can operate autonomously—whether it's recommending your next favorite song, navigating a self-driving car through traffic, or optimizing energy consumption in a smart building. What makes AI agents fascinating is their diversity. While some agents simply follow predefined rules (like a thermostat turning on when temperature drops), others learn from experience and adapt their behavior over time (like how your email spam filter gets better at catching junk mail). This spectrum of intelligence and autonomy gives rise to different types of AI agents, each designed for specific tasks and environments. ## Why Understanding AI Agent Types Matters Whether you're a developer building autonomous systems, a business leader evaluating AI solutions, or simply curious about how intelligent systems work, understanding the types of AI agents is crucial. Here's why: - **Better Decision Making:** Choose the right agent type for your specific use case - **Cost Efficiency:** Avoid over-engineering with complex agents when simple ones suffice - **Performance Optimization:** Match agent capabilities to environmental complexity - **Future-Proofing:** Understand which agents can scale and adapt as needs evolve Let's dive into the five primary categories of AI agents that form the foundation of modern intelligent systems. --- ## The 5 Main Types of AI Agents AI agents can be classified based on their intelligence level, decision-making approach, and ability to learn from experience. Each type represents a step up in sophistication and capability. --- ## 1\. Simple Reflex Agents Simple reflex agents are the most fundamental type of AI agents—the building blocks of intelligent automation. They operate purely by reacting to the current state of their environment, without any memory, learning capability, or understanding of cause and effect. ### How Simple Reflex Agents Work These agents follow a straightforward **condition-action rule** structure, often described as *"if this happens, then do that"* logic. They use sensors to perceive the immediate environment and respond instantly based on predefined rules. There's no consideration of past events, no prediction of future consequences—just immediate, reactive behavior. **Decision Flow:** ![Flow diagram of a Simple Reflex AI Agent cycle](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/02/OrderCreated-Email-Flow-2026-02-03-091927.png) Simple Reflex Agents ### Real-World Examples **Automatic Sliding Doors** When motion is detected near the entrance, the door opens. When no movement is sensed, it closes. The system doesn't remember who walked in earlier or predict future foot traffic—it simply reacts to present input. **Sensor-Based Street Lamps** If ambient light drops below a threshold, the lamp switches on automatically. When daylight increases, it switches off. The lamp doesn't track historical light patterns or weather forecasts; it only responds to current brightness levels. **Basic Thermostats** Temperature below 68°F? Turn on heat. Temperature above 72°F? Turn off heat. No consideration for time of day, occupancy, or energy costs. **Motion-Activated Security Lights** Detect movement? Light on. No movement for 5 minutes? Light off. Simple, effective, predictable. ### When to Use Simple Reflex Agents - Predictable environments with clearly defined states - Binary decisions with straightforward rules - Real-time response requirements - Low computational resources available - Minimal maintenance desired ### Limitations - Cannot handle partially observable environments - No adaptation or learning capability - Struggles with complex, multi-step decisions - May oscillate between actions in dynamic environments - No memory of past interactions --- ## 2\. Model-Based Reflex Agents Think of model-based reflex agents as **"Reflex Agents with Memory."** Unlike their simpler cousins that only care about the present moment, these agents maintain an internal representation of the world that helps them understand things they cannot directly observe right now. ### How Model-Based Reflex Agents Work These agents excel in **partially observable environments**—situations where you can't see everything at once. They maintain an internal state (a "world model") by combining: 1. **Current sensor input** (what they see now) 2. **Internal memory** (what they remember) 3. **Transition model** (how they expect the world to change) 4. **Sensor model** (how their observations relate to actual world states) **Decision Flow:** ![Flow diagram of a Model-Based Reflex Agents](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/02/OrderCreated-Email-Flow-2026-02-03-093306.png) Model-Based Reflex Agents ### Real-World Examples **Robot Vacuum Cleaners** A basic vacuum bumps randomly into walls. A model-based vacuum remembers the room layout it has already cleaned, avoiding redundant passes and efficiently covering the entire floor. It builds a map as it goes and knows which areas still need attention. **Self-Driving Cars** If a pedestrian momentarily disappears behind a parked bus, a simple reflex agent might forget they exist. A model-based agent's internal model "remembers" the pedestrian is still there and continues cautious behavior until the person is in view again. **Smart Home Climate Control** These systems track temperature trends, occupancy patterns, and time of day to predict heating/cooling needs. They remember that you typically arrive home at 6 PM and pre-condition the house accordingly. **Autonomous Drones** Maintain stable flight even when GPS signal is temporarily lost by using internal models of physics, wind patterns, and previous position data. ### When to Use Model-Based Reflex Agents - Partially observable environments with hidden information - Tracking state over time is important - Navigation tasks requiring spatial memory - Noisy sensor data needs interpretation - Predictable dynamics in how the environment changes ### Limitations - More computationally expensive than simple reflex agents - Internal model can become outdated or inaccurate - Still reactive rather than proactive - Cannot reason about long-term goals --- ## 3\. Goal-Based Agents Now we enter the realm of **proactive intelligence.** Goal-based agents don't just react—they have a destination in mind and actively plan how to get there. This makes them fundamentally more flexible and powerful than reflex-based agents. ### How Goal-Based Agents Work These agents use **search and planning algorithms** to evaluate different action sequences. They ask, "Which series of actions will help me achieve my goal?" This involves: 1. **Goal representation** (defining success state) 2. **Search space exploration** (considering possible action sequences) 3. **Path planning** (finding routes to the goal) 4. **Flexibility** (finding alternative routes when blocked) **Decision Flow:** ![Flow diagram of a Goal-Based Agents](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/02/OrderCreated-Email-Flow-2026-02-03-093625.png) Goal-Based Agents ### Real-World Examples **GPS Navigation Systems (Google Maps, Waze)** Your goal: reach Dharapuram by 5 PM. If there's a traffic jam on the usual route, the agent doesn't just stop—it recalculates and finds an alternative path. If that route gets blocked too, it adapts again. The goal remains constant; the path is flexible. **Warehouse Robots (Amazon Fulfillment Centers)** Goal: Pick up Package #12345 from Shelf B7\. The robot plans the shortest collision-free path through the warehouse aisles, avoiding other robots and dynamic obstacles. If a route is blocked, it replans instantly. **Chess-Playing AI** Goal: Checkmate the opponent's king. The agent searches through thousands of possible move sequences, evaluating which paths lead to achieving the goal while defending against counter-moves. **Automated Trading Bots** Goal: Maximize portfolio value. The agent plans sequences of buy/sell actions based on market conditions, always working toward the defined goal. ### When to Use Goal-Based Agents - Clear objectives that can be defined formally - Multiple paths to success exist - Dynamic environments requiring adaptation - Sequential decision-making is required - Obstacle avoidance and replanning needed ### Limitations - Can be computationally expensive (search space grows exponentially) - Doesn't consider quality of goal achievement (just reaching vs. reaching optimally) - May find any solution rather than the best solution - Requires explicit goal definition --- ## 4\. Utility-Based Agents If goal-based agents are about **"getting there,"** utility-based agents are about **"getting there in the best way possible."** They don't just achieve goals—they optimize how well goals are achieved using a utility function to measure success quality. ### How Utility-Based Agents Work These agents use a **utility function** (also called a performance measure) that maps states or action outcomes to numerical values representing "happiness" or "desirability." They choose actions that maximize expected utility, considering: 1. **Trade-offs** (speed vs. cost vs. safety) 2. **Conflicting objectives** (multiple competing goals) 3. **Uncertainty** (probabilistic outcomes) 4. **Optimization** (finding the best, not just any, solution) **Decision Flow:** ![Flow diagram of a Utility-Based Agents](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/02/OrderCreated-Email-Flow-2026-02-03-093808.png) Utility-Based Agents ### Real-World Examples **Flight Booking Platforms** Goal: Book a flight from Chennai to Delhi. But which one? The agent calculates utility based on multiple factors: - Price (cheaper = higher utility) - Duration (faster = higher utility) - Departure time (convenient hours = higher utility) - Number of stops (direct = higher utility) Users can adjust weights, and the agent optimizes accordingly. **Autonomous Vehicle Decision-Making** Should the car take the highway (faster but more expensive tolls) or surface streets (slower but free)? The utility function weighs time savings against cost savings, considering traffic conditions, fuel efficiency, and passenger preferences. **Smart Grid Energy Management** When should your home draw power from the grid? The utility function optimizes for: - Cost (draw power during off-peak hours = high utility) - Necessity (critical appliances = high utility) - Environmental impact (renewable energy = high utility) **Medical Diagnosis Systems** Which treatment option maximizes patient outcome utility considering effectiveness, side effects, cost, and recovery time? ### When to Use Utility-Based Agents - Multiple objectives need balancing - Trade-offs must be made systematically - Optimization is more important than just completion - Uncertain outcomes require probabilistic reasoning - Preferences vary by situation or user ### Limitations - Designing good utility functions is difficult - Computational complexity in calculating expected utilities - Requires numerical representation of preferences - May struggle with qualitative or ethical trade-offs --- ## 5\. Learning Agents Welcome to the **pinnacle of AI agent intelligence.** Learning agents don't come with a fixed manual—they improve over time through experience, making them the most adaptive and powerful type of AI agent available today. ### How Learning Agents Work Learning agents have four key components working together: 1. **Learning Element** Responsible for making improvements based on feedback. Uses algorithms like reinforcement learning, supervised learning, or unsupervised learning to update the agent's knowledge. 2. **Critic** Provides feedback on how well the agent is performing. This could be explicit rewards (like game scores) or implicit signals (like user engagement metrics). 3. **Performance Element** The part that actually selects and executes actions—essentially the "current agent" that interacts with the environment. 4. **Problem Generator** Suggests exploratory actions that might lead to better long-term learning, even if they're not immediately optimal. This is the "curiosity" component that prevents the agent from getting stuck in local optima. **Learning Flow:** ![Flow diagram of a Learning Agents](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2026/02/OrderCreated-Email-Flow-2026-02-03-093929.png) Learning Agents ### The Learning Process: Reinforcement Learning Example Let's walk through how a learning agent improves: 1. **Initial State:** Agent has basic or random behavior 2. **Action:** Agent takes an action (could be good or bad) 3. **Feedback:** Critic evaluates the outcome (reward or penalty) 4. **Learning:** Learning element adjusts behavior to increase future rewards 5. **Iteration:** Process repeats millions of times until optimal behavior emerges ### Real-World Examples **Recommendation Systems (Netflix, YouTube, Spotify)** - **Observation:** You watch several sci-fi movies but skip romantic comedies - **Critic Feedback:** Watched videos = positive signal, skipped = negative signal - **Learning:** The agent learns your preferences over time - **Improvement:** Recommendations become increasingly personalized Each user gets a unique experience because the agent continuously learns from their behavior. **AlphaGo and Game-Playing AI** - **Initial State:** Knows Go rules but plays randomly - **Training:** Plays millions of games against itself - **Feedback:** Wins = positive reward, losses = negative - **Learning:** Discovers which move patterns lead to victory - **Result:** Eventually defeats world champion Lee Sedol **Spam Filters (Gmail, Outlook)** - **Initial State:** Generic spam detection rules - **Your Actions:** You mark emails as spam or "not spam" - **Learning:** Filter learns your specific definition of spam - **Improvement:** Becomes personalized to your communication patterns **Autonomous Trading Algorithms** - **Observation:** Market conditions and trade outcomes - **Feedback:** Profit/loss from trades - **Learning:** Discovers profitable patterns and strategies - **Adaptation:** Adjusts to changing market conditions **Chatbots and Virtual Assistants** Modern conversational AI learns from: - Successful task completions - User satisfaction ratings - Conversation patterns - Correction feedback ### Types of Learning in AI Agents **Supervised Learning** Agent learns from labeled examples (e.g., "this email is spam," "this X-ray shows pneumonia") **Unsupervised Learning** Agent discovers patterns without explicit labels (e.g., customer segmentation, anomaly detection) **Reinforcement Learning** Agent learns through trial and error, maximizing cumulative reward (e.g., game playing, robot control) **Transfer Learning** Agent applies knowledge learned in one domain to related domains (e.g., language model applied to multiple tasks) ### When to Use Learning Agents - Complex environments where rules are unknown or change over time - Personalization is crucial - Continuous improvement is desired - Abundant data for training is available - Adaptation to changing conditions is necessary - Explicit programming is too difficult or impossible ### Limitations - Requires substantial training data and computation - Can be unpredictable during learning phase - Risk of learning undesired behaviors from biased data - "Black box" problem—hard to explain why decisions are made - May require human oversight and safety constraints - Can be expensive to train and maintain ### The Ethical Dimension Learning agents raise important questions: - **Bias:** Can learn and amplify societal biases present in training data - **Privacy:** May need sensitive data to learn effectively - **Accountability:** Who's responsible when a learning agent makes a mistake? - **Transparency:** How do we ensure AI decisions are explainable? --- ## Comparison Guide: Choosing the Right AI Agent ### Detailed Comparison Table | **Agent Type** | **Intelligence Level** | **Memory?** | **Learning?** | **Planning?** | **Best For...** | **Computational Cost** | | ----------------- | ---------------------- | ----------- | ------------- | ------------- | ------------------------------------- | ---------------------- | | **Simple Reflex** | Low | No | No | No | Predictable, static environments | Very Low | | **Model-Based** | Low-Medium | Yes | No | No | Partially observable environments | Low-Medium | | **Goal-Based** | Medium | Yes | No | Yes | Target achievement with obstacles | Medium-High | | **Utility-Based** | Medium-High | Yes | No | Yes | Optimization and trade-offs | High | | **Learning** | High | Yes | Yes | Yes | Complex, changing, personalized tasks | Very High | ### Decision Tree: Which Agent Type Should You Use? **Start here:** What's your primary requirement? 1. **Do you need the system to improve over time?** - YES → **Learning Agent** - NO → Continue to question 2 2. **Do you need to optimize for multiple competing objectives?** - YES → **Utility-Based Agent** - NO → Continue to question 3 3. **Do you need to plan multi-step sequences to reach a goal?** - YES → **Goal-Based Agent** - NO → Continue to question 4 4. **Is your environment partially observable (can't see everything at once)?** - YES → **Model-Based Reflex Agent** - NO → **Simple Reflex Agent** ### Hybrid Approaches In practice, many real-world systems combine multiple agent types: **Example: Modern Self-Driving Cars** - **Simple Reflex:** Emergency braking when obstacle suddenly appears - **Model-Based:** Tracking positions of surrounding vehicles - **Goal-Based:** Planning route to destination - **Utility-Based:** Choosing lanes and speeds for optimal efficiency/safety - **Learning:** Improving driving behavior from experience --- ## Common Challenges and Limitations #### Challenge 1: The Frame Problem Agents must decide which aspects of the environment are relevant. In complex worlds, this is computationally intractable. ****Example:** A robot making coffee doesn't need to consider planetary orbits, but how does it know that? #### Challenge 2: The Exploration-Exploitation Trade-Off Learning agents must balance trying new strategies (exploration) vs. using known good strategies (exploitation). ****Example:** Should Netflix recommend a new genre you've never tried, or stick with what it knows you like? #### Challenge 3: Safety and Robustness Agents may behave unpredictably in edge cases or adversarial situations. ****Example:** Adversarial attacks can fool image recognition systems by adding imperceptible noise. #### Challenge 4: Scalability As environments grow more complex, computational requirements explode exponentially. ****Example:** Chess has 10^120 possible games—planning exhaustively is impossible. #### Challenge 5: Ethical Decision-Making Utility functions struggle to capture human values, especially in moral dilemmas. ****Example:** The trolley problem in autonomous vehicles—how do you code ethics? --- ## The Future of AI Agents ### Emerging Trends #### ****Multi-Agent Systems** Rather than single agents, we're seeing swarms of agents cooperating and competing: - Decentralized autonomous organizations (DAOs) - Multi-robot coordination in warehouses - Agent-based economic simulations #### ****Embodied AI** Agents with physical bodies operating in the real world: - Humanoid robots (Boston Dynamics, Tesla Optimus) - Robotic process automation becoming physical - Home assistance robots #### ****Neuromorphic Computing** Hardware designed to mimic biological neurons, enabling: - More efficient learning agents - Real-time adaptation - Lower power consumption #### ****Explainable AI (XAI)** Making learning agents' decisions interpretable: - Regulatory requirements driving adoption - Trust building in high-stakes domains - Debugging and improvement #### ****Hybrid Intelligence** Human-AI collaboration where agents augment rather than replace humans: - Co-pilots and assistants - AI-enhanced decision support - Creative partnerships --- ## Frequently Asked Questions #### What are the main types of AI agents? The five main types of AI agents are: simple reflex agents (rule-based reactions), model-based reflex agents (with internal state memory), goal-based agents (planning toward objectives), utility-based agents (optimizing outcomes), and learning agents (improving through experience). #### Which AI agent type is best for automation? For simple, repetitive tasks in predictable environments, ****simple reflex agents** are ideal due to low cost and reliability. For complex, adaptive automation, ****learning agents** excel because they improve over time and handle variability. #### How do learning agents differ from goal-based agents? Goal-based agents follow predefined planning strategies to achieve fixed goals, while learning agents improve their strategies through experience and feedback. Learning agents can discover better approaches over time, whereas goal-based agents execute predetermined planning algorithms. #### Can AI agents work together? Yes! Multi-agent systems involve multiple AI agents cooperating or competing. Examples include autonomous vehicle fleets coordinating traffic, distributed search and rescue robots, and agent-based market simulations. This enables solving problems too complex for single agents. #### Are AI agents the same as AI models? No. AI models (like neural networks) are the "brains" that make predictions or decisions. AI agents are complete systems that perceive, decide, and act in environments using AI models as components. An agent uses models to make decisions but also has sensors, actuators, and action-selection mechanisms. #### What programming languages are used to build AI agents? The most common languages are: - ****Python** (scikit-learn, TensorFlow, PyTorch for learning agents) - ****Java** (JADE framework for multi-agent systems) - ****C++** (for high-performance robotics) - ****JavaScript/TypeScript** (for web-based agents) - ****R** (for statistical agents) #### How long does it take to train a learning agent? - Simple learning tasks: Minutes to hours - Complex game-playing AI: Days to weeks - Large language models: Weeks to months - Continuous learning systems: Indefinitely, improving throughout deployment Training time depends on problem complexity, data availability, and computational resources. #### What's the difference between AI agents and robotics? AI agents are the "brain" (software decision-making), while robots are the "body" (physical hardware). Robotics incorporates AI agents for control, but also involves mechanical engineering, sensor systems, and actuators. A software-only chatbot is an AI agent but not a robot; a warehouse robot uses AI agents for decision-making. --- ## Conclusion Understanding the types of AI agents—from simple reflex systems to sophisticated learning agents—is essential for anyone working with artificial intelligence in 2026\. Each agent type serves specific purposes, and choosing the right one means balancing complexity, cost, and capability. Whether you're building your first automated system or deploying advanced machine learning solutions, this framework helps you make informed decisions about AI agent architecture. ### Sitecore Content SDK v1.3.1: App Router Moves to General Availability URL: https://www.gowthamaraja.com/sitecore-content-sdk-v1-3-1-app-router-moves-to-general-availability/ Last updated: 2026-02-20T02:05:00.000Z Sitecore has just released Content SDK v1.3.1, marking a significant milestone for the XM Cloud development community. This release brings the highly anticipated **General Availability of App Router support**, transforming what was previously a beta feature into production-ready software that enterprise teams can confidently deploy. ## What makes this Release Important? After months of beta testing and community feedback, App Router support has officially graduated to General Availability status. This isn't just a version bump—it's Sitecore's commitment to modern Next.js architecture and a signal that teams can now migrate their enterprise projects without the uncertainty of beta software. For those who've been following the Content SDK journey, this represents the maturation of a feature that fundamentally changes how we build with XM Cloud. App Router brings improved performance, better SEO, enhanced developer experience, and aligns perfectly with Next.js 13+ standards. ## Key Highlights of v1.3.1 According to the official release notes, this version delivers updates to enhance performance, security, and developer experience, with stability improvements and critical security fixes. The move to GA status means: - **Production-ready stability**: No more worrying about breaking changes that plagued beta releases - **Enterprise confidence**: Teams can commit to App Router migrations without hesitation - **Full support**: Sitecore now fully backs this architecture for production deployments - **Security enhancements**: Critical fixes ensure your applications remain secure ## Why App Router Matters For developers who've been working with Pages Router, the shift to App Router brings several game-changing benefits: ### Modern Architecture Alignment App Router embraces the latest Next.js patterns, including server components, streaming, and improved data fetching. This means your XM Cloud projects leverage cutting-edge web technologies right out of the box. ### Performance Improvements By reducing the amount of JavaScript that runs in the browser and embracing server-side rendering patterns, applications built with App Router deliver faster page loads and better Core Web Vitals scores. ### Cleaner Code Structure The migration to the `app/` directory brings more intuitive file organization, making projects easier to navigate and maintain. Data fetching becomes more declarative, and the separation of concerns between server and client components creates cleaner architecture. ### Better Developer Experience With server components as the default, developers write less boilerplate code and the framework handles more optimization automatically. This leads to faster development cycles and fewer potential bugs. For more details on the release, visit the [official Sitecore Developer Portal changelog](https://developers.sitecore.com/changelog/sitecoreai/15122025/content-sdk-v1.3.1-released-with-general-availability-of-app-router?ref=gowthamaraja.com). ### Migrating from JSS to Sitecore Content SDK 1.x in SitecoreAI (XM Cloud) – SDK Lifecycle Deep Dive URL: https://www.gowthamaraja.com/migrating-from-jss-to-sitecore-content-sdk-1-x-in-sitecoreai-xm-cloud-sdk-lifecycle-deep-dive/ Last updated: 2026-02-20T02:05:11.000Z While working hands-on with the official **Sitecore PLAY! Summit** demo – one of the most complex, production-grade JSS applications in the ecosystem (50+ components, multisite middleware, OrderCloud, Sitecore Search, Content Hub DAM, Auth0, and more) – I attempted a full migration to **Sitecore Content SDK 1.2.1**. The results from the completed phases were impressive: **bundles \~45% smaller, dramatically fewer files touched, and far simpler services** – even before finishing the component migration. This post is the real-world chronicle of that journey, refined into a repeatable, Next.js-focused guide you can apply today. Whether you’re preparing for the 2026 JSS sunset or simply want a leaner, SitecoreAI-ready codebase, here’s everything I learned – the wins, the pitfalls, and the exact commands that actually worked. ## Why Migrate PLAY! Summit (and Your App) to Content SDK? | Aspect | JSS 22.x (PLAY! Summit today) | Content SDK 1.x (After migration) | Real Impact (measured on PLAY!) | | ------------------------------- | ---------------------------------------------- | ------------------------------------------------- | ---------------------------------- | | **Bundle Size** | Bloated by unused chromes and plugins | **\~49% smaller** thanks to explicit tree-shaking | \~190 KB vs 280 KB initial | | **File & Code Lines** | Scattered configs, temp folder, generated code | **81% fewer files, 39% less code** | Much cleaner repository | | **Data Fetching** | LayoutService + heavy factory boilerplate | Unified SitecoreClient (15 lines vs 50+) | Faster, more maintainable services | | **Editing Experience** | Experience Editor chromes (being deprecated) | XM Cloud Pages only – faster and modern | Happier content authors | | **Middleware** | Plugin array + generated code | defineMiddleware \+ typed functions | Clearer configuration | | **Personalization & Analytics** | Works but fragmented | Native @sitecore-cloudsdk/events | Direct flow into SitecoreAI | Bottom line: Content SDK isn’t “JSS lite” – it’s the version Sitecore built specifically for XM Cloud and SitecoreAI. ## My Migration Status (Honest Update – November 22, 2025) **Completed & Working** - Node.js 22 + Next.js 15 + React 19 upgrade - JSS 22.8 baseline → All JSS packages removed cleanly - Content SDK 1.2.1 installed without conflicts - Centralized `sitecore.config.ts` \+ `sitecore.cli.config.ts` - All services (layout, dictionary, editing) migrated to `SitecoreClient` - Solid foundation ready for the rest **Still Pending** - Updating 50+ components (field helpers, context, etc.) - Complex middleware plugins (multisite, personalization, redirects) - Third-party integrations (OrderCloud, Search, CDP, Auth0) - Full regression testing **Verdict:** The foundation is already cleaner and faster than the original JSS version – finishing the migration (or starting fresh) is absolutely worth it. ## Pre-Migration Checklist 1. **Node.js 22+** – Non-negotiable (`nvm use 22.17.1`) 2. Upgrade to JSS 22.8.0 (required bridge step) 3. Create a Git branch: `feature/content-sdk-migration` 4. Backup `.env` and take an XM Cloud environment snapshot Spin up a reference app: ```bash npx create-content-sdk-app@latest play-summit-reference --template nextjs ``` ## Step-by-Step Migration Guide (Next.js – What Actually Worked on PLAY!) ### 1\. Dependency Overhaul ```bash # CRITICAL: Must be on Node.js 22 node --version # → v22.x.x # Remove ALL JSS packages in ONE command npm uninstall @sitecore-jss/sitecore-jss-nextjs \ @sitecore-jss/sitecore-jss-cli \ @sitecore-jss/sitecore-jss-dev-tools \ @sitecore-jss/sitecore-jss-react --legacy-peer-deps # Install ONLY the Next.js SDK (core is pulled automatically) npm install @sitecore-content-sdk/nextjs@latest --legacy-peer-deps ``` > **Golden Rule:** Never install both `@sitecore/content-sdk` and `@sitecore-content-sdk/nextjs` explicitly – it breaks the dependency tree. ### 2\. Central Configuration `sitecore.config.ts` (project root) ```ts import { defineSitecoreConfig } from '@sitecore-content-sdk/nextjs'; export const sitecoreConfig = defineSitecoreConfig({ siteName: process.env.SITECORE_SITE_NAME!, apiKey: process.env.SITECORE_API_KEY!, endpoint: process.env.SITECORE_API_URL!, editingSecret: process.env.SITECORE_EDITING_SECRET!, edgeUrl: process.env.NEXT_PUBLIC_SITECORE_EDGE_URL!, defaultLanguage: 'en', generateStaticPaths: process.env.GENERATE_STATIC_PATHS === 'true', rootPlaceholders: ['headless-header', 'headless-main', 'headless-footer'], }); ``` Update `.env.local` ```env # OLD → NEW SITECORE_API_HOST=... → SITECORE_API_URL=... JSS_EDITING_SECRET=... → SITECORE_EDITING_SECRET=... DISABLE_SSG_FETCH=false → GENERATE_STATIC_PATHS=true SITECORE_EDGE_URL=... → NEXT_PUBLIC_SITECORE_EDGE_URL=... ``` ### 3\. Unified SitecoreClient `src/lib/sitecore-client.ts` ```ts import { createSitecoreClient } from '@sitecore-content-sdk/nextjs'; import { sitecoreConfig } from '../../sitecore.config'; export const sitecoreClient = createSitecoreClient(sitecoreConfig); ``` Layout service example (70% less code): ```ts import { sitecoreClient } from './sitecore-client'; export async function getLayoutData(path: string, language: string) { return await sitecoreClient.layout.fetch({ path, language }); } ``` ### 4\. Explicit Component Mapping `src/lib/component-map.ts` ```ts import Hero from '@/components/Hero'; import ContentBlock from '@/components/ContentBlock'; // …import all components export const componentMap = { Hero, ContentBlock, // Use exact datasource template names! }; ``` ### 5\. Component Updates ```tsx // Before (JSS) import { Text, Image } from '@sitecore-jss/sitecore-jss-nextjs'; // After (Content SDK) import { Text, Image } from '@sitecore-content-sdk/nextjs'; ``` Also use `rendering.uid` for keys and remove chromes. ### 6\. Middleware – The Modern Way ```ts import { defineMiddleware } from '@sitecore-content-sdk/nextjs'; import { sitecoreConfig } from './sitecore.config'; export default defineMiddleware({ config: sitecoreConfig, async redirect(req) { /* logic */ }, async personalize(req) { /* logic */ }, }); export const config = { matcher: '/((?!api|_next/static|_next/image|assets|favicon.ico|sw.js).*)' }; ``` ### 7\. Dynamic Route Page (\[\[...path\]\].tsx) ```tsx import { SitecoreProvider, ComponentRenderer } from '@sitecore-content-sdk/nextjs'; import { componentMap } from '@/lib/component-map'; export default function SitecorePage({ layoutData }: SitecorePageProps) { return ( {layoutData.sitecore.route?.placeholders['headless-main']?.map(c => ( ))} ); } ``` ## Common Pitfalls & Fixes from the PLAY! Trenches | Problem | Fix | | ---------------------------------- | ----------------------------------------------------- | | npm peer dependency hell | Always use \--legacy-peer-deps \+ combine uninstalls | | Node.js 18 “EBADENGINE” warnings | Switch to Node.js 22 **before** any npm work | | Blank preview / missing components | Add component to component-map.ts | | Middleware not firing | Use the exact matcher array shown above | | Static generation failing | Temporarily set GENERATE\_STATIC\_PATHS=false in .env | ## SitecoreAI Advantages You’ll Feel Immediately - Native `@sitecore-cloudsdk/events` → events flow straight into SitecoreAI for smarter personalization - Smaller payloads = faster variant delivery - XM Cloud Pages is noticeably snappier without chromes In my benchmarks, Time-to-Interactive dropped \~35% on the homepage. ## Summary The PLAY! Summit foundation on Content SDK is already cleaner, faster, and more future-proof than the original JSS version – and I’m only halfway through. Start with the dependency + config steps, measure the immediate bundle wins, then decide: finish the migration or spin up a fresh Content SDK app and port features incrementally. **Resources** - Official Migration Guide → [https://doc.sitecore.com/sai/en/developers/content-sdk/migrate-jss-22-8-next-js-apps-to-content-sdk-1-0.html](https://doc.sitecore.com/sai/en/developers/content-sdk/migrate-jss-22-8-next-js-apps-to-content-sdk-1-0.html?ref=gowthamaraja.com) - PLAY! Summit Repo → [https://github.com/Sitecore/Sitecore.Demo.XmCloud.PlaySummit](https://github.com/Sitecore/Sitecore.Demo.XmCloud.PlaySummit?ref=gowthamaraja.com) - [https://explorewithnikitavashisht.wordpress.com/2025/09/04/migrating-next-js-apps-to-sitecore-content-sdk/](https://explorewithnikitavashisht.wordpress.com/2025/09/04/migrating-next-js-apps-to-sitecore-content-sdk/?ref=gowthamaraja.com) - [https://medium.com/@gaur.arun777/blog-1-introduction-to-sitecore-content-sdk-17b64ae1e30e](https://medium.com/@gaur.arun777/blog-1-introduction-to-sitecore-content-sdk-17b64ae1e30e?ref=gowthamaraja.com) ### How to Integrate Gradial with Sitecore XM Cloud: A Practical Guide for Faster Campaign Automation URL: https://www.gowthamaraja.com/how-to-integrate-gradial-with-sitecore-xm-cloud-a-practical-guide-for-faster-campaign-automation/ Last updated: 2025-11-22T09:19:13.000Z If you’ve been working with Sitecore XM Cloud (now evolving into the broader **SitecoreAI** platform as of November 2025) and wondering how to take your marketing automation to the next level, the strategic partnership with Gradial — announced on **July 14, 2025** — is a game-changer you don’t want to miss. Gradial brings **agentic AI orchestration** directly into the Sitecore ecosystem, transforming simple marketing briefs into fully executed, hyper-personalized campaigns with far less manual intervention. This guide incorporates the latest details from official announcements, Gradial/Sitecore documentation, and real-world client testing. The efficiency gains are substantial — especially now with SitecoreAI’s Agentic Studio and unified platform that launched in November 2025. --- ## Why the Sitecore + Gradial Partnership Changes Everything Traditional campaign setup is fragmented: content authoring in XM Cloud/Pages, segmentation in CDP/Personalize, asset management in Content Hub, rules configuration, testing, and deployment. Powerful, but slow and labor-intensive. Gradial acts as an **AI-powered orchestration layer** that securely integrates with Sitecore XM Cloud, Content Hub, and the full SitecoreAI suite. It automates the entire execution layer: - Pulls audience segments and data - Selects and matches content variants and assets - Generates personalization rules and experiences - Optimizes in real-time based on performance signals - Complements (does **not** replace) Sitecore Stream and the new SitecoreAI features like Agentic Studio Key advantages: - Campaigns that took days or weeks now launch in **hours** - 70–90 % reduction in operational handoffs, tickets, and delays - All data and operations stay secure inside the Sitecore ecosystem - Scales personalization without scaling headcount - Dramatically lowers total cost of ownership > **Best fit:** XM Cloud Plus or full SitecoreAI tenants with Personalize/CDP enabled. As of November 2025, all existing XM Cloud customers are automatically upgraded to SitecoreAI. ## Prerequisites - Active Sitecore XM Cloud / SitecoreAI environment with Deploy app access - Automation Client credentials (Authoring + Rendering scopes) - Gradial account (sign up at gradial.com or via your Sitecore rep) - Basic familiarity with XM Cloud GraphQL/REST endpoints and Rendering Hosts Create credentials: **XM Cloud Deploy → Credentials → New Automation Client** ## Step-by-Step: Connecting Gradial to Sitecore XM Cloud / SitecoreAI Gradial connects via Sitecore’s official GraphQL and REST APIs — no custom code required. 1. Log into Gradial → **Settings → Integrations** 2. Add Integration → **Sitecore XM Cloud** 3. Fill in the details: - Connection Name: e.g., “Prod-SitecoreAI” - Hostname: your XM Cloud / SitecoreAI host (e.g., xmcloud-myorg.sitecorecloud.io) - Author API Client ID & Secret (from Deploy) - Preview Rendering Host (found in Content Editor → Rendering Hosts) 4. (Optional but recommended) Connect Content Hub separately for asset workflows 5. Test the connection — Gradial will validate and list your projects/environments 6. For advanced flows: Enable Sitecore’s **Agent API** or use the new **SitecoreAI Agentic Studio** (November 2025+) Example configuration: ``` Connection Name: Production-SitecoreAI Hostname: xmcloud-myorg-prod.sitecorecloud.io Client ID: abc123... Client Secret: xyz789... Preview Rendering Host: preview-myorg.sitecorecloud.io ``` Auth errors? Double-check scopes include **Authoring**, **Rendering**, and appropriate Content Hub REST permissions. ## Creating Your First AI-Powered Campaign 1. In Gradial, start a new Agent or pick a template (“Campaign Orchestrator”, “Hyper-Personalization Flow”, etc.) 2. Gradial’s agents will: - Query SitecoreAI for content, items, and assets - Pull segments from CDP/Personalize - Auto-generate variants, rules, and decisions - Push everything to Pages/Experience Editor or Content Hub for review 3. Review → tweak (human-in-the-loop) → approve → deploy with one click Submit a natural-language brief, e.g.: > “Launch a holiday promotion for returning EU visitors — personalize banners, CTAs, and product recommendations based on past purchases and browsing behavior.” Verification is instant: new components appear in Pages, decisions in Personalize, assets tagged in Content Hub. With the November 2025 SitecoreAI release you can now extend this further using **Agentic Studio** — visually build or customize agents, no code required. ## Common Issues & Quick Fixes - Rate limits/delays → SitecoreAI limits are generous; throttle bulk operations - Initial sync on large repos → 5–15 minutes is normal - Permissions → Gradial service account needs read/write on target folders/projects - Content Hub quirks → Use a dedicated API user with DAM/CMP roles - Deeper customizations → SitecoreAI Agent API or Sitecore Studio Marketplace ## The Long-Term Vision The July 2025 partnership was just the beginning. The November 2025 **SitecoreAI** launch — with Agentic Studio, unified licensing, and 20+ pre-built agents — takes everything to the next level. We’re moving from manual personalization to truly **agentic systems** where AI does the heavy lifting and marketers focus on strategy and creativity. If you’re still on legacy Sitecore XP/XM or cobbling together disconnected tools, migrating to SitecoreAI + Gradial is the logical next step. Spin up a dev environment and try it . Questions or roadblocks? Drop a comment below or ping me on LinkedIn. Happy to help! If you’d like to dive deeper into the Sitecore + Gradial integration, [Prabhu Ranganathan](https://www.linkedin.com/in/prabhu-ranganathan/?ref=gowthamaraja.com) and I recently presented a full session on exactly this topic at [SUGCBE (Sitecore User Group Coimbatore)](https://www.linkedin.com/groups/14208028/?ref=gowthamaraja.com). Here’s the recording Sitecore XM Cloud and Gradial References: [Sitecore - Gradial DocsConnecting Gradial to Sitecore![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/apple-touch-icon.png)Gradial Docs![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/image)](https://docs.gradial.com/onboarding/integrations/sitecore?ref=gowthamaraja.com) [https://www.sitecore.com/resources/insights/artificial-intelligence/hyper-personalization-sitecore-gradial](https://www.sitecore.com/resources/insights/artificial-intelligence/hyper-personalization-sitecore-gradial?ref=gowthamaraja.com) [Sitecore XM Cloud and Gradial: The Future of Intelligent Digital Experience DeliveryAfter more than 10 years working with Sitecore across on-prem, XP, and composable architectures, it’s inspiring to see how far the platform…![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/icon/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156)MediumPrabhu Ranganathan![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/thumbnail/1-eOHDLTHnkZwF5Y0L-nzAOg.png)](https://medium.com/@prabhu.ranganathan/sitecore-xm-cloud-and-gradial-the-future-of-intelligent-digital-experience-delivery-9ad86579ac35?ref=gowthamaraja.com) ### SitecoreAI and Sitecore Studio: A Game-Changer for Developers in the Digital Experience Space URL: https://www.gowthamaraja.com/sitecoreai-and-sitecore-studio-a-game-changer-for-developers-in-the-digital-experience-space/ Last updated: 2025-11-22T09:17:58.000Z --- # Sitecore Symposium 2025 Recap: The Bold New Era of SitecoreAI and Sitecore Studio If you were at **Sitecore Symposium 2025 in Orlando** or following the buzz on LinkedIn, you’d know this wasn’t just another product launch. This was **Sitecore making a bold statement** about where digital experiences are headed — and honestly, as someone who’s been working with Sitecore for a while now, I’m genuinely excited about what this means for us developers. --- ## The Big Picture: Welcome to SitecoreAI and Sitecore Studio Let’s get straight to it. **Sitecore just unveiled SitecoreAI**, their next-generation digital experience platform built with AI at its core. And this isn’t about simply slapping AI features onto an existing platform — they’ve **reimagined how we’ll build digital experiences** going forward. The platform unifies everything — **XM Cloud, DAM, MRM, and CMP** — into one **composable SaaS system**. For those of us juggling multiple tools and systems, this **consolidation is a breath of fresh air**. What really caught my attention, though, is how they’re positioning this for *“the world beyond the website.”* We all know traffic patterns are changing, with AI-driven discovery replacing traditional search — and **SitecoreAI seems to be addressing that head-on.** --- ## Agentic Studio: Where the Magic Happens Here’s where things get interesting for us developers. At the heart of SitecoreAI is the **Agentic Studio** — think of it as your new workspace where **marketers and AI collaborate** instead of just coexisting. The platform launches with **20+ pre-built AI agents** out of the box, handling everything from campaign planning to content migration and testing. You can even **create custom agents and workflows** using simple visual tools — *no coding required for basic setups.* But here’s the best part for developers: the entire system runs on a **Model Context Protocol (MCP)** layer that defines every product as an action an agent can use to perform specific tasks. ### Key Components of Agentic Studio - **Agentic Flows:** Orchestrate multi-step personalized campaigns with complete visibility. - **Spaces:** Real-time collaboration environments where humans and AI work together, creating continuous feedback loops for improvement. --- ## Sitecore Studio: The Innovation Layer We’ve Been Waiting For Now, this is where developers truly come into play. **Sitecore Studio** was announced as the **breakthrough innovation layer** of SitecoreAI — a framework that allows us to **build and customize AI-powered agents and workflows** within secure, governed environments. ### 🔧 Sitecore Studio Consists of Four Connected Environments 1. **Agentic Studio** – For composing AI workflows 2. **App Studio** – For custom application development 3. **Sitecore Connect** – For integrations 4. **Marketplace** – For sharing and discovering innovations What’s refreshing here is that Sitecore is finally ending the old trade-off between **SaaS simplicity** and **enterprise flexibility**. We get the benefits of a **managed SaaS platform**, while still retaining the freedom to **customize and extend** it as needed. For anyone who’s struggled with rigid SaaS systems — this is a big step forward. --- ## What This Means for Migration and ROI If you’re working with **legacy Sitecore XP** instances or other CMS platforms, there’s great news. Sitecore introduced **SitecoreAI Pathway** — an AI-powered service that **automates content migration**, reportedly cutting migration time by *two-thirds.* It supports migrations **from Sitecore XP and even non-Sitecore platforms.** According to a **Total Economic Impact study**, organizations using **XM Cloud** achieved: - **371% ROI** - **50% increase in digital conversions** And now, those same capabilities **power SitecoreAI**. --- ## Technical Foundation: Built on Azure From an infrastructure perspective, **SitecoreAI runs on Microsoft Azure**. For existing **XM Cloud customers**, the **upgrade path is seamless** — no migration needed, full data continuity, and **instant access** to Agentic Studio and pre-built AI agents. The platform also integrates a **unified knowledge graph**, reinforcing the base for embedded AI capabilities. It’s built on a **governed AI framework**, ensuring **transparency, security, and compliance** with enterprise and regulatory standards. --- ## Developer Takeaway What excites me most about **SitecoreAI** and **Sitecore Studio** is how they’re **democratizing AI capabilities** while still giving developers the **extensibility and control** we need. The **no-code/low-code** approach empowers marketers to do more independently — but the **underlying architecture** remains robust enough for advanced **custom development**. In short, Sitecore is **bridging the gap between innovation and implementation**, and I can’t wait to start building with it. ### Sitecore XM Cloud Just Got the New Publishing Jobs Table UI and API URL: https://www.gowthamaraja.com/sitecore-xm-cloud-just-got-the-new-publishing-jobs-table-ui-and-api/ Last updated: 2025-11-22T09:18:21.000Z Let’s be honest—publishing in Sitecore XM Cloud has sometimes felt like sending your content into the void and hoping for the best. You hit publish, cross your fingers, and wait. And wait. And maybe check a log file or two if you're lucky enough to have access. But that’s all changing. Sitecore just dropped a major update that’s going to make publishing feel less like a guessing game and more like mission control. The new Publishing Jobs Table UI and a seriously powerful REST API are here, and they’re rolling out fully on September 17, 2025\. Whether you’re a marketer trying to hit a campaign deadline or a developer automating your CI/CD pipeline, this update is built to make your life easier. Let’s break it down. --- ### UI That Actually Tells You What’s Going On Picture this: a clean, intuitive dashboard that shows you every publishing job from the last 30 days. No more digging through logs or waiting for someone in IT to tell you what’s happening. The new Publishing Jobs Table UI gives you real-time visibility into your publishing queue—who started what, when it started, how long it took, and whether it succeeded or failed. Here’s what stands out: - **Live Queue Tracking**: You can see exactly where your job sits in the queue. No more blind waiting. - **Detailed Timings**: Start time, finish time, queue time, run time—it’s all there. - **Who Did What**: Know who triggered the job, what type it was (smart publish, full republish), and what options were selected. - **Error Insights**: Hover over job statuses to get the full story—partial successes, failures, and everything in between. And the best part? You don’t need to be an admin to use it. Marketers can now check job statuses themselves, which means fewer Slack messages to devs and faster decision-making. --- ### Automation Lovers, Rejoice: The New Publishing API Is a Beast If you’re the kind of person who gets excited about scripting and automation, the new Publishing REST API is going to be your new best friend. It’s fully documented and ready to plug into whatever tools you’re using—Postman, Node.js, .NET, Python, you name it. Here’s what you can do: - **Trigger Publishes Programmatically**: Choose your targets, languages, and options. - **Monitor Jobs in Real Time**: Pull job details, check statuses, and even audit user permissions. - **Cancel Jobs Mid-Flight**: No more restarting environments just to stop a runaway publish. - **Extract Metrics for Reporting**: Perfect for dashboards, audits, or just keeping tabs on performance. This isn’t just a dev tool—it’s a gateway to smarter workflows. Think Slack alerts when jobs finish, nightly publishes that run automatically, or even auto-cancel logic if a job takes too long. --- ### What Used to Be Frustrating and How This Fixes It? Before this update, publishing in XM Cloud had some serious blind spots: - You couldn’t see where your job was in the queue. - Cancelling a job often meant restarting the whole environment. - Marketers had to rely on devs for status updates. - Developers had to build clunky workarounds just to automate basic tasks. Now? You’ve got transparency, control, and flexibility. The UI gives you a clear picture of what’s happening, and the API lets you build whatever publishing logic your team needs. --- ### Real-World Scenarios where it really helps 1. A publish stuck in the queue can be cancelled and restarted to go live faster. 2. Publishes can be scheduled automatically at night, with stats tracked for performance. 3. If a publish is slow, the UI shows the reason (like media processing) so it can be fixed quickly. 4. Job histories can be exported by user or date for audits—no manual effort needed. This update is more than just an add-on—it’s a big improvement. The new Publishing Jobs Table UI and API make publishing in Sitecore faster, easier, and more reliable. Whether you’re coding or just need to push content live, these features save time and remove guesswork. Happy publishing! ### How to Implement Bulk Deletion for Push Source Documents in Sitecore Search? URL: https://www.gowthamaraja.com/how-to-implement-bulk-deletion-for-push-source-documents-in-sitecore-search/ Last updated: 2025-11-22T09:18:47.000Z Sitecore Search is a powerful tool for managing content, and I recently explored its functionality, specifically in the context of the Push Source. During my exploration, I encountered a challenge: deleting specific types of documents in bulk. Surprisingly, Sitecore Search does not provide a direct method for achieving this scenario. Driven by this limitation, I began working on a solution to address this gap. ## Document Deletion in Sitecore Search When it comes to deleting documents, Sitecore Search offers two primary methods: 1. **Sitecore Search Customer Engagement Console (CEC) :** This is a user-friendly interface; however, it does not support bulk deletion of multiple documents simultaneously. 2. **Sitecore Injection API:** This API provides more flexibility but is limited to deleting one document at a time. To delete a document using the Injection API, you can utilize the following endpoint: ``` {base-URL}/ingestion/v1/domains/{domainID}/sources/{sourceID}/entities/{entityID}/documents/{documentID}?locale={locale} ``` While this API is effective for single-document deletion, it lacks the ability to handle multiple document IDs in a single request. Consequently, if you need to delete multiple documents, you must call the API repeatedly for each document ID. ## Challenges in Bulk Deletion The first hurdle is obtaining the document IDs. To accomplish this, you'll need to use the API to fetch all relevant document IDs and then pass them one-by-one to the delete endpoint. This repetitive process can be tedious and time-consuming, especially when working with large sets of documents. ## A Practical Solution: Automating Bulk Deletion with PowerShell To address this issue, I developed a PowerShell script to automate the bulk deletion process. This script simplifies the task by programmatically fetching document IDs and calling the delete API for each ID. Here’s how the PowerShell script can help: - Fetch document IDs using the appropriate API calls. - Loop through the document IDs and invoke the delete API for each one automatically. - Provide flexibility for customization to meet specific requirements. #### **Fetch ID from Search:** ``` # Define the API URL and headers for the Sitecore Search API # - $apiUrl: Specifies the API endpoint for retrieving document IDs. # - $headers: Contains the necessary headers, including domain ID, content type, # and authorization token, for making authenticated requests to the API. $apiUrl = 'https://discover.sitecorecloud.io/discover/v2/{domainid}' # Replace with your actual Domain ID $headers = @{ 'rfk.domainId' = 'rfkid_7' # Replace with your actual domain ID 'Content-Type' = 'application/json' 'Accept' = 'application/json' 'Authorization' = '' # Insert your actual token } # Specify the output file where all document IDs will be saved in JSON format $outputFile = 'delete_document.json' # Initialize variables for paginated API requests # - $offset: Tracks the starting point for each batch of results (pagination). # - $limit: Specifies the maximum number of items to retrieve per API call. # - $totalItems: Will store the total number of items available from the API. # - $allContent: An array to accumulate all retrieved document details (e.g., IDs). $offset = 0 $limit = 100 $totalItems = $null $allContent = @() # Array to store all extracted content do { # Prepare the JSON request payload for fetching document IDs # - $body: Constructs the API request body with search parameters, such as entity, # fields to extract ('id'), batch size ($limit), and starting point ($offset). $body = @{ widget = @{ items = @(@{ entity = 'product' # Specify the entity type to search for (e.g., 'product'). rfk_id = 'product_search' # Replace with your actual RFK ID search = @{ content = @{ fields = @('id') # Specify which fields to retrieve (e.g., 'id'). } limit = $limit # Number of items to retrieve in each batch. offset = $offset # Starting point for the current batch. } sources = @('') # Specify the source ID to target the appropriate data source. }) } } | ConvertTo-Json -Depth 10 -Compress # Convert the request body to a JSON string. # Make the API call using the POST method and capture the response # - $response: Contains the API's response, including document IDs and pagination info. $response = Invoke-RestMethod -Uri $apiUrl -Headers $headers -Method Post -Body $body # Extract relevant data from the API response # - $content: Holds the list of document details (e.g., IDs) for the current batch. # - $totalItems: Indicates the total number of items available for retrieval. $content = $response.widgets[0].content $totalItems = $response.widgets[0].total_item # Append the retrieved document details to the $allContent array # This ensures all document details across multiple batches are stored. foreach ($item in $content) { $allContent += @{ id = $item.id # Document ID. source_id = $item.source_id # Source ID of the document. } } # Log progress by displaying the current offset being processed Write-Host "Processed offset $offset" # Increment the offset to fetch the next batch of results in the subsequent API call $offset += $limit } while ($offset -lt $totalItems) # Continue fetching data until all items are retrieved. # Write the collected document details to the specified JSON file # - Converts the $allContent array to a JSON format and saves it to $outputFile. $allContent | ConvertTo-Json -Depth 10 | Out-File -FilePath $outputFile -Encoding utf8 # Log completion message indicating where the output file is stored Write-Host "Processing complete. The data is saved in '$outputFile'." ``` The above code will fetch all the Ids from the Search Entity. If you want to do a filtering by type or any other attributed you can make use of Search Result Filters. #### **Delete IDs from the output of above Script.** This script fetch the IDs from the delete\_document.json file and iterate through and delete the document ID from the Search. ``` # Define script parameters to customize bulk document deletion # - $JsonFilePath: Mandatory parameter specifying the path to the input JSON file with document IDs. # - $LogFilePath: Optional parameter specifying the path for the log file (default: './bulk_deletion.log'). # - $ApiDomain: Optional parameter specifying the Sitecore API domain ID (default: "22764180680"). # - $ApiSource: Optional parameter specifying the Sitecore API source ID (default: "1088192"). # - $ApiToken: Optional parameter specifying the authentication token for Sitecore API access. # - $Locale: Optional parameter specifying the locale (default: "en_us"). param( [Parameter(Mandatory = $true)] [string]$JsonFilePath, [Parameter(Mandatory = $false)] [string]$LogFilePath = ".\bulk_deletion.log", [Parameter(Mandatory = $false)] [string]$ApiDomain = "", [Parameter(Mandatory = $false)] [string]$ApiSource = "", [Parameter(Mandatory = $false)] [string]$ApiToken = "", [Parameter(Mandatory = $false)] [string]$Locale = "en_us" ) # Function to log messages with timestamps # - $Message: The log message to write both to the console and the log file. function Write-Log { param($Message) $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" "$timestamp - $Message" | Add-Content -Path $LogFilePath Write-Host $Message } # Function to delete a single Sitecore Search document using the API # - $DocumentId: Mandatory parameter specifying the document ID to delete. # - $SourceId: Mandatory parameter specifying the source ID of the document. function Remove-SitecoreSearchDocument { param( [Parameter(Mandatory = $true)] [string]$DocumentId, [Parameter(Mandatory = $true)] [string]$SourceId ) # Construct the API URL using dynamic parameters $apiUrl = "https://discover.sitecorecloud.io/ingestion/v1/domains/$ApiDomain/sources/$SourceId/entities/map/documents/$DocumentId`?locale=$Locale" $headers = @{ 'Accept' = 'application/json' 'Authorization' = $ApiToken } Write-Log "Making DELETE API call to: $apiUrl" try { # Invoke the REST API DELETE request $response = Invoke-RestMethod -Uri $apiUrl -Method Delete -Headers $headers Write-Log "Document successfully deleted: $DocumentId" return @{ success = $true documentId = $DocumentId sourceId = $SourceId } } catch { # Log error details for unsuccessful deletion attempts Write-Log "Error deleting document: $DocumentId" Write-Log "Error details:" Write-Log $_.Exception.Message if ($_.ErrorDetails) { Write-Log "Response body:" Write-Log $_.ErrorDetails.Message } elseif ($_.Exception.Response) { Write-Log "Response body:" try { $rawResponse = $_.Exception.Response.Content.ReadAsStringAsync().Result Write-Log $rawResponse } catch { Write-Log "Unable to read error response content: $_" } } return @{ success = $false documentId = $DocumentId sourceId = $SourceId error = $_.Exception.Message } } } # Ensure the input file exists; exit if not found if (-not (Test-Path $JsonFilePath)) { Write-Log "Error: Input file not found at path: $JsonFilePath" exit 1 } # Create or clear the log file if (Test-Path $LogFilePath) { Clear-Content $LogFilePath } else { New-Item -Path $LogFilePath -ItemType File -Force | Out-Null } Write-Log "Starting bulk document deletion process..." Write-Log "Reading JSON file: $JsonFilePath" try { # Read and parse the JSON file containing document IDs $jsonContent = Get-Content $JsonFilePath -Raw | ConvertFrom-Json } catch { # Log and exit if JSON file parsing fails Write-Log "Error: Failed to parse JSON file: $_" exit 1 } # Initialize counters for tracking the deletion process $totalDocuments = $jsonContent.Count $processedCount = 0 $successCount = 0 $failureCount = 0 Write-Log "Found $totalDocuments documents to delete" foreach ($doc in $jsonContent) { $processedCount++ $documentId = $doc.id $sourceId = $doc.source_id Write-Log "Processing document $processedCount of $totalDocuments (ID: $documentId, Source: $sourceId)" # Call the function to delete the document and capture the result $result = Remove-SitecoreSearchDocument -DocumentId $documentId -SourceId $sourceId if ($result.success) { $successCount++ Write-Log "Success - Document ID: $documentId deleted" } else { $failureCount++ Write-Log "Error - Document ID: $documentId - Error: $($result.error)" } # Add a small delay to prevent overwhelming the API Start-Sleep -Milliseconds 500 } Write-Log "Deletion completed:" Write-Log "Total documents processed: $totalDocuments" Write-Log "Successfully deleted: $successCount" Write-Log "Failed deletions: $failureCount" # Output summary to console Write-Host "" Write-Host "Deletion Summary:" -ForegroundColor Cyan Write-Host "Total documents processed: $totalDocuments" -ForegroundColor White Write-Host "Successfully deleted: $successCount" -ForegroundColor Green Write-Host "Failed deletions: $failureCount" -ForegroundColor Red ``` This solution significantly reduces the manual effort and ensures efficiency when handling bulk deletion tasks. This solution addresses the current limitation in Sitecore Search by using a PowerShell script for bulk deletion. However, it highlights the need for Sitecore to introduce an API dedicated to bulk deletion, which would make workflows easier and improve efficiency for developers working with Push Sources. If you encounter similar issues, you can customize and use this script to simplify the task. Until Sitecore provides a native bulk deletion feature, this script offers a reliable and practical workaround. ### SUGCON India 2024 Recap: Key Insights and Takeaways for Sitecore Users URL: https://www.gowthamaraja.com/sugcon-india-2024-recap-key-insights-and-takeaways-for-sitecore-users/ Last updated: 2025-11-25T13:45:40.000Z ## A Thrilling First Encounter in SUGCON Attending SUGCON India for the first time was an exhilarating experience. It was incredibly rewarding to meet key figures from the Sitecore community in person and engage in meaningful networking. The community is buzzing with energy and openness, making it a perfect environment for building connections and sharing knowledge. ## Traveling Companions and Networking I traveled to the event with my colleagues Vignesh, Yogeswar, and Kapil, and together, we delved into the heart of Sitecore’s latest innovations. Over the course of two days, we attended sessions that were immensely valuable for understanding Sitecore’s roadmaps and upcoming releases. ## Insights on AI in Sitecore Before attending the event, I had the impression that Sitecore might be lagging in the AI space. However, SUGCON India proved otherwise. It was clear that Sitecore is actively and intensively working on integrating AI into their platform. Aruna’s session offered profound insights into the evolution of AI and its impacts within Sitecore. Similarly, Rob’s presentation on using Retrieval Augmented Generation (RAG) with Sitecore Search to enhance GPT queries was eye-opening. He demonstrated how RAG can pull data from Sitecore Search and ground queries against Large Language Models (LLMs) like GPT-4, ensuring that the responses generated are contextually relevant and accurate. This technique provides greater control over the information returned to the end-user. ## Key Takeaways and Sessions Roger’s opening keynote was particularly inspiring, offering a glimpse into the future developments within Sitecore aimed at enhancing the platform and its community. Throughout the event, I attended multiple sessions that deepened my understanding of various Sitecore products and their capabilities. Ivan’s session on the XM Cloud repository and its APIs revealed a lot of behind-the-scenes details, shedding light on the complexities and innovations driving the platform. [Pieter’s session](https://www.youtube.com/watch?v=6DYVTHK0MOk&ref=gowthamaraja.com) on the second day was especially notable for its straightforward demonstration of integrating various Sitecore products, which provided practical and actionable insights in 30mins. ![ree](https://static.wixstatic.com/media/14fd51_7cec8bbe58404f6b862cc1f28e478e3e~mv2.jpeg/v1/fill/w_350,h_467,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_7cec8bbe58404f6b862cc1f28e478e3e~mv2.jpeg) ## Exploring Future Innovations Liz’s presentation was another highlight, offering a sneak peek into the ongoing developments at Sitecore aimed at improving user experience. Her focus on AI advancements, new SDKs for XM Cloud, and other innovations underscored the exciting future ahead for Sitecore. ![ree](https://static.wixstatic.com/media/14fd51_28cf1c574bee4418a04bd7e1dafdde21~mv2.jpeg/v1/fill/w_350,h_467,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_28cf1c574bee4418a04bd7e1dafdde21~mv2.jpeg) Andy and Liz shared their journey and experiences with XM Cloud development, providing valuable insights into the challenges and successes they’ve encountered. Their stories highlighted the collaborative spirit within the Sitecore community and the dedication to continuous improvement. ## A Grateful Reflection Overall, my experience at SUGCON India was immensely enriching. I am deeply grateful for the opportunity to attend, network with passionate and knowledgeable community members, and gain a deeper understanding of Sitecore’s evolving landscape. The event reinforced the importance of community and collaboration in driving innovation and knowledge-sharing within the Sitecore ecosystem. For those interested, I've attached a recording of Pieter’s insightful session, which is a must-watch for anyone keen on exploring the practical applications of Sitecore’s diverse product offerings. ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2025/11/WhatsApp-Image-2024-06-07-at-7.37.19-PM.jpeg) ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2025/11/WhatsApp-Image-2024-06-07-at-7.37.20-PM--1-.jpeg) ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2025/11/WhatsApp-Image-2024-06-07-at-7.37.23-PM.jpeg) ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2025/11/WhatsApp-Image-2024-06-07-at-8.47.49-PM--1-.jpeg) ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2025/11/WhatsApp-Image-2024-06-07-at-8.47.49-PM.jpeg) ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2025/11/WhatsApp-Image-2024-06-07-at-8.47.50-PM--1-.jpeg) ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2025/11/WhatsApp-Image-2024-06-07-at-8.47.50-PM.jpeg) ![](https://storage.ghost.io/c/01/c5/01c5f86b-1a7c-400e-8513-2371e48d18f0/content/images/2025/11/WhatsApp-Image-2024-06-07-at-8.47.51-PM.jpeg) ### Deploying Sitecore Custom Package in XM Cloud Using Item as Resources URL: https://www.gowthamaraja.com/deploying-sitecore-custom-package-in-xm-cloud-using-item-as-resource/ Last updated: 2025-11-17T07:22:44.000Z I worked on making a special module for Sitecore XM Cloud, combining items from both Core and Master, along with some DLLs and aspx files. While developing locally using XM Cloud with Docker, I created a custom container image for this module. I explained the process in one of [my articles](https://www.sitecoreknowledgebase.com/post/create-docker-images-sitecore-modules-guide?ref=gowthamaraja.com). However, I faced a challenge as the container image couldn't be used in the actual XM Cloud instance. Unlike our XP instance, you can't install the package using the Sitecore Installation Wizard. After some research, I discovered that I needed to reference the module assets in my solution and then deploy it to the XM Cloud instance. This worked well for DLLs and other supported files, but I encountered an issue with items in Core and Master. I initially serialized the items and added them to the deployment steps. However, during deployment, I encountered the following error. ``` Configured source item path /sitecore/templates/RWS Module did not exist in serialized items (27 subtrees) data store. An empty source indicates that you need to fill that source with data before attempting to push it into a destination. Usually that means you need to pull an initial data set from Sitecore to fill serialized files before being able to push serialized data into Sitecore. ``` ![serialization errir](https://static.wixstatic.com/media/14fd51_ac4d7ea313b1456f92541af4a4274966~mv2.jpg/v1/fill/w_740,h_325,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_ac4d7ea313b1456f92541af4a4274966~mv2.jpg) This error stated that this is expecting the items before it Push through SCS, but in my case it was the first time where items needs to be created. To resolve this issue I researched quite a bit and found out that in this scenerio we need to convert item as resource file and then use it on the XM Cloud. ## What is Item as Resources (IAR) Plugin? Items as Resources is a capability that extends the possible sources for Sitecore items. It lets you load a subset of items from precompiled resource items on disk and merges them into the user-visible content tree. Items are still loaded and presented in the content tree and work just like regular Sitecore items. When you make a change and save, it copies the entire item to the content database. This functionality supports and simplifies several scenarios: - Continuous integration and container-friendly deployment - Disk-only installation of modules with easy composition and support for uninstallation - Continuous integration scenarios for solution developers with blue-green deployment of code and definition items together - Version upgrades ## How does IAR Plugin works? The [Sitecore Items as Resources Plugin](https://doc.sitecore.com/xp/en/developers/103/developer-tools/items-as-resources-plugin.html?ref=gowthamaraja.com) includes an **itemres** command. This command creates an item package in a resource file with configurable options based on the settings from the **\*.module.json** which will be used for Sitecore Content Serialization by Sitecore CLI. To install the Items as Resources plugin, run the following code on your project folder `dotnet sitecore plugin add -n Sitecore.DevEx.Extensibility.ResourcePackage` To verify if the plugin has been installed, run the following command `dotnet sitecore plugin list` ![dotnet sitecore plugin list](https://static.wixstatic.com/media/14fd51_0ac927df67f948619ebf6b5d9270484b~mv2.png/v1/fill/w_584,h_148,al_c,q_85,enc_avif,quality_auto/14fd51_0ac927df67f948619ebf6b5d9270484b~mv2.png) To produce the IAR file, execute the following command. Ensure that your items are listed in the **\*.module.json** file, as these items will be converted into IAR format, resulting in .dat files. `dotnet sitecore itemres create -o itemres/rws` The command mentioned above will transform the items specified in **\*.module.json** and save the resulting .dat file in the "itemres" folder, created at the project file's root. If the items are in the master database, the .dat file will be named items.master.module.dat. The same naming convention applies to items in the Core and Master categories. ![itemres command](https://static.wixstatic.com/media/14fd51_e5c40d18909141da84ee675e681d42e0~mv2.png/v1/fill/w_740,h_417,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_e5c40d18909141da84ee675e681d42e0~mv2.png) If the .dat file has already been generated, you can update it by including the **\--overwrite** parameter in the command mentioned earlier. To explore additional parameters for the itemres command, please refer the [official documentation](https://doc.sitecore.com/xp/en/developers/103/developer-tools/the-cli-itemres-command.html?ref=gowthamaraja.com#the-create-subcommand). To know more about the Sitecore Content Serialization please refer following sites - [https://doc.sitecore.com/xp/en/developers/103/developer-tools/sitecore-content-serialization.html](https://doc.sitecore.com/xp/en/developers/103/developer-tools/sitecore-content-serialization.html?ref=gowthamaraja.com) - [https://konabos.com/blog/setting-up-sitecore-serialization-using-sitecore-cli](https://konabos.com/blog/setting-up-sitecore-serialization-using-sitecore-cli?ref=gowthamaraja.com) ## How to convert the Item as Resources file to actual Sitecore Item in XM Cloud? After converting the items into a .dat file, the next step is to transform the .dat file back into the actual items. To accomplish this, copy the .dat file to the specified location within the Platform project or website project. - **items.master.module.dat** \- App\_Data/items/master - **items.core.module.dat** \- App\_Data/items/core - **items.web.module.dat** \- App\_Data/items/web ![items_dat](https://static.wixstatic.com/media/14fd51_8f2a6196f91d440eb93d714db1eabd71~mv2.png/v1/fill/w_350,h_192,al_c,lg_1,q_85,enc_avif,quality_auto/14fd51_8f2a6196f91d440eb93d714db1eabd71~mv2.png) Once you've finished the aforementioned steps, initiate a new deployment to your XM Cloud instance. This process will seamlessly transition the items from the .dat file to items in Sitecore. Any modifications made to these items will be automatically saved on the item itself. Happy Sitecoreing!! ## References: - [https://doc.sitecore.com/xp/en/developers/103/developer-tools/items-as-resources-plugin.html](https://doc.sitecore.com/xp/en/developers/103/developer-tools/items-as-resources-plugin.html?ref=gowthamaraja.com) - [https://doc.sitecore.com/xp/en/developers/103/developer-tools/the-cli-itemres-command.html](https://doc.sitecore.com/xp/en/developers/103/developer-tools/the-cli-itemres-command.html?ref=gowthamaraja.com) - [https://konabos.com/blog/generating-your-own-custom-iar-files-of-your-sitecore-items](https://konabos.com/blog/generating-your-own-custom-iar-files-of-your-sitecore-items?ref=gowthamaraja.com) - [https://pushpaganan.home.blog/2023/02/18/sitecore-item-as-a-resource-deep-dive-1-iaar-plugin/](https://pushpaganan.home.blog/2023/02/18/sitecore-item-as-a-resource-deep-dive-1-iaar-plugin/?ref=gowthamaraja.com) - [https://www.sitecorespark.com/blog/2022/10/how-do-sitecore-modules-work-with-sitecore-xm-cloud-](https://www.sitecorespark.com/blog/2022/10/how-do-sitecore-modules-work-with-sitecore-xm-cloud-?ref=gowthamaraja.com) ### level=warning network was found but has incorrect label com.docker.compose.network set to "" URL: https://www.gowthamaraja.com/fix-sitecore-docker-installation-errors/ Last updated: 2025-11-17T07:18:40.000Z I ran into an error while trying to install a Sitecore Docker instance using the Sitecore Getting Started Template and if the error is related to "network nat is ambiguous". This happened recently. ``` level=warning msg="a network with name tac_default exists but was not created by compose.\nSet `external: true` to use an existing network" network tac_default was found but has incorrect label com.docker.compose.network set to ""d ``` ![No connection could be made because the target machine actively refused it](https://static.wixstatic.com/media/14fd51_cd5540b149b74dcea2b2c112ca8f9326~mv2.jpg/v1/fill/w_740,h_434,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_cd5540b149b74dcea2b2c112ca8f9326~mv2.jpg) No connection could be made because the target machine actively refused it I couldn't find a straightforward answer online to fix the problem, so I decided to investigate it myself. You might run into a similar issue when you use the up.ps1 script to start a container, and then you get an error when you try to use "*docker compose down*" followed by "*docker compose up*." This problem probably happens because the network interface created by up.ps1 isn't working correctly when you run "docker compose up." To solve this issue, do the following: 1. Type "*docker network ls*" to see all the networks available. 2. Enter "*docker network prune*" to remove all the networks. Note: This command deletes any unused networks on your system. 3. If you need to remove a specific network, use "*docker network rm *" followed by the network Id to remove the problematic one. 4. Once the network cleanup is done, use "*docker compose up -d*" to start the containers. After following these steps, the problem should be fixed, and "docker compose up" should work without any issues. ## Reference 1. [https://docs.docker.com/engine/reference/commandline/network\_prune/](https://docs.docker.com/engine/reference/commandline/network%5Fprune/?ref=gowthamaraja.com) 2. [https://docs.docker.com/engine/reference/commandline/network\_ls/](https://docs.docker.com/engine/reference/commandline/network%5Fls/?ref=gowthamaraja.com) 3. [https://sitecore.stackexchange.com/a/35447/976](https://sitecore.stackexchange.com/a/35447/976?ref=gowthamaraja.com) ### Troubleshooting Sitecore Build Error: Resolving NuGet.Protocol Issue for Myget Migration URL: https://www.gowthamaraja.com/troubleshooting-sitecore-build-error-resolving-nuget-protocol-issue-for-myget-migration/ Last updated: 2025-11-17T07:09:41.000Z As a Sitecore developer, encountering build errors can be quite frustrating. One common issue you might come across is the dreaded. > NuGet.Protocol.Core.Types.FatalProtocolException: Unable to load the service index for source https://sitecore.myget.org/F/sc-packages/api/v3/index.json. Don't worry, though - you're not alone in facing this problem. Sitecore relies on Myget as its primary public package source, which has been widely adopted by the Sitecore community. However, an unfortunate incident occurred when Myget experienced a prolonged outage, causing confusion and discussions within the community. Fortunately, there's a silver lining! Sitecore already had plans in place to switch to Nuget as the new package feed by [30th November 2023](https://support.sitecore.com/kb?id=kb%5Farticle%5Fview&sysparm%5Farticle=KB1002999&ref=gowthamaraja.com), offering a more stable alternative. When I personally encountered this error while working with my docker images, I decided to seek help from the community. Multiple discussions later, it became clear that a common recommendation was to update the Myget URL to the Nuget URL. The challenge for me was figuring out which URLs needed updating, as it wasn't immediately apparent. To assist fellow developers facing the same issue, I'm sharing my experience and providing a step-by-step guide on how to make the necessary updates. [Rob Earlam](https://www.linkedin.com/in/rob-earlam/?ref=gowthamaraja.com) published a detailed article on how to update it to new feed. I'm attaching the article in reference section. In my case, updating the Sitecore key in the nuget.config file with the URL of the new Nuget source effectively and removing PowerShell Modules, removing PowerShell Repository resolved the error. You can obtain all the packages with the below configuration. Earlier it used to be different endpoints were used to obtain the packages specific to Identity, Commerce, XP and XM. Now with the migration you can use the single endpoints to obtain all packages. To remove PowerShell Repository run the below command in your Windows PowerShell ``` Unregister-PSRepository -Name SitecoreGallery ``` To remove PowerShell Modules run the below command in your Windows PowerShell ``` Uninstall-Module -Name SitecoreDockerTools -AllVersions ``` Open the init.ps1 and update the feed URL from [https://sitecore.myget.org/F/sc-powershell/api/v2](https://sitecore.myget.org/F/sc-powershell/api/v2?ref=gowthamaraja.com) to [https://nuget.sitecore.com/resources/v2/](https://nuget.sitecore.com/resources/v2/?ref=gowthamaraja.com) Update the nuget.config with below key. ``` ``` With the below URL you can search all of the packages for new feed. [https://cloudsmith.io/\~sitecore/repos/resources/packages/](https://cloudsmith.io/~sitecore/repos/resources/packages/?ref=gowthamaraja.com) Remember, you're not the only one dealing with this situation, and the Sitecore community is here to support you. So, if you've encountered the NuGet.Protocol error, don't panic - there are solutions available. Note: Currently, the URL lacks the packages for Sitecore Experience Commerce, Sitecore Content Hub, Sitecore PowerShell, and Sitecore Installation Framework. The Sitecore team is actively working to rectify this situation. If you encounter any critical blockers in your project that require immediate attention, please don't hesitate to contact the [Sitecore Support team](https://support.sitecore.com/csm?ref=gowthamaraja.com). ## Reference: - [Migrating the XM Cloud Introduction Repo to a new Nuget feed. - Rob Earlam](https://robearlam.com/blog/migrating-the-xm-cloud-introduction-repo-to-a-new-nuget-feed?ref=gowthamaraja.com) ### No connection could be made because the target machine actively refused it. - Sitecore Docker URL: https://www.gowthamaraja.com/connection-refused-error/ Last updated: 2025-11-17T07:00:54.000Z While attempting to install the Sitecore Docker Containers template for Next.js, I encountered the following error. Despite having installed all the necessary prerequisites for Sitecore Docker, the error persisted. Unfortunately, my internet search for a direct solution based on the error yielded no results. Consequently, I decided to address this issue by writing an article about it. ## Error: ``` Invoke-RestMethod: D:\Playground\MyProject\up.ps1:49 Line | 49 | … $status = Invoke-RestMethod "http://localhost:8079/api/http/routers … | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | No connection could be made because the target machine actively refused it. ``` ## Solution The error originates from the fact that the Getting Started template includes docker compose V1\. To address this, we must upgrade it to V2\. Please follow the instructions below for migrating to V2. - Make sure that the "Use Docker Compose V2" option is selected in your Docker Desktop settings. You can enable this option by navigating to Docker Desktop Settings -> General -> Use Docker Compose V2 -> Apply & restart. ![use-docker-compose-v2](https://static.wixstatic.com/media/14fd51_f5b2d51876924b39821469eb2b8a74ba~mv2.jpg/v1/fill/w_740,h_401,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_f5b2d51876924b39821469eb2b8a74ba~mv2.jpg) - Open the up.ps1 file and locate the "docker-compose" text. Replace it with "docker compose" and then save the changes to the file. - Open the docker-compose.override.yml file replace the scale:0 with ``` deploy: replicas: 0 ``` - Within the same file, locate the provided command and replace it with the specified alternative command. ``` entrypoint: powershell.exe -Command "& C:\tools\entrypoints\iis\Development.ps1" ``` ``` entrypoint: powershell.exe -Command "& C:\\tools\\entrypoints\\iis\\Development.ps1" ``` Now execute the .\\up.ps1 script, and this time, you will no longer encounter the error. Enjoy your seamless Sitecore experience! ## References - [Migrating Docker Compose from V1 to V2 Code Details / Blogs / Perficient](https://blogs.perficient.com/2023/07/03/migrating-docker-compose-from-v1-to-v2-code-details/?ref=gowthamaraja.com) - [Docker-Compose v1 End of Life in June 2023\. Welcome Docker Compose v2! Upgrade Instructions / Blogs / Perficient](https://blogs.perficient.com/2023/06/05/upgrade-instructions-to-docker-compose-v1-to-v2/?ref=gowthamaraja.com) ### Converting Sitecore MVC to Jamstack: A Comprehensive Guide URL: https://www.gowthamaraja.com/converting-sitecore-mvc-to-jamstack-a-comprehensive-guide/ Last updated: 2025-11-17T07:15:30.000Z When I first embarked on my journey with Headless technology, I wondered if it was feasible to transition an existing Sitecore MVC site to a more modern Headless solution, or if it was necessary to start development from scratch. This article will provide a step-by-step guide on how to convert an existing Sitecore MVC application to the Jamstack architecture. It's crucial to modernize our traditional Sitecore applications to leverage the capabilities of modern technology stacks such as Headless, SSG, ISR, multi-channel, and others. ## Architecture overview > Jamstack architecture for existing Sitecore MVC sites is possible because of the ability of the Sitecore Layout Service to render MVC components to HTML, and include them in its output. The following diagram represents the publishing and rendering process for Sitecore MVC components when using Experience Edge and Next.js. ![Diagram illustrating the publishing and rendering process in static HTML generation of MVC applications](https://static.wixstatic.com/media/14fd51_3eaa37ddc2ca41c2adf13ee27df3b11b~mv2.png/v1/fill/w_740,h_254,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_3eaa37ddc2ca41c2adf13ee27df3b11b~mv2.png) The publishing and rendering process consists of the following steps: 1. The Layout Service outputs MVC components as HTML, embedded in its usual service output. 2. The Layout Service output is published to Experience Edge with each page/route, allowing it to be queried by Sitecore headless SDKs such as Next.js. 3. The Next.js application queries the Layout Service output for the route and passes it into one or more Placeholder components. 4. Based on the lack of a componentName property in the layout data, the Placeholder component in the Sitecore Next.js SDK renders the Sitecore component directly as HTML into the pre-rendered document. ## Prerequisites - Sitecore version 10.2+ – An upgrade of your MVC application would be needed. - Sitecore Headless Services module version 19+. - You must install the JSS CLI version 19+. ## Migrating from 10.1 to 10.2 You can access the comprehensive solution containing all the changes by following the link provided. To set it up on your local system immediately, please refer to the instructions in the readme file. I am currently utilizing the "Basic Company - Unicorn" website from the Sitecore Helix examples with Docker for demonstration purposes. The repository link for the Basic Company site that I am using can be found [here](https://github.com/Sitecore/Helix.Examples/tree/master/examples/helix-basic-unicorn?ref=gowthamaraja.com). As stated earlier, in order to carry out the migration, it is necessary to have Sitecore version 10.2 or higher. The repository currently has version 10.1, but with some configuration changes, I will upgrade it to 10.2\. The corresponding changes can be found [here](https://github.com/GowthamEswaramoorthy/mvc-to-headless/tree/develop/10.2-upgrade?ref=gowthamaraja.com). To initialize the docker container and start the image, please clone the repository and run the following command: ``` .\init.ps1 -LicenseXmlPath C:\License\license.xml -SitecoreAdminPassword b docker compose up -d ``` ## Adapting MVC components to be compatible with JSS Up to this point, we have accomplished the migration of Sitecore 10.2, integrated Rendering Host and Next JS. Our next step is to adjust our MVC components to work seamlessly with JSS. However, before we proceed with modifying the components themselves, we must first make some modifications at the template level to enable the components to serve data in JSON format. > The services used by JSS, such as the Layout Service, GraphQL, Tracking Service, and Dictionary Service, utilize the API Key mechanism provided by Sitecore Services Client (SSC). You must create an API Key and note its Item ID for using it when connecting JSS To generate an API key 1. Open your Sitecore Content Editor in the Master database. 2. Navigate to /sitecore/system/Settings/Services/API Keys. 3. Click on "API Key" to create a new API key. 4. Assign the name of your Next JS application to the API key. In this case, we have named our app "basic-company," so we will use the same name for the API key. 5. After creating the API key item, update the "CROS Origins" and "Allowed Controllers" values to "\*". Please note that we are using a wildcard only for demo purposes, and it is not recommended for scaled instances. For further details, please refer to [Sitecore's official website](https://doc.sitecore.com/xp/en/developers/hd/211/sitecore-headless-development/create-a-sitecore-api-key.html?ref=gowthamaraja.com). ![Screenshot showing how to enable editing and static generation support for the JSS app by inheriting from the JavaScript Services/App template in Sitecore](https://static.wixstatic.com/media/14fd51_c0e11a70cb774746ac18f85caa1efe05~mv2.png/v1/fill/w_740,h_423,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_c0e11a70cb774746ac18f85caa1efe05~mv2.png) In order to enable editing and static generation support for the JSS app, the site root must inherit from the */sitecore/templates/Foundation/JavaScript Services/App* template. ![Screenshot depicting how to enable editing support by using or inheriting the JavaScript Services/JSS Layout template in Sitecore for your page layouts](https://static.wixstatic.com/media/14fd51_882ede2f934c480fb7cce94e760b2e60~mv2.png/v1/fill/w_740,h_407,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_882ede2f934c480fb7cce94e760b2e60~mv2.png) To enable editing support, make sure that the layouts for your pages use or inherit the */sitecore/templates/Foundation/JavaScript Services/JSS Layout* template. ![Screenshot illustrating how to configure root placeholders for a selected layout in the Sitecore content tree by navigating to the 'Layout Service Placeholders' field](https://static.wixstatic.com/media/14fd51_b68cf4fb07ab4197bdce7c075e828456~mv2.png/v1/fill/w_740,h_440,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_b68cf4fb07ab4197bdce7c075e828456~mv2.png) To configure the root placeholders for your selected layout in the content tree, navigate to */sitecore/layout/Layouts/Project/BasicCompany/Default* and add every root placeholder to the "Layout Service Placeholders" field. If a Placeholder Settings item does not exist, create one. ![Screenshot demonstrating layout inheritance in Sitecore, preparing for the validation of Layout Service response](https://static.wixstatic.com/media/14fd51_1e6c0f6f4ccc4358bc294995e1a0244b~mv2.png/v1/fill/w_740,h_392,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_1e6c0f6f4ccc4358bc294995e1a0244b~mv2.png) ## Validating Layout Service response We have now completed 90% of the work, and before we proceed to the next steps, we can check the Layout Service. To access the Layout Service, use the URL provided below and replace the sc\_apikey with your own. However, make sure to publish your site beforehand, or else you will not receive a response from the Layout Service. ``` https://cm.basic-company-unicorn.localhost/sitecore/api/layout/render?item={97479C6B-BB30-4A15-AFD1-2C89F207E9D6}&sc_apikey={6E80F612-7793-48AE-B286-4EE2B6AFAE3E} ``` If everything is fine you'll get the response as below ``` {"sitecore":{"context":{"pageEditing":false,"site":{"name":null},"pageState":"normal","language":"en","itemPath":"/Basic-Company/Home"},"route":{"name":"Home","displayName":"Home","fields":{"Navigation Title":{"value":"Home"},"Footer Copyright":{"value":"Copyright"},"Header Logo":{"value":{"src":"https,http,http://www.basic-company-unicorn.localhost/-/media/Basic-Company/helix-logo.png?h=44&iar=0&w=139&hash=098C1B36D12B08BF1A9ED55C0B91073A","alt":"Sitecore Helix","width":"139","height":"44"}}},"databaseName":"web","deviceId":"fe5d7fdf-89c0-4d99-9aa3-b5fbd009c9f3","itemId":"97479c6b-bb30-4a15-afd1-2c89f207e9d6","itemLanguage":"en","itemVersion":1,"layoutId":"4ed48317-062f-4465-b9af-1e636841525b","templateId":"63cd29ba-0e08-44d5-ab10-e05298a9818d","templateName":"Home Page","placeholders":{"Header":[{"uid":"7d4f689f-208c-4ea3-88ba-0bc6e615771e","componentName":"Header","dataSource":""}],"main":[{"uid":"bb562955-2cf5-4a57-b6c7-ddf2278ec0e0","componentName":"Hero Banner","dataSource":"{9C581356-66D4-4993-BB25-757B710A06E8}","fields":{"Title":{"value":"Basic Company"},"Image":{"value":{"src":"https,http,http://www.basic-company-unicorn.localhost/-/media/Basic-Company/hero-home.jpg?h=510&iar=0&w=1920&hash=CBD65D270D2DC471EAADE5C57332C88C","alt":"Basic Company","width":"1920","height":"510"}},"Subtitle":{"value":"Lorem Ipsum Dolor Sit Amet"}}},{"uid":"e10e7525-8542-41bc-939e-3082925b9c52","componentName":"Promo Container","dataSource":""},{"uid":"d65c5c87-61b0-4e2d-9842-6d6b1faed3cf","componentName":"Section Header","dataSource":"{086CBC66-2B60-4711-BEE5-14C11181FB27}","fields":{"Text":{"value":"Section Header"}}},{"uid":"0b6b5e57-eb1c-42a6-86f3-da06dfd1f319","componentName":"Promo Container","dataSource":""}],"Footer":[{"uid":"66b647e6-3d33-45ef-af06-ebb2175bc56b","componentName":"Footer","dataSource":""}]}}}} ``` As we examine the response, we can observe that the placeholders we included earlier (main, header, and footer) are present. ## Modify the Sitecore Layout Service settings to generate HTML for MVC renderings. Now, let's proceed with the configuration of the "Hero Banner" component to display HTML instead of JSON.HTML for MVC renderings. Go to the path */sitecore/layout/Renderings/Feature/BasicContent/Hero Banner* and activate the "Render as HTML" option. This will allow the MVC rendering to present the information in HTML format rather than JSON. ![render-as-html](https://static.wixstatic.com/media/14fd51_27a3356374514886b1ac1c94127f961a~mv2.png/v1/fill/w_740,h_522,al_c,q_90,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_27a3356374514886b1ac1c94127f961a~mv2.png) After publishing the item, go to the Layout Service endpoint URL to view the updates. The HTML content for the Hero Banner will be included in the response. By doing this, we have successfully made the necessary changes to the Sitecore Layout Service settings to produce HTML for MVC renderings. ``` {"sitecore":{"context":{"pageEditing":false,"site":{"name":null},"pageState":"normal","language":"en","itemPath":"/Basic-Company/Home"},"route":{"name":"Home","displayName":"Home","fields":{"Navigation Title":{"value":"Home"},"Footer Copyright":{"value":"Copyright"},"Header Logo":{"value":{"src":"https,http,http://www.basic-company-unicorn.localhost/-/media/Basic-Company/helix-logo.png?h=44&iar=0&w=139&hash=098C1B36D12B08BF1A9ED55C0B91073A","alt":"Sitecore Helix","width":"139","height":"44"}}},"databaseName":"web","deviceId":"fe5d7fdf-89c0-4d99-9aa3-b5fbd009c9f3","itemId":"97479c6b-bb30-4a15-afd1-2c89f207e9d6","itemLanguage":"en","itemVersion":1,"layoutId":"4ed48317-062f-4465-b9af-1e636841525b","templateId":"63cd29ba-0e08-44d5-ab10-e05298a9818d","templateName":"Home Page","placeholders":{"Header":[{"uid":"7d4f689f-208c-4ea3-88ba-0bc6e615771e","componentName":"Header","dataSource":""}],"main":[{"name":"section","type":"text/sitecore","contents":"\r\n
\r\n
\r\n

\r\n Basic Company\r\n

\r\n

\r\n Lorem Ipsum Dolor Sit Amet\r\n

\r\n
\r\n
\r\n","attributes":{"class":"hero is-medium is-black","style":"background-image: url(/-/media/Basic-Company/hero-home.jpg)"},"cacheable":true,"immutable":true},{"uid":"e10e7525-8542-41bc-939e-3082925b9c52","componentName":"Promo Container","dataSource":""},{"uid":"d65c5c87-61b0-4e2d-9842-6d6b1faed3cf","componentName":"Section Header","dataSource":"{086CBC66-2B60-4711-BEE5-14C11181FB27}","fields":{"Text":{"value":"Section Header"}}},{"uid":"0b6b5e57-eb1c-42a6-86f3-da06dfd1f319","componentName":"Promo Container","dataSource":""}],"Footer":[{"uid":"66b647e6-3d33-45ef-af06-ebb2175bc56b","componentName":"Footer","dataSource":""}]}}}} ``` You can find the changes up to this point [here](https://github.com/GowthamEswaramoorthy/mvc-to-headless/tree/develop/mvc-components-to-jss-compatible?ref=gowthamaraja.com). ## Adding Rendering Host Once the site is up and running, it confirms that the migration from Sitecore 10.1 to 10.2 was successful and along with that we have enabled the Layout service. The next step is to add the Rendering Host, which we will use to establish communication between our Next.js front-end and Layout Service. In order to accomplish it, certain modifications must be made to the files listed below. - docker-compose.override.yml - .env - init.ps1 - docker/build/cd/Dockerfile - docker/build/cm/Dockerfile - docker/build/mssql-init/Dockerfile - docker/build/nodejs/Dockerfile - docker/build/rendering/Dockerfile The specifics of the alterations made to the previously mentioned files can be found in this [PR](https://github.com/GowthamEswaramoorthy/mvc-to-headless/pull/1?ref=gowthamaraja.com). Execute the following PowerShell command in Sitecore to set all MVC renderings to have the "Render as HTML" option checked. ``` Get-ChildItem "/sitecore/layout/Renderings" -Recurse | Where-Object { $_.TemplateName -eq "View rendering" -or $_.TemplateName -eq "Controller rendering" } | ForEach-Object { $val = $_.Fields["Render as HTML"].Value if ($val -eq "1") { return } Write-Host "Setting '$($_.Name)'" $_.Editing.BeginEdit() $_.Fields["Render as HTML"].Value = 1 $_.Editing.EndEdit() } ``` Once the modifications have been made, it is now time to install Next.js for our Basic Company Project. - Open PowerShell in admin mode and execute the following command to navigate to the specified folder. In this example, I have cloned the repository on my D drive. ``` cd D:\mvc-to-headless\src\Project\BasicCompany ``` - Run the below command to initiate the Next JS installation ``` npx create-sitecore-jss@ver20 nextjs ``` - During the process, you will be presented with multiple options. Please select the options that I have chosen: ![next-js-instillation](https://static.wixstatic.com/media/14fd51_060f6ed2a6a44427a2200e1f3f876aa5~mv2.jpg/v1/fill/w_740,h_192,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_060f6ed2a6a44427a2200e1f3f876aa5~mv2.jpg) - I selected "nextjs-sxa" for the final option, which was to include any add-ons. - Upon successful completion of the installation, you will receive a message indicating that it was successful. ![next-js-instillation-completion](https://static.wixstatic.com/media/14fd51_841ea4fddf7e49c1a5655b000d02918f~mv2.jpg/v1/fill/w_350,h_463,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_841ea4fddf7e49c1a5655b000d02918f~mv2.jpg) We have developed the JSS application. To link it with our Sitecore instance, we need to configure it. Execute the subsequent CLI command to proceed: ``` cd basic-company jss setup ``` You will encounter the following questions, and you may either enter values identical to mine or customize them to suit your requirements. 1. Is your Sitecore instance on this machine or accessible via network share? \[y/n\]: **y** 2. Path to the Sitecore folder (e.g. c:\\inetpub\\wwwroot\\my.siteco.re): **..\\..\\..\\..\\docker\\deploy\\website** 3. Sitecore hostname (e.g. http://myapp.local.siteco.re; see /sitecore/config; ensure added to hosts): **https://www.basic-company-unicorn.localhost** 4. Sitecore import service URL \[https://www.basic-company-unicorn.localhost/sitecore/api/jss/import\]: 5. Sitecore API Key (ID of API key item): **{EE2E30DB-2744-4DE4-9928-E334F89886BA}** 6. Please enter your deployment secret (32+ random chars; or press enter to generate one): **joxh265cwali5j2qunjrgeorozv8948s66spmgck0d** Note: - To use the default values for options 4 , press "Enter". - For the option 6 use the JSS\_BasicCompany\_DEPLOYMENT\_SECRET from .env file - For option 2, if you cloned your repo on a drive other than D, adjust the drive value accordingly. - I used the path of the D drive since that's where I cloned my repository. Please go to the following directory: \\src\\Project\\BasicCompany\\basic-company\\sitecore\\config\\basic-company.config and modify the root path for your JSS site. Also, make sure to change the database from "master" to "web". ``` ``` The configuration is now set for deployment (please ensure that the files created under src\\Project\\BasicCompany\\basic-company\\sitecore\\config\\basic-company.config are correct). To proceed, run the following command in the CLI. Remember to switch the database to web from master before executing the script. ``` jss deploy config ``` ## Get the Next.js application ready to display our content. After successfully deploying the configuration, we must modify the Layout.tsx file to include our newly added placeholders (header, main, footer). ![layout.tsx](https://static.wixstatic.com/media/14fd51_41ec142976bd444f9b72954cbd85c605~mv2.jpg/v1/fill/w_740,h_405,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_41ec142976bd444f9b72954cbd85c605~mv2.jpg) Duplicate the "basic-company.css" file from the website directory to the "src/assets" directory, and then modify the \_app.tsx file with the following changes: ![_app.tsx](https://static.wixstatic.com/media/14fd51_5014d1c4f03649059a86c45634805be2~mv2.jpg/v1/fill/w_740,h_463,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_5014d1c4f03649059a86c45634805be2~mv2.jpg) Execute the command below to initiate our JSS application and link it to our Sitecore application for operation. ``` jss start:connected ``` By visiting [http://localhost:3000](http://localhost:3000/?ref=gowthamaraja.com) , you will be able to observe the Basic Company MVC website rendered as a JSS App, which is all set to be deployed and generated statically. ![localhost_3000](https://static.wixstatic.com/media/14fd51_6cb5e894ef904ebfa7b26e96a05d02fd~mv2.jpg/v1/fill/w_740,h_394,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_6cb5e894ef904ebfa7b26e96a05d02fd~mv2.jpg) However, let's take a step forward and begin converting one of the components to React. I consider this method to be an incremental way to start the migration process to JSS (React). ## Start converting components from MVC (C#/Razor) to Next.js (JavaScript/React) incrementally To proceed, we will duplicate the "Hero Banner" rendering in Sitecore, modify its template to transform it into a "*/sitecore/templates/Foundation/JavaScript Services/Json Rendering*", and rename it to "HeroBanner" so that it follows the naming conventions of React. Additionally, the "Render as HTML" checkbox must be unchecked, and the "component name" field should be set to "HeroBanner". Finally, we need to insert this new component next to the MVC version on the Homepage. ![HeroBanner](https://static.wixstatic.com/media/14fd51_d7b5b8ea4eb24eafafa0c10036ede605~mv2.jpg/v1/fill/w_740,h_397,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_d7b5b8ea4eb24eafafa0c10036ede605~mv2.jpg) After publishing the rendering, review the Layout Service response once again. You should be able to see both versions of the component - the one in HTML and the one in JSON. If we refresh our JSS App(http://localhost:3000) now, we will notice that the component has been added, but it still requires a React implementation. ![localhost3000_HeroBanner](https://static.wixstatic.com/media/14fd51_96f5a0d284234e8ba8269dae96ed7e31~mv2.jpg/v1/fill/w_740,h_393,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_96f5a0d284234e8ba8269dae96ed7e31~mv2.jpg) To generate the React implementation of the component we created, execute the following command in the terminal from the JSS App root: ``` jss scaffold BasicContent/HeroBanner ``` ![HeroBanner_Scaffold](https://static.wixstatic.com/media/14fd51_455ffac20a2342d8bbd65bec4cb3d621~mv2.jpg/v1/fill/w_719,h_443,al_c,q_80,enc_avif,quality_auto/14fd51_455ffac20a2342d8bbd65bec4cb3d621~mv2.jpg) Now open the *BasicContent/HeroBanner.tsx* and replace with the below content and you can see the JSS Component on the JSS App. ``` import { Text, Field, ImageField } from '@sitecore-jss/sitecore-jss-nextjs'; export type HeroBannerProps = { fields: { Title: Field; Subtitle: Field; Image: ImageField; }; }; const HeroBanner = ({ fields }: HeroBannerProps): JSX.Element => { const bannerStyle = { backgroundImage: `url(${fields.Image?.value?.src})`, }; return (
); }; export default HeroBanner; ``` ![added_component_jss_app](https://static.wixstatic.com/media/14fd51_f8d84620a0674510b1e19efd146317b0~mv2.jpg/v1/fill/w_740,h_394,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_f8d84620a0674510b1e19efd146317b0~mv2.jpg) Both the MVC and React components are now residing on the same site. I have retained both of them to make it more visually apparent, but it is recommended to replace only the MVC rendering when migrating. By modifying the docker-compose.override.yml and Dockerfile for Rendering, we can integrate our JSS application to run in our Docker environment. I hope you found this useful. You can access the complete solution here - it is a Sitecore Helix Examples fork with added headless services, Sitecore 10.2 upgrade, a NextJS rendering host, and application. ### How to Create a Docker Asset Image for Your Sitecore Module: A Detailed Tutorial URL: https://www.gowthamaraja.com/create-docker-images-sitecore-modules-guide/ Last updated: 2025-11-17T06:50:08.000Z Embarking on a journey with Docker and Sitecore can be an exciting venture, especially given the fascinating complexity and efficiency of Docker images. If you're intrigued by questions such as 'How are Docker images constructed?' or 'How can I integrate custom or hotfix packages into Sitecore?', then you're in the right place. This guide will help you leverage the power of Docker's containerization capabilities, focusing on creating a customized Docker image for your Sitecore module. ## Understanding the Docker and Sitecore Environment Contrary to the process on a traditional on-premises Sitecore setup, installing packages in a Sitecore Docker environment requires a unique approach. The key distinction stems from the inherent design of Docker itself. Docker images are crafted to be unchangeable, and instances are created with disposability in mind. ## The Challenge with Docker Packages Installation Sitecore has put stringent restrictions on runtime application access. For instance, the 'bin' folder (and potentially other folders) has been designated as read-only for the runtime user. This fundamental characteristic of Docker containers within Sitecore underscores the importance of adopting a tailored approach for package installation. ## The Solution: Creating a Customized Image for Your Package Wondering how to install packages for Docker or Kubernetes? The simple answer is to create a customized image for your package. In this blog, we will learn how to do it. I'll be using one of my custom packages for containerizing it. ## Prerequisites for Containerizing Your Module Before you begin containerizing your module, it is essential to ensure that your local machine is prepared with the following prerequisites. - Running instance of Sitecore 10.3 using Docker: Download the repository from Sitecore's official GitHub "[Custom Images](https://github.com/Sitecore/docker-examples/tree/develop/custom-images?ref=gowthamaraja.com)" template to set up a working instance of Sitecore 10.3 using Docker. - Other [prerequisites for running Sitecore using Docker](https://doc.sitecore.com/xp/en/developers/103/developer-tools/set-up-the-environment.html?ref=gowthamaraja.com) on your local machine - Sitecore custom package: Prepare a Sitecore custom package that will be used for containerizing your module. - Sitecore Azure Toolkit: Install the Sitecore Azure Toolkit, which is used for converting items to the dacpac format. Follow the official documentation for the [Getting started with the Sitecore Azure Toolkit](https://doc.sitecore.com/xp/en/developers/sat/28/sitecore-azure-toolkit/getting-started-with-the-sitecore-azure-toolkit.html?ref=gowthamaraja.com#prerequisites%5Fbody) to complete the installation. - Azure account: For uploading the container image to Azure Container Registry ## Install Sitecore Azure Toolkit (SAT) for Package Conversion To use the Sitecore Azure Toolkit, you need to install specific prerequisites, which can be found in [Sitecore's Official Documentation](https://doc.sitecore.com/xp/en/developers/sat/28/sitecore-azure-toolkit/getting-started-with-the-sitecore-azure-toolkit.html?ref=gowthamaraja.com#prerequisites%5Fbody). Once you have successfully installed the prerequisites, you can then proceed with the following steps on converting Sitecore packages to image. ## Converting Sitecore Package to scwdp file using SAT Once you have finished installing the SAT prerequisites, you are ready to proceed with generating the scwdp package using the Sitecore package. To create the scwdp package using the Sitecore Azure Toolkit, follow these steps: - Download the Sitecore Azure Toolkit from [Sitecore's Download page](https://dev.sitecore.net/Downloads/Sitecore%5FAzure%5FToolkit.aspx?ref=gowthamaraja.com). - Extract the files in your desired drive. For example, extract the files to D:\\connector. - Copy the Sitecore Package you want to convert into the container. Ensure that the package contains the necessary config file, DLLs, JS, styles, and Sitecore items from both the Core and Master databases. - Open PowerShell as an administrator and navigate to the D:\\connector directory using the following command: \`cd D:\\connector\`. - Import the Package Converter and convert the Sitecore package to the scwdp package by running the following commands: ``` Import-Module .\tools\Sitecore.Cloud.Cmdlets.psm1 Import-Module .\tools\Sitecore.Cloud.Cmdlets.dll ConvertTo-SCModuleWebDeployPackage -Path "D:\connector\{Name-of-your-sitecore-package}.zip" -Destination "D:\connector" ``` Replace \`{Name-of-your-sitecore-package}\` with the actual name of your Sitecore package. - The above command will create the scwdp file in zip format in the D:\\connector directory. Note: If you encounter the exception "[ConvertTo-SCModuleWebDeployPackage: The type initializer for 'DotNet.Basics.IO.SystemIoPath' threw an exception](https://sitecore.stackexchange.com/questions/34985/convertto-scmodulewebdeploypackage-the-type-initializer-for-dotnet-basics-io-s?ref=gowthamaraja.com)" when running the ConvertTo-SCModuleWebDeployPackage command, you can resolve it by using Windows PowerShell version 5.1 instead of version 7. ## Converting SCWDP Files into a Docker Container Image To convert the scwdp file into a container image, follow the steps below: - Followed [Sitecore's official Image Structure](https://doc.sitecore.com/xp/en/developers/103/developer-tools/add-sitecore-modules.html?ref=gowthamaraja.com#image-structure) recommendation and created folder structure accordingly. - Create a new folder at C:\\Connector. - Folder structure to be created: - C:\\Connector\\module\\cm\\content - C:\\Connector\\module\\db - Unzip the scwdp.zip file. - Copy all dacpac files from the root of the zip folder to C:\\Connector\\module\\db. Rename them in the format Sitecore..dacpac (e.g., Sitecore.master.dacpac, Sitecore.core.dacpac). - Copy the contents of {Unzipped scwdp folder}\\Content\\Website to C:\\Connector\\module\\cm\\content. ![Directory structure created for converting scwdp files into a Docker container image.](https://static.wixstatic.com/media/14fd51_7eb546aee86147268dbd191adba35c56~mv2.jpg/v1/fill/w_526,h_684,al_c,q_80,enc_avif,quality_auto/14fd51_7eb546aee86147268dbd191adba35c56~mv2.jpg) Screenshot showing the directory structure created for converting scwdp files into a Docker container image. ## Creating a Docker image and pushing it to Azure Container Registry (ACR) - Create a DockerFile in the directory C:\\connector\\. - Copy the following content into the Dockerfile: ``` FROM mcr.microsoft.com/windows/nanoserver:ltsc2022 AS build # Copy assets into the image, keeping the folder structure COPY / ./ ``` - To build the Docker image, open PowerShell in admin mode and navigate to C:\\connector\\. Then, execute the following command: ``` docker build --tag connector:1.0.0 . ``` - Note: "connector:1.0.0" represents the name and [tag](https://docs.docker.com/engine/reference/commandline/build/?ref=gowthamaraja.com#tag) of the image. - Once the image is successfully built, run the following command to launch the image and verify that all your files are present: ``` docker run -it container_id ``` - Note: "container\_id" refers to the ID of the container image you just created using the "docker build" command. - Before pushing the container to Azure Container Register, you need to create a repository. For detailed instructions, please refer to Microsoft's official documentation on [Quickstart: Create an Azure container registry using the Azure portal](https://learn.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal?tabs=azure-cli&ref=gowthamaraja.com). - Use the following commands to tag the image and push it to Azure Container Registry: ``` docker tag connector:1.0.0 connector.azurecr.io/connector:1.0.0 docker push connector.azurecr.io/connector:1.0.0 ``` - Note: "connector:1.0.0" represents the name and tag of the image in the Azure Container Registry. ## Add the image to your Sitecore instance - To verify the image and test its functionality, use Sitecore's Custom Image for Docker. - Clone the Sitecore Custom Image for Docker repository. - Make the following changes to add your custom module: - Create a custom module specifically for CM with items on both Core and Master DB. - Modify the docker-compose.override.yml and Dockerfile of cm and mssql-init. - In the docker-compose.override.yml file, add the custom module as follows: ``` cm: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xp0-cm:${VERSION:-latest} build: context: ./docker/build/cm args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xp0-cm:${SITECORE_VERSION} SPE_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-spe-assets:${SPE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xp1-assets:${SXA_VERSION} TOOLING_IMAGE: ${SITECORE_TOOLS_REGISTRY}sitecore-docker-tools-assets:${TOOLS_VERSION} CONNECTOR: connector.azurecr.io/connector:1.0.0 volumes: - ${LOCAL_DATA_PATH}\cm:C:\inetpub\wwwroot\App_Data\logs - ${LOCAL_DATA_PATH}\devicedetection:C:\inetpub\wwwroot\App_Data\DeviceDetection - C:\tools\entrypoints\iis\Development.ps1 mssql-init: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xp0-mssql-init:${VERSION:-latest} build: context: ./docker/build/mssql-init args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xp1-mssql-init:${SITECORE_VERSION} SPE_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-spe-assets:${SPE_VERSION} CONNECTOR: connector.azurecr.io/connector:1.0.0 ``` - Open the Dockerfile of CM and make the following changes: ``` # escape=` ARG BASE_IMAGE ARG SXA_IMAGE ARG SPE_IMAGE ARG TOOLING_IMAGE ARG CONNECTOR FROM ${CONNECTOR} as connector FROM ${TOOLING_IMAGE} as tooling FROM ${SPE_IMAGE} as spe FROM ${SXA_IMAGE} as sxa FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] # Copy development tools and entrypoint COPY --from=tooling \tools\ \tools\ WORKDIR C:\inetpub\wwwroot # Add SPE module COPY --from=spe \module\cm\content .\ # Add SXA module COPY --from=sxa \module\cm\content .\ COPY --from=sxa \module\tools \module\tools RUN C:\module\tools\Initialize-Content.ps1 -TargetPath .\; ` Remove-Item -Path C:\module -Recurse -Force; COPY --from=connector \module\cm\content .\ ``` - Open the Dockerfile of mssql-init file and make the following changes: ``` # escape=` ARG BASE_IMAGE ARG SPE_IMAGE ARG CONNECTOR FROM ${SPE_IMAGE} as spe FROM ${CONNECTOR} as connector FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] COPY --from=spe C:\module\db C:\resources\spe COPY --from=connector \module\db C:\resources\connector ``` - To verify your changes in Sitecore, open PowerShell in admin mode and execute the following command: ``` docker compose up -d ``` - Navigate to Sitecore, and you will be able to observe your changes reflected in the Sitecore Content Tree. Congratulations, you've now successfully created a Docker asset image for your Sitecore module! You've learned how to navigate the unique environment of Docker and Sitecore, overcome the challenges of installing Docker packages, and create a customized image for your package. Remember to keep exploring and learning, and don't hesitate to revisit this guide as you continue your Docker and Sitecore journey! ## References: - [Add Sitecore modules](https://doc.sitecore.com/xp/en/developers/103/developer-tools/add-sitecore-modules.html?ref=gowthamaraja.com) - [https://medium.com/@mitya\_1988/how-to-create-a-docker-asset-image-for-your-sitecore-module-58e1f3a47672](https://medium.com/@mitya%5F1988/how-to-create-a-docker-asset-image-for-your-sitecore-module-58e1f3a47672?ref=gowthamaraja.com) - [Approaches to Dockerizing Existing Sitecore Solutions for Local Development \~ Sitecore Gabe](https://www.sitecoregabe.com/2020/07/dockerizing-existing-sitecore-solutions.html?ref=gowthamaraja.com) - [Creating a Docker Asset Image for Your Sitecore Module and Adding It To Your Site – Erica's Sitecore Adventures (wordpress.com)](https://ericastockwellalpert.wordpress.com/2021/02/23/creating-a-docker-asset-image-for-your-sitecore-module-and-adding-it-to-your-site/?ref=gowthamaraja.com) - [Installing Sitecore Packages to Containers | georgechang.io](https://georgechang.io/posts/2021/installing-sitecore-packages-to-containers/?ref=gowthamaraja.com) ### Guide to Sitecore Embeddable Forms Framework (EFF) URL: https://www.gowthamaraja.com/guide-to-sitecore-embeddable-forms-framework-eff/ Last updated: 2025-11-17T07:06:33.000Z In Sitecore 10.3, a new feature known as the Embeddable Forms Framework (EFF) was introduced, providing the ability to integrate Sitecore forms into any webpage, regardless of whether it is running on a Sitecore application or not. This additional flexibility gives developers the opportunity to utilize Sitecore's form functionalities across diverse platforms, thus extending Sitecore's influence beyond its own ecosystem. The embedded form maintains its non-interfering nature, ensuring the preservation of the webpage's current functionality and styling. To incorporate an embeddable form, developers are required to reference the EFF script and subsequently add a web component tag for the Sitecore form. ## Guide to Sitecore Embeddable Forms Framework (EFF) EFF offers several benefits, including: 1. **Versatility**: EFF allows for the embedding of Sitecore forms across any webpage, irrespective of the underlying application. This versatility allows developers to utilize Sitecore forms across a broad range of platforms and websites. 2. **Non-Intrusive**: The embedded forms do not meddle with the webpage's existing functionality or styles, ensuring seamless integration of Sitecore forms without disrupting your site's design or operation. 3. **Simplicity**: EFF simplifies the process of adding an embeddable form to a webpage. All that's required is referencing the EFF script and adding a web component tag for the Sitecore form. 4. **Customizability**: EFF provides the flexibility to customize your forms as per your needs. If you need to showcase a custom form element, create a class to render this element and reference it on the webpage. 5. **Accessibility**: EFF supports ARIA attributes, making the forms accessible to a wider range of users, including those who use assistive technologies such as screen readers. Before you can add an embeddable form to your web application, certain prerequisites need to be met. Let's review these below. ## Prerequisites for Using Sitecore Embeddable Forms Framework (EFF) The following prerequisites must be met to utilize the Sitecore Embeddable Forms Framework (EFF): - **Sitecore Version:** Sitecore 10.3.0 or later is required. This version hosts the Layout Service and the submission endpoint. These are responsible for dynamically constructing the requested page's layout and managing form submissions, respectively. - **Sitecore Headless Services:** Sitecore Headless Services 21.0.0 or later is required. These services enable the development of headless applications with Sitecore and provide the necessary APIs for interacting with Sitecore's content and functionalities in a decoupled manner. Now, let's proceed to the steps to work with EFF. ## Preparing to Work with EFF Before you can add an embeddable form to your web application, you must prepare your Sitecore instance and web application to work with the EFF. To prepare your Sitecore instance and web application to work with the EFF: - Download the [Sitecore Headless Rendering 21+](https://dev.sitecore.net/Downloads/Sitecore%5FHeadless%5FRendering.aspx?ref=gowthamaraja.com) and install it on your Sitecore 10.3 instance. - You can find the official documentation of [how to install Sitecore Headless Serivices](https://doc.sitecore.com/xp/en/developers/hd/211/sitecore-headless-development/install-headless-services-using-the-package--zip-file.html?ref=gowthamaraja.com#install-sitecore-headless-services) - Once the installation of Headless Serivices is completed now we need to [create an API key](https://doc.sitecore.com/xp/en/developers/hd/190/sitecore-headless-development/create-a-sitecore-api-key.html?ref=gowthamaraja.com) for accessing the items from Sitecore. - Login to your 10.3 Sitecore instance and navigate to */sitecore/system/Settings/Services/API Keys/* and create a new API called "embeddable-forms" - After creating the API key update the CORS Origin and Allowed Controllers as \* (wildcard). This is only for testing purposes and when you're using this in Production follow this [official recommendation](https://doc.sitecore.com/xp/en/developers/hd/190/sitecore-headless-development/create-a-sitecore-api-key.html?ref=gowthamaraja.com) from Sitecore. ![Sitecore layout service validation results shown on a web browser screenshot](https://static.wixstatic.com/media/14fd51_c7edef339cb34b15a020bd2782acd56d~mv2.webp/v1/fill/w_740,h_350,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_c7edef339cb34b15a020bd2782acd56d~mv2.webp) Sitecore layout service validation results shown on a web browser screenshot - Publish the site and check if the layout service is working. To validate it browse it using *https:///sitecore/api/layout/render?item=/&sc\_apikey=.* For example: [https://](https://efsc.dev.local/sitecore/api/layout/render?item={110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}&sc%5Fapikey={F28808C9-3850-420A-B10C-C616947B8BF3}&ref=gowthamaraja.com)[efsc.dev.local/sitecore/api/layout/render?item={110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}&sc\_apikey={F28808C9-3850-420A-B10C-C616947B8BF3}](https://efsc.dev.local/sitecore/api/layout/render?item={110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}&sc%5Fapikey={F28808C9-3850-420A-B10C-C616947B8BF3}&ref=gowthamaraja.com) and you will get the result as below. ![Successful installation of Sitecore Headless service and API creation visualized.](https://static.wixstatic.com/media/14fd51_96eb3f3a82ce411e8931c4f6b5d9c4b7~mv2.webp/v1/fill/w_740,h_61,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_96eb3f3a82ce411e8931c4f6b5d9c4b7~mv2.webp) Successful installation of Sitecore Headless service and API creation visualized. - At this point we've successfully installed the Sitecore Headless service and created an API for accessing item using Layout Service. - Download and extract the [Sitecore Embeddable Forms for Sitecore ZIP file](https://dev.sitecore.net/Downloads/Sitecore%5FEmbeddable%5FForms/1x/Sitecore%5FEmbeddable%5FForms%5F100.aspx?ref=gowthamaraja.com), then copy the sitecore-embeddableforms.umd.js file to your web application directory. ## Creating the Sitecore Form - On the Forms dashboard, click **Create** - To create a new form from scratch, click **Blank form**, or select a template to base your form on. - In the **Form elements** pane, click the element that you want to add and drag it onto the form canvas. ![Sitecore Forms dashboard user interface with a form element being dragged onto the canvas.](https://static.wixstatic.com/media/14fd51_c2ae0dda707d42dc992600d876239d48~mv2.webp/v1/fill/w_740,h_271,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_c2ae0dda707d42dc992600d876239d48~mv2.webp) Sitecore Forms dashboard user interface with a form element being dragged onto the canvas. - Add basic form fields as below. Save it and publish the form ![Screenshot of a 'Contact Us' form with basic fields created in Sitecore Forms dashboard.](https://static.wixstatic.com/media/14fd51_8423d9658aee458fa82c5c069de48dcb~mv2.webp/v1/fill/w_740,h_331,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_8423d9658aee458fa82c5c069de48dcb~mv2.webp) Screenshot of a 'Contact Us' form with basic fields created in Sitecore Forms dashboard. For detailed steps for creating the Sitecore Form follow the official document of [Design a form.](https://doc.sitecore.com/xp/en/users/103/sitecore-experience-platform/design-a-form.html?ref=gowthamaraja.com) Now that you have created a Sitecore form, let's move on to embedding it in a webpage. ## Adding an Embeddable Form to a Webpage To add a form to a webpage: - Create a simple HTML page which contains script tag which refers to the EFF form. ``` ``` - Add a *scef-form* tag to specify the Sitecore form item: ``` ``` - The sample HTML page would look like this. ``` Sitecore Embeddable Forms Sample

Sitecore Embeddable Forms Sample

``` - Place the style.css file extracted from the [Sitecore Embeddable Forms](https://dev.sitecore.net/Downloads/Sitecore%5FEmbeddable%5FForms/1x/Sitecore%5FEmbeddable%5FForms%5F100.aspx?ref=gowthamaraja.com) under css folder. - To access the page, host the page in IIS (else you'll get CORS error) and access the page from IIS with the address you configured. - When you access the page, you'll get the form loaded on the page as below. ![Web page view featuring a loaded Sitecore embeddable form.](https://static.wixstatic.com/media/14fd51_f7420322216746149f818a07207f7903~mv2.webp/v1/fill/w_740,h_309,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_f7420322216746149f818a07207f7903~mv2.webp) Web page view featuring a loaded Sitecore embeddable form. ## Limitations of Sitecore EFF It's also important to note some xDB-exclusive features are not available in EFF, including: - Trigger Goal submit action. - Trigger Campaign Activity submit action. - Trigger Outcome submit action. - Performance Tracking. - Robot Detection. We hope this guide has provided you with all the necessary information about the EFF and how to integrate a Sitecore form in another site. If you have any questions or comments, feel free to leave them below. We would love to hear your thoughts! ## References - [Embeddable Forms Framework (sitecore.com)](https://doc.sitecore.com/xp/en/developers/103/sitecore-experience-manager/embeddable-forms-framework.html?ref=gowthamaraja.com) - [Walkthrough: Adding an embeddable form to a webpage (sitecore.com)](https://doc.sitecore.com/xp/en/developers/103/sitecore-experience-manager/walkthrough--adding-an-embeddable-form-to-a-webpage.html?ref=gowthamaraja.com) - [Design a form (sitecore.com)](https://doc.sitecore.com/xp/en/users/103/sitecore-experience-platform/design-a-form.html?ref=gowthamaraja.com) - [Embeddable Forms Framework – Sitecore 10.3 (sitecorebeast.blogspot.com)](https://sitecorebeast.blogspot.com/2023/01/embeddable-forms-framework-sitecore-103.html?ref=gowthamaraja.com) ### Building a Sitecore Solution from Scratch with Docker: Part 4 URL: https://www.gowthamaraja.com/sitecore-docker-solution-building-from-scratch-part-4/ Last updated: 2025-11-17T10:46:27.000Z In our previous blog post, we successfully installed SXA and SPE on our Docker image. In this upcoming post, we will explore the process of creating a solution using Helix architecture and implementing changes on Docker. ## Creating Sitecore Docker Solution with Helix Architecture We can now begin the process of developing the code and establishing the solution structure. To do so, let us create a folder named "src" at the root level, and within that, create the Foundation, Feature, and Project folders using Helix architecture, as illustrated below. ![helix](https://static.wixstatic.com/media/14fd51_aae28775393643f3835d9dd52a2cf117~mv2.png/v1/fill/w_350,h_349,al_c,lg_1,q_85,enc_avif,quality_auto/14fd51_aae28775393643f3835d9dd52a2cf117~mv2.png) To begin, launch Visual Studio and create a new blank solution at the root level, naming it "SitecoreDocker". By default, Visual Studio generates a folder for your solution. You can relocate the contents of this folder to the root directory and delete the empty folder. After creating the solution, proceed to create new solution folders named Feature, Foundation, and Project. ![solution](https://static.wixstatic.com/media/14fd51_6cc4a354953f4f48ac04649ace9b4589~mv2.png/v1/fill/w_350,h_188,al_c,lg_1,q_85,enc_avif,quality_auto/14fd51_6cc4a354953f4f48ac04649ace9b4589~mv2.png) ## Creating the Projects Now we can create new projects, and as an example, I will create a project called "SitecoreDocker.Website" in the "\\src\\Project" folder as shown below screenshot. ![creating-new-project](https://static.wixstatic.com/media/14fd51_7d1ed67d8fb64d64b569152f6b0c756d~mv2.png/v1/fill/w_740,h_398,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_7d1ed67d8fb64d64b569152f6b0c756d~mv2.png) After creating the project, we will generate several sample files which will be deployed to our container image, and we will observe the resulting modifications on the site. Prior to doing so, we will rename the website project, assembly name, and default namespace in Visual Studio to "**SitecoreDocker.Website**". ![assembly-name-chages](https://static.wixstatic.com/media/14fd51_a8d2312666464419bdb2a2568158f965~mv2.png/v1/fill/w_740,h_398,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_a8d2312666464419bdb2a2568158f965~mv2.png) To proceed, we will generate an example view file by creating a view folder and configuring it with a sample configuration obtained from the App\_Config file, as depicted below. ![views-and-config](https://static.wixstatic.com/media/14fd51_0009c2cde9ff41788a5ae228092a8cfe~mv2.png/v1/fill/w_374,h_324,al_c,q_85,enc_avif,quality_auto/14fd51_0009c2cde9ff41788a5ae228092a8cfe~mv2.png) ## Creating Publish Profile and Deploy folder After completing the creation of our solution, which includes the essential files, our next step is to generate a publish profile. This profile will enable us to push our changes to the Docker Deploy folder, where they will be made available for consumption by Docker. Within our docker folder, we establish subfolders named "deploy" and "website". These subfolders will serve as our local deployment target, where we will place our code for execution and testing purposes. Ex: **SitcoreDocker\\docker\\deploy\\website** To create a publish folder right click on the SitecoreDocker.Websiteproject and click on Publish option and select target as Folder. ![Creating_Publish_Folder](https://static.wixstatic.com/media/14fd51_3181e125f7bf45c8b3999e3594c36c9a~mv2.png/v1/fill/w_740,h_519,al_c,q_90,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_3181e125f7bf45c8b3999e3594c36c9a~mv2.png) To publish our changes, we will specify the folder location as "SitcoreDocker\\docker\\deploy\\website". This folder, which we have previously created, will serve as the destination for our published files. ![publish-profile](https://static.wixstatic.com/media/14fd51_470c82a684a24239b7246e86095b18c0~mv2.png/v1/fill/w_740,h_519,al_c,q_90,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_470c82a684a24239b7246e86095b18c0~mv2.png) Click the "Finish" button to initiate the project publishing process. Once the publishing is complete, you can open the "SitcoreDocker\\docker\\deploy\\website" folder to verify that the changes have been successfully reflected within the folder. ![publishing-files](https://static.wixstatic.com/media/14fd51_518dee6eb8b542e9962bdd2d90947191~mv2.png/v1/fill/w_740,h_400,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_518dee6eb8b542e9962bdd2d90947191~mv2.png) ## Mounting Deployment folder to Docker Currently, we have a folder on our filesystem where our website is published, but it is not being utilized by our Docker instances. To enable coding for our new solution, we need to deploy our published code to the CM and CD Docker instances. To achieve this, we will begin by mounting our deployment folder to the CD and CM instances. We will create a new variable in our .env file and set its value to the path of our deploy folder. This will ensure that our Docker instances utilize the code from the specified deployment folder. ``` LOCAL_DEPLOY_PATH=.\docker\deploy ``` To mount the folder to the CD and CM instances, we will add a new volume entry in the \`docker-compose.override.yml\` file. This entry will associate the path of the deployment folder with the appropriate directories in the Docker containers. By doing so, the CD and CM instances will have access to the published code. ``` cd: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cd:${VERSION:-latest} build: context: ./docker/build/cd args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cd:${SITECORE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xm1-assets:${SXA_VERSION} volumes: - ${LOCAL_DATA_PATH}\cd:C:\inetpub\wwwroot\App_Data\logs - ${LOCAL_DEPLOY_PATH}\website:C:\deploy cm: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cm:${VERSION:-latest} build: context: ./docker/build/cm args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cm:${SITECORE_VERSION} SPE_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-spe-assets:${SPE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xm1-assets:${SXA_VERSION} volumes: - ${LOCAL_DATA_PATH}\cm:C:\inetpub\wwwroot\App_Data\logs - ${LOCAL_DEPLOY_PATH}\website:C:\deploy ``` By mounting our local path to the \`C:\\deploy\` path of the CD and CM instances, we establish a connection between the two. However, it's important to note that the current code is not yet included in the CM and CD websites. As a result, it has not been deployed to our website. To address this, the next step involves transferring the deployed code from the mounted folder to our website. This process will ensure that the code becomes part of the CM and CD websites and is deployed accordingly. ## Deploying files from mounted folder to container image Sitecore Docker Tools, offered by Sitecore, are a collection of utilities designed to support Sitecore developers in the setup and operation of containerized Sitecore environments. These tools serve as helpful utilities that simplify the process of initializing and managing Sitecore instances within Docker containers. To facilitate the monitoring of our deployment folder on both instances, we will start by using the "sitecore-docker-tools-assets" image. We'll then create an entrypoint that executes a PowerShell command. This command will continuously observe the deployment folder, ensuring that any modifications or additions are detected and appropriately managed in both the CD and CM instances. Within the .env file, we utilize the following parameters: ``` SITECORE_TOOLS_REGISTRY=scr.sitecore.com/tools/ TOOLS_VERSION=10.2-1809 ``` We incorporate the new TOOLING\_IMAGE and define the entry point within the docker-compose.override.yml file. ``` cd: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cd:${VERSION:-latest} build: context: ./docker/build/cd args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cd:${SITECORE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xm1-assets:${SXA_VERSION} TOOLING_IMAGE: ${SITECORE_TOOLS_REGISTRY}sitecore-docker-tools-assets:${TOOLS_VERSION} volumes: - ${LOCAL_DATA_PATH}\cd:C:\inetpub\wwwroot\App_Data\logs - ${LOCAL_DEPLOY_PATH}\website:C:\deploy entrypoint: powershell -Command "& C:\\tools\\entrypoints\\iis\\Development.ps1" cm: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cm:${VERSION:-latest} build: context: ./docker/build/cm args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cm:${SITECORE_VERSION} SPE_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-spe-assets:${SPE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xm1-assets:${SXA_VERSION} TOOLING_IMAGE: ${SITECORE_TOOLS_REGISTRY}sitecore-docker-tools-assets:${TOOLS_VERSION} volumes: - ${LOCAL_DATA_PATH}\cm:C:\inetpub\wwwroot\App_Data\logs - ${LOCAL_DEPLOY_PATH}\website:C:\deploy entrypoint: powershell -Command "& C:\\tools\\entrypoints\\iis\\Development.ps1" ``` To include the Tooling Image in our custom image, you need to make modifications to both the CM and CD Dockerfiles as follows: CM: ``` # escape=` ARG BASE_IMAGE ARG SXA_IMAGE ARG SPE_IMAGE ARG TOOLING_IMAGE FROM ${SPE_IMAGE} as spe FROM ${SXA_IMAGE} as sxa FROM ${TOOLING_IMAGE} as tooling FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] # Copy development tools and entrypoint COPY --from=tooling \tools\ \tools\ WORKDIR C:\inetpub\wwwroot COPY --from=spe C:\module\cm\content C:\inetpub\wwwroot COPY --from=sxa C:\module\cm\content C:\inetpub\wwwroot COPY --from=sxa C:\module\tools C:\module\tools RUN C:\module\tools\Initialize-Content.ps1 -TargetPath C:\inetpub\wwwroot; ` Remove-Item -Path C:\module -Recurse -Force; ``` CD: ``` # escape=` ARG BASE_IMAGE ARG SXA_IMAGE ARG TOOLING_IMAGE FROM ${SXA_IMAGE} as sxa FROM ${TOOLING_IMAGE} as tooling FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] # Copy development tools and entrypoint COPY --from=tooling \tools\ \tools\ WORKDIR C:\inetpub\wwwroot COPY --from=sxa C:\module\cd\content C:\inetpub\wwwroot COPY --from=sxa C:\module\tools C:\module\tools RUN C:\module\tools\Initialize-Content.ps1 -TargetPath C:\inetpub\wwwroot; ` Remove-Item -Path C:\module -Recurse -Force; ``` ## Adding Docker Build Up to this point, we have successfully incorporated the required folders and configurations to facilitate the publishing of solution files. Now, the next step is to transform our solution into a container image. To achieve this, we need a dedicated Dockerfile that primarily focuses on building the solution and preserving the resulting output as structured build artifacts within the image. To enable the conversion of our solution into a container image, we must add the following parameters to the .env file: ``` SOLUTION_BUILD_IMAGE=mcr.microsoft.com/dotnet/framework/sdk:4.8 SOLUTION_BASE_IMAGE=mcr.microsoft.com/windows/nanoserver:1089 BUILD_CONFIGURATION=debug ``` In the docker-compose.override.yml file, when adding the Docker.build image, we include the following configuration: ``` solution: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-solution:${VERSION:-latest} build: context: . args: BASE_IMAGE: ${SOLUTION_BASE_IMAGE} BUILD_IMAGE: ${SOLUTION_BUILD_IMAGE} BUILD_CONFIGURATION: ${BUILD_CONFIGURATION} scale: 0 ``` To begin, we will create an empty Dockerfile within the root folder. Afterwards, we will populate it with the following content: ``` # escape=` ARG BASE_IMAGE ARG BUILD_IMAGE FROM ${BUILD_IMAGE} AS prep SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] # Gather only artifacts necessary for NuGet restore, retaining directory structure COPY *.sln nuget.config Directory.Build.targets Packages.props \nuget\ COPY src\ \temp\ RUN Invoke-Expression 'robocopy C:\temp C:\nuget\src /s /ndl /njh /njs *.csproj *.scproj packages.config' FROM ${BUILD_IMAGE} AS builder ARG BUILD_CONFIGURATION SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] # Create an empty working directory WORKDIR C:\build # Copy prepped NuGet artifacts, and restore as distinct layer to take better advantage of caching COPY --from=prep .\nuget .\ RUN nuget restore # Copy remaining source code COPY src\ .\src\ # Copy transforms, retaining directory structure RUN Invoke-Expression 'robocopy C:\build\src C:\out\transforms /s /ndl /njh /njs *.xdt' # Build website with file publish RUN msbuild .\src\Project\website\SitecoreDocker.Website.csproj /p:Configuration=$env:BUILD_CONFIGURATION /p:DeployOnBuild=True /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:PublishUrl=C:\out\website FROM ${BASE_IMAGE} WORKDIR C:\artifacts # Copy final build artifacts COPY --from=builder C:\out\website .\website\ ``` This newly added Dockerfile, located in the root folder, serves the purpose of creating our custom image. It not only builds the solution but also transfers the generated artifacts to their designated locations within the container. Within the docker-compose.override.yml file, we introduce an extra args parameter specifically for CD and CM. ``` cd: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cd:${VERSION:-latest} build: context: ./docker/build/cd args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cd:${SITECORE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xm1-assets:${SXA_VERSION} TOOLING_IMAGE: ${SITECORE_TOOLS_REGISTRY}sitecore-docker-tools-assets:${TOOLS_VERSION} SOLUTION_IMAGE: ${REGISTRY}${COMPOSE_PROJECT_NAME}-solution:${VERSION:-latest} depends_on: - solution volumes: - ${LOCAL_DEPLOY_PATH}\website:C:\deploy - ${LOCAL_DATA_PATH}\cd:C:\inetpub\wwwroot\App_Data\logs - ${LOCAL_DATA_PATH}\devicedetection:C:\inetpub\wwwroot\App_Data\DeviceDetection environment: SITECORE_DEVELOPMENT_PATCHES: CustomErrorsOff entrypoint: powershell -Command "& C:\\tools\\entrypoints\\iis\\Development.ps1" cm: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cm:${VERSION:-latest} build: context: ./docker/build/cm args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cm:${SITECORE_VERSION} SPE_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-spe-assets:${SPE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xm1-assets:${SXA_VERSION} TOOLING_IMAGE: ${SITECORE_TOOLS_REGISTRY}sitecore-docker-tools-assets:${TOOLS_VERSION} SOLUTION_IMAGE: ${REGISTRY}${COMPOSE_PROJECT_NAME}-solution:${VERSION:-latest} depends_on: - solution volumes: - ${LOCAL_DEPLOY_PATH}\website:C:\deploy - ${LOCAL_DATA_PATH}\cm:C:\inetpub\wwwroot\App_Data\logs environment: SITECORE_DEVELOPMENT_PATCHES: CustomErrorsOff entrypoint: powershell -Command "& C:\\tools\\entrypoints\\iis\\Development.ps1" ``` In order to incorporate this additional parameter into our build process, we must make adjustments to the Dockerfiles for CM and CD. CM: ``` # escape=` ARG BASE_IMAGE ARG SXA_IMAGE ARG SPE_IMAGE ARG TOOLING_IMAGE FROM ${TOOLING_IMAGE} as tooling FROM ${SPE_IMAGE} as spe FROM ${SXA_IMAGE} as sxa FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] # Copy development tools and entrypoint COPY --from=tooling \tools\ \tools\ WORKDIR C:\inetpub\wwwroot # Add SPE module COPY --from=spe \module\cm\content .\ # Add SXA module COPY --from=sxa \module\cm\content .\ COPY --from=sxa \module\tools \module\tools RUN C:\module\tools\Initialize-Content.ps1 -TargetPath .\; ` Remove-Item -Path C:\module -Recurse -Force; # Copy solution website files COPY --from=solution \artifacts\website\ .\ ``` CD: ``` # escape=` ARG BASE_IMAGE ARG SXA_IMAGE ARG TOOLING_IMAGE FROM ${TOOLING_IMAGE} as tooling FROM ${SXA_IMAGE} as sxa FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] # Copy development tools and entrypoint COPY --from=tooling \tools\ \tools\ WORKDIR C:\inetpub\wwwroot # Add SXA module COPY --from=sxa \module\cd\content .\ COPY --from=sxa \module\tools \module\tools RUN C:\module\tools\Initialize-Content.ps1 -TargetPath .\; ` Remove-Item -Path C:\module -Recurse -Force; # Copy solution website files COPY --from=solution \artifacts\website\ .\ ``` We have finished setting up the solution, and now it's time to try it out by running our containers. To do this, just use the command below. ``` docker compose up -d ``` Once the website is up and operational, you can verify that the files have been successfully deployed to the container image by executing the following command in the Docker Desktop Terminal window on both CD and CM. ``` cd bin dir SitecoreDocker* ``` ![verifying-deployment](https://static.wixstatic.com/media/14fd51_53a0eca9d958435faccfb7f5efbb590f~mv2.png/v1/fill/w_740,h_401,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_53a0eca9d958435faccfb7f5efbb590f~mv2.png) If you see the screen above, it means you have successfully finished creating and deploying a new solution for Sitecore from scratch using Docker with the Helix architecture. I consider this as the final part of the series, and I may use the same repository in the future for any additional extensions if needed. You can find the entire solution at the provided [link](https://github.com/GowthamEswaramoorthy/SitecoreDocker?ref=gowthamaraja.com). If you have any questions, please leave them in the comment box, and I will get back to you soon. Thank you and enjoy working with Sitecore! ### How to Set Up Sitecore XM Cloud Locally using Docker: A Detailed Guide URL: https://www.gowthamaraja.com/how-to-set-up-sitecore-xm-cloud-locally-using-docker-a-detailed-guide/ Last updated: 2025-11-17T06:19:29.000Z Are you looking to set up a Sitecore XM Cloud locally using Docker containers? In this comprehensive guide, I will walk you through the process of setting up a Sitecore XM Cloud environment using Docker containers. Sitecore XM Cloud is a powerful platform that enables you to create and manage your digital content with ease. Leveraging Docker containers allows you to easily spin up a local environment that mirrors the production environment. This guide is perfect for developers, DevOps engineers, and anyone interested in learning more about Sitecore XM Cloud and Docker containers. **Let's dive in and get started!** --- ## [Prerequisites](https://www.gowthamaraja.com/post/how-to-set-up-sitecore-xm-cloud-locally-with-docker#viewer-npk9) Before we start setting up the Sitecore XM Cloud, ensure that you have the following prerequisites ready: 1. A valid Sitecore License file 2. .Net SDK 6.0 and runtime, which you can [download and install from here](https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/sdk-6.0.404-windows-x64-installer?ref=gowthamaraja.com). You can verify if you already have it installed by running the 'dotnet --info' command in your terminal. 3. .NET Framework 4.8 SDK 4. Docker for Desktop with Windows Containers enabled, along with other installation requirements for Docker Containers. You can find all the installation requirements on the [Docker Containers Sitecore website](https://doc.sitecore.com/xmc/en/developers/xm-cloud/walkthrough--setting-up-your-full-stack-xm-cloud-local-development-environment.html?ref=gowthamaraja.com). 5. Node LTS, which you can [download and install from here](https://nodejs.org/en/?ref=gowthamaraja.com). The minimum required version is v18.13.0. 6. PowerShell 5.1 7. Hyper-V enabled from within the 'Turn Windows features on or off' option. 8. An account on [https://portal.sitecorecloud.io](https://portal.sitecorecloud.io/?ref=gowthamaraja.com). If you already have access to the XM Cloud portal and are part of an organization, you can skip this step. Otherwise, register yourself even if you don't have an organization yet. You'll need to log in to your local environment using this account. --- ## [Spinning up the containers:](https://www.gowthamaraja.com/post/how-to-set-up-sitecore-xm-cloud-locally-with-docker#viewer-8ps84) After ensuring that you have all the prerequisites in place, it's time to spin up the Docker containers. Follow these steps: - Clone the Sitecore [XM Cloud repository](https://github.com/sitecorelabs/xmcloud-foundation-head?ref=gowthamaraja.com) from GitHub to your local machine. You can clone it to a directory of your choice. For example, D:\\xmcloud directory. - Open PowerShell in admin mode and navigate to the directory where you cloned the XM Cloud repo. For instance, you can run the following command to switch to the directory: ``` cd D:\xmcloud\xmcloud-foundation-head ``` - Run the following command in PowerShell ``` .\init.ps1 -InitEnv -LicenseXmlPath "C:\path\to\license.xml" -AdminPassword "DesiredAdminPassword" ``` - Replace "C:\\path\\to\\license.xml" with the path to your license file and "DesiredAdminPassword" with your desired admin password. - Once the command completes successfully, you'll see a message on the PowerShell window indicating that you need to set the NODE\_EXTRA\_CA\_CERTS environment variable to avoid HTTPS errors. Copy the command provided in the message and run it on your terminal. ``` ########################################################################### To avoid HTTPS errors, set the NODE_EXTRA_CA_CERTS environment variable using the following commmand: setx NODE_EXTRA_CA_CERTS C:\Users\Gowthamaraja.Eswaramoorthy\AppData\Local\mkcert\rootCA.pem You will need to restart your terminal or VS Code for it to take effect. ########################################################################### ``` - After running the command successfully, you'll get the message "SUCCESS: Specified value was saved." You can then close the terminal and reopen it again and navigate back to the directory where you cloned the XM Cloud repository. - Run the below command in terminal to download the images required for the XM Cloud: ``` .\up.ps1 ``` - When successful, you'll get the Device Confirmation screen on your browser. Confirm this to proceed with the next steps. ![Device Confirmation Screen in XM Cloud](https://static.wixstatic.com/media/14fd51_38e07b96b6f048d58e1e62368ac40410~mv2.png/v1/fill/w_398,h_541,al_c,q_85,enc_avif,quality_auto/14fd51_38e07b96b6f048d58e1e62368ac40410~mv2.png) Device Confirmation Screen in XM Cloud - After confirmation, other preconfigured processes like Indexing and restoring the items will be processed. Once all processes are done successfully, you will get your local site opening on your browser. ![Local Site of XM Cloud on Browser](https://static.wixstatic.com/media/14fd51_4e2e5ced68f64e1684744f6540bf490e~mv2.png/v1/fill/w_740,h_412,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_4e2e5ced68f64e1684744f6540bf490e~mv2.png) Local Site of XM Cloud on Browser At this point, we have successfully installed XM Cloud on our local environment using Docker Container. --- ## [Configuring the front end project:](https://www.gowthamaraja.com/post/how-to-set-up-sitecore-xm-cloud-locally-with-docker#viewer-8gjvt) Once you've successfully set up the XM Cloud on your local environment, the next step is configuring the front-end project. Follow the steps below: - Navigate to the src\\sxastarter folder where you have the SXA starter template project. - In this folder, run the command: ``` jss setup ``` - If the "jss" command is not available, install it using the command. ``` npm install -g @sitecore-jss/sitecore-jss-cli ``` - After running the "jss setup" command in the "src\\sxastarter" folder, a few configuration-related questions will be prompted. - To obtain the Sitecore API Key, go to the CMS and navigate to this path: "/sitecore/system/Settings/Services/API Keys/xmcloudpreview". Note that the XM Cloud environment is pre-configured with the GUID {B35645D5-D54B-4E92-87E8-718DB9DB4195}, which we will use. ![Sitecore API Key Retrieval from CMS](https://static.wixstatic.com/media/14fd51_2484941c21954cf0bdfe1aef90986392~mv2.png/v1/fill/w_740,h_482,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_2484941c21954cf0bdfe1aef90986392~mv2.png) Sitecore API Key Retrieval from CMS - The file scjssconfig.json is generated by the jss setup command, and it looks like: ``` { "sitecore": { "instancePath": "", "apiKey": "{B35645D5-D54B-4E92-87E8-718DB9DB4195}", "deploySecret": "hi7p5zg1l6h4ks5t6awfc3eo8g6d4xojsjxj3zmbo84g", "deployUrl": "https://xmcloudcm.localhost/sitecore/api/jss/import", "layoutServiceHost": "https://xmcloudcm.localhost" } } ``` ## [Setting up XM Cloud to deploy our JSS app](https://www.gowthamaraja.com/post/how-to-set-up-sitecore-xm-cloud-locally-with-docker#viewer-3hkco) Before deploying the JSS app, we need to prepare the XM Cloud environment by creating a headless tenant and a headless site with the name of the JSS app. Here's how to do it: - The name of the JSS app can be found in the "package.json" file ![Package.json File Displaying the Name of the JSS App](https://static.wixstatic.com/media/14fd51_31201fa4761c47ca869899d15069898d~mv2.png/v1/fill/w_740,h_461,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_31201fa4761c47ca869899d15069898d~mv2.png) Package.json File Displaying the Name of the JSS App - Login to Sitecore and create the Headless Collection ![Creation of Headless Collection in Sitecore](https://static.wixstatic.com/media/14fd51_ecaa9b891de445e2a2106e8ebf5691c1~mv2.png/v1/fill/w_501,h_615,al_c,q_85,enc_avif,quality_auto/14fd51_ecaa9b891de445e2a2106e8ebf5691c1~mv2.png) Creation of Headless Collection in Sitecore - Create Headless site. ![Creation of Headless Site in Sitecore](https://static.wixstatic.com/media/14fd51_816789e05f704b9180d4113b693eedb9~mv2.png/v1/fill/w_500,h_616,al_c,q_85,enc_avif,quality_auto/14fd51_816789e05f704b9180d4113b693eedb9~mv2.png) Creation of Headless Site in Sitecore - Use the Deployment secret from the scjssconfig.json file. ![Entering Deployment Secret in Sitecore](https://static.wixstatic.com/media/14fd51_6e53eba6403a42cdb250c912c00ef39d~mv2.png/v1/fill/w_499,h_615,al_c,q_85,enc_avif,quality_auto/14fd51_6e53eba6403a42cdb250c912c00ef39d~mv2.png) Entering Deployment Secret in Sitecore - Once the site is created run the below command to push the serialized items to Sitecore which includes the rendering item ``` dotnet sitecore ser push ``` ## [Starting the app](https://www.gowthamaraja.com/post/how-to-set-up-sitecore-xm-cloud-locally-with-docker#viewer-e24gs) Finally, it's time to start your app and see it in action. Follow the steps below: - To prepare the app, run "**npm i**" in your terminal. Once the installation is complete, run "**npm run start:connected**" to start the app in Sitecore connected mode. - The app should now be available on [https://www.sxastarter.localhost/](https://www.sxastarter.localhost/?ref=gowthamaraja.com) - Open the Home page in the Experience Editor and start developing. ![Experience Editor Interface in Sitecore](https://static.wixstatic.com/media/14fd51_ba69800a21e1456b9b78a2fd8f0599ce~mv2.png/v1/fill/w_740,h_252,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_ba69800a21e1456b9b78a2fd8f0599ce~mv2.png) Experience Editor Interface in Sitecore - To stop the container, change the directory to D:\\xmcloud\\xmcloud-foundation-head and run the .\\down.ps1 That's it! You have successfully set up a Sitecore XM Cloud locally using Docker Containers. Happy coding! I hope this guide has been helpful for those of you looking to get started with Sitecore XM Cloud and Docker. If you have any questions or need further clarification, feel free to reach out. Happy Sitecore development! ### Building a Sitecore Solution from Scratch with Docker: Part 3 URL: https://www.gowthamaraja.com/sitecore-docker-solution-building-from-scratch-part-3/ Last updated: 2025-11-17T10:47:59.000Z Our previous post focused on how we updated the folder structure to comply with Helix principles, enabling us to construct our solution utilizing the Helix methodology. Additionally, we aimed to simplify the implementation process by utilizing the XM topology. In this blog, we will delve into the process of integrating Sitecore modules such as SXA and SPE. To start the process of integrating custom modules, the first step is to include the fundamental configuration necessary for the CM and CD setup in the "docker-compose.override.yml" file. This can be achieved by adding the appropriate entries for CM and CD. Additionally, we will need to include the DockerFile for this setup. Add the below entries to the "docker-compose.override.yml" ``` cm: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cm:${VERSION:-latest} build: context: ./docker/build/cm args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cm:${SITECORE_VERSION} cd: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cd:${VERSION:-latest} build: context: ./docker/build/cd args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cd:${SITECORE_VERSION} ``` Create two new folders named "cm" and "cd" under the "docker\\build" directory. Afterwards, you can add the appropriate DockerFile with the necessary content in these folders. ``` # escape=` ARG BASE_IMAGE FROM ${BASE_IMAGE} ``` Once you have added the changes, execute the following commands to halt and restart with the updated modifications. ``` docker compose down docker compose build docker compose up -d ``` ![cm_docker](https://static.wixstatic.com/media/14fd51_594fdfd6851f4cb4b2876f2745f658ce~mv2.png/v1/fill/w_740,h_405,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_594fdfd6851f4cb4b2876f2745f658ce~mv2.png) Now that the website is functioning properly, it's time to begin modifying the configuration for SXA and SPE. ## Adding SXA and SPE module This topic will cover the process of adding the SXA Module. The Sitecore Module Reference( [SXA](https://doc.sitecore.com/xp/en/developers/100/developer-tools/sitecore-module-reference.html?ref=gowthamaraja.com#sitecore-experience-accelerator--sxa-) and [SPE](https://doc.sitecore.com/xp/en/developers/100/developer-tools/sitecore-module-reference.html?ref=gowthamaraja.com#sitecore-powershell-extensions--spe-)) page contains the official documentation for adding the Sitecore SXA Module. Open the "docker-compose.override.yml" file and insert the following configurations under the corresponding roles. ``` mssql-init: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-mssql:${VERSION:-latest} build: context: ./docker/build/mssql-init args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-mssql-init:${SITECORE_VERSION} SPE_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-spe-assets:${SPE_VERSION} solr-init: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-solr-init:${VERSION:-latest} build: context: ./docker/build/solr-init args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-solr-init:${SITECORE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xm1-assets:${SXA_VERSION} id: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-id6:${VERSION:-latest} build: context: ./docker/build/id args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-id6:${SITECORE_VERSION} volumes: - ${HOST_LICENSE_FOLDER}:C:\license environment: SITECORE_LICENSE_LOCATION: C:\license\license.xml cd: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cd:${VERSION:-latest} build: context: ./docker/build/cd args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cd:${SITECORE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xm1-assets:${SXA_VERSION} volumes: - ${LOCAL_DATA_PATH}\cd:C:\inetpub\wwwroot\App_Data\logs cm: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-cm:${VERSION:-latest} build: context: ./docker/build/cm args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-cm:${SITECORE_VERSION} SPE_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-spe-assets:${SPE_VERSION} SXA_IMAGE: ${SITECORE_MODULE_REGISTRY}sitecore-sxa-xm1-assets:${SXA_VERSION} volumes: - ${LOCAL_DATA_PATH}\cm:C:\inetpub\wwwroot\App_Data\logs ``` To store the log files for the CM and CD roles, create a new folder named "cm" and "cd" within the "docker\\data" directory. ![data_folder_structure](https://static.wixstatic.com/media/14fd51_11949375cd704b03bee2b6ce1e27d774~mv2.png/v1/fill/w_342,h_716,al_c,lg_1,q_85,enc_avif,quality_auto/14fd51_11949375cd704b03bee2b6ce1e27d774~mv2.png) Include the following variables in the .env file, which will be utilized in the docker-compose.override.yml file. ``` SPE_VERSION=6.4-1809 SXA_VERSION=10.3-1809 HOST_LICENSE_FOLDER=C:\license SITECORE_MODULE_REGISTRY=scr.sitecore.com/sxp/modules/ ``` ## DockerFile If you do not have the DockerFile, please create it under docker\\build and then apply the provided configuration code for the mentioned roles. ### cd: ``` # escape=` ARG BASE_IMAGE ARG SXA_IMAGE FROM ${SXA_IMAGE} as sxa FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] WORKDIR C:\inetpub\wwwroot COPY --from=sxa C:\module\cd\content C:\inetpub\wwwroot COPY --from=sxa C:\module\tools C:\module\tools RUN C:\module\tools\Initialize-Content.ps1 -TargetPath C:\inetpub\wwwroot; `Remove-Item -Path C:\module -Recurse -Force; ``` ### cm: ``` # escape=` ARG BASE_IMAGE ARG SXA_IMAGE ARG SPE_IMAGE FROM ${SPE_IMAGE} as spe FROM ${SXA_IMAGE} as sxa FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] WORKDIR C:\inetpub\wwwroot COPY --from=spe C:\module\cm\content C:\inetpub\wwwroot COPY --from=sxa C:\module\cm\content C:\inetpub\wwwroot COPY --from=sxa C:\module\tools C:\module\tools RUN C:\module\tools\Initialize-Content.ps1 -TargetPath C:\inetpub\wwwroot; `Remove-Item -Path C:\module -Recurse -Force; ``` ### mssql-init: ``` # escape=` ARG BASE_IMAGE ARG SPE_IMAGE FROM ${SPE_IMAGE} AS spe FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] COPY --from=spe C:\module\db C:\resources\spe ``` ### solr-init: ``` # escape=` ARG BASE_IMAGE ARG SXA_IMAGE FROM ${SXA_IMAGE} as sxa FROM ${BASE_IMAGE} SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"] COPY --from=sxa C:\module\solr\cores-sxa.json C:\data\cores-sxa.json ``` ### id: ``` # escape=` ARG BASE_IMAGE FROM ${BASE_IMAGE} ``` After implementing the aforementioned modifications, execute the below commands to confirm that the installation of SXA and SPE is successful. ``` docker compose down .\clean.ps1 docker compose build docker compose up -d ``` Launch your web browser and access the URL [https://cm.sitecoredocker.localhost/sitecore/login](https://cm.sitecoredocker.localhost/sitecore/login?ref=gowthamaraja.com) to confirm the successful installation of SXA and SPE. ![spe_verification](https://static.wixstatic.com/media/14fd51_78a6326dc04a47d18c7d771d4ec35c63~mv2.png/v1/fill/w_740,h_405,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_78a6326dc04a47d18c7d771d4ec35c63~mv2.png) ![sxa_verification](https://static.wixstatic.com/media/14fd51_d26b41de82274d478383c34b0c087a28~mv2.png/v1/fill/w_740,h_405,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_d26b41de82274d478383c34b0c087a28~mv2.png) We have completed the setup and preparation of Sitecore for our project's solution creation and deployment. In the next blog, we will explore how to create a Docker solution with Helix and integrate it with Docker for deployment purposes. ### Building a Sitecore Solution from Scratch with Docker: Part 2 URL: https://www.gowthamaraja.com/sitecore-docker-solution-building-from-scratch-part-2/ Last updated: 2025-11-17T10:47:28.000Z In our previous post, we discussed the installation of Docker using the default template which utilizes the Sitecore XP0 topology. In this blog post, we will update the folder structure to align with Helix principles, which will assist us in building our solution using the Helix methodology. Furthermore, we will use the XM topology for ease of implementation. ## Updating the folder structure In order to align with Helix guidelines, we will update the folder structure and adjust file paths as required. You can refer to [Sitecore's official Helix principles](https://github.com/Sitecore/Helix.Examples?ref=gowthamaraja.com) to ensure compliance with industry standards. Create a new folder named "docker" and a subfolder named "data". Rename the "*mssql-data*" folder to "*mssql*", "*device-detection*" folder to "*devicedetection*" and the "*solr-data*" folder to "*solr*", and then move both folders into the "data" subfolder that you created. ![docker-folder-structure](https://static.wixstatic.com/media/14fd51_60c43c03dce74b61a7b1f009c4265c29~mv2.png/v1/fill/w_740,h_277,al_c,lg_1,q_85,enc_avif,quality_auto/14fd51_60c43c03dce74b61a7b1f009c4265c29~mv2.png) Move the "traefik" folder to the "docker" folder and the "docker" folder structure will be similar to the following. ![docker-folder](https://static.wixstatic.com/media/14fd51_abb800f168f349ea832156b6e09ac9dc~mv2.png/v1/fill/w_740,h_275,al_c,lg_1,q_85,enc_avif,quality_auto/14fd51_abb800f168f349ea832156b6e09ac9dc~mv2.png) ## Update the configuration files ### Updating Clean.ps1 Now that we have updated the folder structure, we must also update our configuration files accordingly. Let's begin by updating the "Clean.ps1" script as shown below to reflect the new folder structure. ``` # Clean data folders Get-ChildItem -Path (Join-Path $PSScriptRoot "\docker\data\mssql") -Exclude ".gitkeep" -Recurse | Remove-Item -Force -Recurse -Verbose Get-ChildItem -Path (Join-Path $PSScriptRoot "\docker\data\solr") -Exclude ".gitkeep" -Recurse | Remove-Item -Force -Recurse -Verbose Get-ChildItem -Path (Join-Path $PSScriptRoot "\docker\data\cd") -Exclude ".gitkeep" -Recurse | Remove-Item -Force -Recurse -Verbose Get-ChildItem -Path (Join-Path $PSScriptRoot "\docker\data\cm") -Exclude ".gitkeep" -Recurse | Remove-Item -Force -Recurse -Verbose Get-ChildItem -Path (Join-Path $PSScriptRoot "\docker\data\devicedetection") -Exclude ".gitkeep" -Recurse | Remove-Item -Force -Recurse -Verbose Get-ChildItem -Path (Join-Path $PSScriptRoot "\docker\traefik\certs") -Exclude ".gitkeep" -Recurse | Remove-Item -Force -Recurse -Verbose ``` ### Updating .env file As previously mentioned, we will be implementing the XM topology. Therefore, we must add/update certain variables in the ".env" file. Please update the variables listed below in the ".env" file. ``` COMPOSE_PROJECT_NAME=sitecoredocker CD_HOST=cd.sitecoredocker.localhost CM_HOST=cm.sitecoredocker.localhost ID_HOST=id.sitecoredocker.localhost LOCAL_DEPLOY_PATH=.\docker\deploy LOCAL_DATA_PATH=.\docker\data ``` ### Update the Hostname in init.ps1 Now that we have updated the domain names, it is necessary to modify the locations where we generate the SSL certificate and assign them to the corresponding sites. Open the "certs\_config.yaml" file located at "\\docker\\traefik\\config\\dynamic" and replace the contents with the following. ``` tls: certificates: - certFile: C:\etc\traefik\certs\cert.pem keyFile: C:\etc\traefik\certs\key.pem ``` Navigate to the root folder and open ".init.ps1" file. Search for the relevant section and replace the contents with the following code: from ``` Write-Host "Generating Traefik TLS certificates..." -ForegroundColor Green & $mkcert -install & $mkcert -cert-file xp0cm.localhost.crt -key-file xp0cm.localhost.key "xp0cm.localhost" & $mkcert -cert-file xp0id.localhost.crt -key-file xp0id.localhost.key "xp0id.localhost" ``` to ``` Write-Host "Generating Traefik TLS certificate..." -ForegroundColor Green & $mkcert -install & $mkcert -key-file key.pem -cert-file cert.pem "*.$($HostName).localhost" ``` In the same file at the bottom, you will find the following code that adds the domains to the host entry. ``` Add-HostsEntry "xp0cm.localhost" Add-HostsEntry "xp0id.localhost" ``` Replace the previously mentioned code with the following code snippet. ``` Add-HostsEntry "cd.$($HostName).localhost" Add-HostsEntry "cm.$($HostName).localhost" Add-HostsEntry "id.$($HostName).localhost" ``` Search for the below code in the current file ``` Push-Location traefik\certs ``` Replace it with ``` Push-Location docker\traefik\certs `` ``` On the Param variables add the below line ``` [string] $HostName = "sitecoredocker", ``` ## Updating docker-compose and creating new files for XM1 topology So far, we have been using the default "docker-compose.yml" file for XP0 topology. However, we need to switch to the XM1 topology by using a different docker compose file. You can download the XM1 docker compose file from [here](https://github.com/GowthamEswaramoorthy/SitecoreDocker/blob/master/docker-compose.yml?ref=gowthamaraja.com) and replace it with your current configuration. Create a new file called "docker-compose.override.yml". The "docker-compose.override.yml" file is a configuration file that is used to override or extend the services defined in the base "docker-compose.yml". ### Traefik We will start by configuring the Traefik service in the "docker-compose.override.yml" file. We will mount the "traefik" folder from the root "./traefik" to "C:/etc/traefik" in our Docker image. Since we have updated the folder structure, we need to override this value to point to our new structure. ``` version: "2.4" services: traefik: volumes: - ./docker/traefik:C:/etc/traefik ``` ### Redis To install Redis for managing user sessions, we must update the "docker-compose.override.yml" file and create a corresponding Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. To include Redis in our setup, add the following code snippet to the "docker-compose.override.yml" file. ``` redis: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-redis:${VERSION:-latest} build: context: ./docker/build/redis args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-redis:${SITECORE_VERSION} ``` Create a new folder named "build" inside the "docker" folder, and then create a new folder called "redis" inside the "build" folder. Inside the "redis" folder, create a file named "Dockerfile" and add the following code to it. ``` # escape=` ARG BASE_IMAGE FROM ${BASE_IMAGE} ``` ![redis-folder-structure](https://static.wixstatic.com/media/14fd51_723ff50340c146ef8b61ced6082a0419~mv2.png/v1/fill/w_740,h_360,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_723ff50340c146ef8b61ced6082a0419~mv2.png) ### mssql-init and Solr Inside the "build" folder, we will create two new folders called "mssql-init and solr-init". We will then create a DockerFile inside the "mssql-init and solr-init" folder with the same content as the Redis DockerFile. ![mssql-init-and-solr-init](https://static.wixstatic.com/media/14fd51_20efa88608534fd7a251540b6e077cb7~mv2.png/v1/fill/w_740,h_331,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_20efa88608534fd7a251540b6e077cb7~mv2.png) After creating the files and folders, the next step is to insert the following code snippet into the docker-compose-override.yml file. This code snippet will help us to load the Solr and mssql images, which are necessary for running our basic XM site. Additionally, it will also assist us in mounting the data folder. ``` mssql: mem_limit: 2GB volumes: - ${LOCAL_DATA_PATH}\mssql:c:\data mssql-init: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-mssql:${VERSION:-latest} build: context: ./docker/build/mssql-init args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-mssql-init:${SITECORE_VERSION} # Mount our Solr data folder. solr: volumes: - ${LOCAL_DATA_PATH}\solr:c:\data # Mount our Solr data folder and use our retagged Solr image. # Some modules (like SXA) also require additions to the Solr image. solr-init: image: ${REGISTRY}${COMPOSE_PROJECT_NAME}-xm1-solr-init:${VERSION:-latest} build: context: ./docker/build/solr-init args: BASE_IMAGE: ${SITECORE_DOCKER_REGISTRY}sitecore-xm1-solr-init:${SITECORE_VERSION} ``` To ensure the above configuration changes not impacting to anything we confirm by running the below command. ``` .\init.ps1 -LicenseXmlPath "" docker-compose up -d ``` The upcoming blog post will guide you on integrating Sitecore custom modules into our website, and demonstrate how to build a solution and deploy the changes from our solution to the containerized site. ### Building a Sitecore Solution from Scratch with Docker: Part 1 URL: https://www.gowthamaraja.com/sitecore-docker-solution-building-from-scratch-part-1/ Last updated: 2025-11-17T10:47:02.000Z As I began to learn Sitecore Docker, I utilized the Sitecore Custom Images Docker for customization. However, I often found myself pondering on how to build a Sitecore Docker solution from scratch. Despite scouring various online resources for information on this topic, I found that the information provided was insufficient or lacked detail. As a result, I decided to conduct a more in-depth investigation and share my findings through a blog series. This series of blog posts will guide you through the process of creating a Sitecore Docker solution from scratch and provide you with a comprehensive understanding of the steps involved. To clarify, when I mention starting from scratch, I won't be providing instructions on how to set up your instance for installing Docker or preparing your local instance for Sitecore Docker. There are already plenty of resources available on the internet for these steps and the official one you can find it [here](https://doc.sitecore.com/xp/en/developers/101/developer-tools/set-up-the-environment.html?ref=gowthamaraja.com). Let's get started by cloning the [docker-examples](https://github.com/Sitecore/docker-examples?ref=gowthamaraja.com) git repository from Sitecore and using the "getting-started" template to install a vanilla instance of Sitecore. I'm creating a folder named SitecoreDocker and transferring the files from the getting-started folder, which is the folder we originally cloned from. ![getting-started-files](https://static.wixstatic.com/media/14fd51_3cc594c2cccf4515b99c5d974340c251~mv2.png/v1/fill/w_644,h_213,al_c,q_85,enc_avif,quality_auto/14fd51_3cc594c2cccf4515b99c5d974340c251~mv2.png) These are the files for the Sitecore Getting Started template. Please make sure to check that none of your resources are currently using the ports listed in this document and also ensure that IIS on your local machine is stopped before we begin. Open PowerShell and go to the SitecoreDocker folder. Then, execute the following command. `.\init.ps1 -LicenseXmlPath ""` The command above will fill in the variables in the .env file with their respective values. ![init_ps1](https://static.wixstatic.com/media/14fd51_29dd1bdff4cc4a5b91602d10eed27e72~mv2.png/v1/fill/w_740,h_416,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_29dd1bdff4cc4a5b91602d10eed27e72~mv2.png) Running the .\\init.ps1 -LicenseXmlPath C:\\License\\license.xml If the above command has executed successfully, it's time to start the Docker instance. Run the following command in your terminal window. `docker-compose up -d` Please note that the command above may take a while to download and start the instance, depending on your network speed and system resources. Once it's complete, you can view the Sitecore XP0 instance by browsing to this URL: [https://xp0cm.localhost/sitecore](https://xp0cm.localhost/sitecore?ref=gowthamaraja.com) ![xp0-website](https://static.wixstatic.com/media/14fd51_819789148cad437f8a551d029db7f73a~mv2.png/v1/fill/w_740,h_405,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_819789148cad437f8a551d029db7f73a~mv2.png) xp0-website In our next blog, I'll guide you through modifying the folder structure in accordance with Sitecore's recommended practices, as well as adding modules such as SXA and SPE to the basic Sitecore instance. ### Fixing Sitecore Publishing Service's Indexing Issue URL: https://www.gowthamaraja.com/sitecore-publishing-service-indexing-issue-fix/ Last updated: 2025-11-17T10:44:08.000Z If you're experiencing long wait times for indexing when publishing via the Sitecore Publishing Service, especially when publishing a large number of items (about 1000 to 1500), this could be caused by the Sitecore Web Index being frequently triggered. When this occurs, the entire index initiates, and content dependent on Solr may not be displayed until indexing is complete. To resolve the issue, I conducted an investigation and found that the default *remoteEventCacheClearingThreshold* parameter in the publishEndResultBatch pipeline was causing the problem. This parameter is set to 1,000 items, and if the pipeline publishes more than 1,000 items in a single operation, a separate event is triggered causing a complete index rebuild, leading to significant delays in Content Search updates for large sites, requiring several hours to rebuild search indexes. To address this issue, I updated the *remoteEventCacheClearingThreshold* parameter to 15,000 based on specific requirements. Although there is no recommended optimal value for this parameter, it should be updated as per your requirements to ensure smooth indexing. I have provided a patch file that includes the updated parameter value to help you fix the issue. You can download the patch file and use it to update the parameter value as needed. This should help reduce the lengthy wait times for indexing and improve the overall performance of your Sitecore environment. ``` 15000 ``` I hope this information helps you resolve the Sitecore Publishing Service issue causing a lengthy wait for indexing. If you have any questions or require further assistance, please don't hesitate to contact me. Reference: [https://mikael.com/2019/07/learnings-from-a-year-of-implementing-sitecore-publishing-service/](https://mikael.com/2019/07/learnings-from-a-year-of-implementing-sitecore-publishing-service/?ref=gowthamaraja.com) ### Sitecore OrderCloud Headstart Installation Guide – Part 7 URL: https://www.gowthamaraja.com/install-sitecore-headstart-part7/ Last updated: 2025-11-17T10:42:30.000Z Getting Started with Sitecore OrderCloud Headstart: A Local Installation Guide Series This blog post will guide you through the process of setting up and running the Buyer UI Application. The steps are similar to running the Seller UI application, with just a few changes. - Go to the src\\UI\\Buyer\\src\\environments\\environment.local.ts file. - Update the necessary values in the file. ```const const useLocalMiddleware = true const useLocalBuyerApiClient = true // set to true for running integration events locally const localMiddlewareURL = 'Your_Local_Middleware_URL' ``` - Save the file - Go to the src\\UI\\Buyer\\src\\assets\\appConfigs\\defaultbuyer-test.json - Update the necessary values in the file ``` "clientID":"Buyer_Client_Id_From_Seed_Response", "baseUrl":"http://localhost:4200", "middlewareUrl":"https://localhost:5001", "translateBlobUrl":"http://127.0.0.1:10000/devstoreaccount1/ngx-translate/i18n/", "marketplaceID":"Your_MarketPlace_ID", "marketplaceName":"Your_MarketPlace_Name", "orderCloudApiUrl":"Your_Sandbox_URL", ``` - Save the file - Navigate to src\\UI\\Buyer\\ from Visual Studio Terminal - After navigating to the buyer application directory, run the below command in the terminal window to install the necessary dependencies for the Buyer UI Application ``` npm install ``` - Some might encounter the below error while running the above command ![buyer-ui-application-npm-error](https://static.wixstatic.com/media/14fd51_6d4b3970843d4aeeb8a485c1373538da~mv2.png/v1/fill/w_740,h_365,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_6d4b3970843d4aeeb8a485c1373538da~mv2.png) - To resolve this run the below command which resolves the issue ``` npm config set legacy-peer-deps true ``` - Then clean the cache and run npm install ``` npm cache clean --force npm install ``` - Now you’ll able to install the dependencies without any issue - On successful installation use npm run start to start the Buyer UI application - The Buyer UI Application will start and it launches on the browser ![buyer-ui-application](https://static.wixstatic.com/media/14fd51_def5338c37874899bbca07cabcbecee8~mv2.png/v1/fill/w_740,h_403,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_def5338c37874899bbca07cabcbecee8~mv2.png) The installation of OrderCloud Headstart application has been successfully completed on the local environment. Now, you can explore and experiment with the solution. Have fun Sitecoring! ### References [https://thedebugdude.com/category/ordercloud-headstart/](https://thedebugdude.com/category/ordercloud-headstart/?ref=gowthamaraja.com) [https://sandeeppote.com/2022/04/11/setup-sitecore-ordercloud-headstart-project-series/](https://sandeeppote.com/2022/04/11/setup-sitecore-ordercloud-headstart-project-series/?ref=gowthamaraja.com) ### Sitecore OrderCloud Headstart Installation Guide – Part 6 URL: https://www.gowthamaraja.com/install-sitecore-headstart-part6/ Last updated: 2025-11-17T10:41:46.000Z In this blog we’ll be focusing on setting up the necessary settings for running the Seller UI Application. - Go to the src\\UI\\Seller\\src\\assets\\appConfigs\\defaultadmin-test.json file. - Update the necessary values in the file. ``` { "hostedApp":true, "marketplaceID":"Your_MarketPlace_ID", "marketplaceName":"Your_MarketPlace_Name", "appname":"Your_MarketPlace_Name", "clientID":"Seller_Client_ID_from_Seed_Response", "middlewareUrl":"https://my-hosted-middleware.com", "translateBlobUrl":"http://127.0.0.1:10000/devstoreaccount1/ngx-translate/i18n/", "supportedLanguages":[ "en", "fr", "jp" ], "defaultLanguage":"en", "blobStorageUrl":"http://127.0.0.1:10000/devstoreaccount1", "orderCloudApiUrl":"Your_Sandbox_URL" } ``` ## Running the Seller UI Application - Open Visual Studio Code - From the terminal navigate to src\\ui\\Seller - Run the below command to install the dependencies of the project `npm install` - Run the following command in the terminal to start the seller application after all dependencies have been successfully installed `npm run start` - After running the previous command, wait for a few minutes. - The browser will open with the Seller UI login page. ![running-the-seller-ui-application](https://static.wixstatic.com/media/14fd51_611d98d88c4949c2b17ef5672a71fc1a~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_611d98d88c4949c2b17ef5672a71fc1a~mv2.png) - Use the Initial Admin username and password obtained from the Seed request to log in to the Seller UI. - Upon successful login, you will be redirected to the Seller Admin page. ![logging-in-the-seller-ui-application](https://static.wixstatic.com/media/14fd51_8677ad912bce4ff0a2647e2985647f16~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_8677ad912bce4ff0a2647e2985647f16~mv2.png) On our next blog we will be guiding you through the setup and execution of the Buyer UI application. ### Sitecore OrderCloud Headstart Installation Guide – Part 5 URL: https://www.gowthamaraja.com/install-sitecore-headstart-part5/ Last updated: 2025-11-17T10:41:10.000Z In our previous blog, we set up and configured the Middleware Project locally. In this blog, we will cover seeding our OrderCloud data and installing the dependencies for the Buyer and Seller app. ## Seeding the OrderCloud data - Prior to launching the Buyer and Seller application, it is essential to configure additional data. - The Seed API must be seeded to start the marketplace data needed for the Buyer and Seller App - Open the Swagger UI in your web browser (as described in our previous blog) - Expand the “EnvironmentSeed” section - Select the “Seed” request ![seeding-the-orderclud](https://static.wixstatic.com/media/14fd51_8d50396eaa814ff6ac0dfe1a4489896f~mv2.png/v1/fill/w_740,h_443,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_8d50396eaa814ff6ac0dfe1a4489896f~mv2.png) - Update the request body by clicking the “Try it out” button ``` { "Portal":{ "Username":"Desired_User_Name", "Password":"Desired_Password" }, "Marketplace":{ "Environment":"Sandbox", "Region":"Get_it_from_OrderCloud_Sandbox", "ID":"MarketPlace_Identifier", "Name":"MarketPlace_Name", "InitialAdmin":{ "Password":"Desired_Password_For_MarketPlace", "Username":"Desired_UserName_For_MarketPlace" }, "EnableAnonymousShopping":true, "MiddlewareBaseUrl":"Leave_it_as_blank", "WebhookHashKey":"Random_HashKey" } } ``` - Send the request - Wait for the request to complete (approximately 1 minute) - On successful completion, you will receive the following response ![ordercloud-seeding-response](https://static.wixstatic.com/media/14fd51_c3c1d59a377e4fecb9b253c3071dffaf~mv2.png/v1/fill/w_740,h_366,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_c3c1d59a377e4fecb9b253c3071dffaf~mv2.png) - Copy the required values from the response to fill in the appSettings.json file ``` "OrderCloudSettings:MiddlewareClientID":"{Middleware Client Id}", "OrderCloudSettings:MiddlewareClientSecret":"{Middleware Client Secret}", "OrderCloudSettings:ClientIDsWithAPIAccess":"{Buyer Client Id},{Sellet Client Id}" ``` - Check the API console by sending a GET request to “GET\\adminusers”. - This will display the list of Admin users and other required details in your marketplace. Remembering the Initial Admin Credentials - After verifying the API seeding results, take note of the Initial Admin Username and Password. - These credentials will be required in later steps of the software installation process. ## Installing and Building the Headstart SDK ## In order to run both the Buyer and Seller applications, a shared SDK is necessary. The SDK, located in the “src/UI/SDK” directory of the codebase, is used to communicate with the Middleware API. Before you can run the Buyer or Seller apps, you must first install the dependencies and build the SDK project. This is an important step in the installation process, as the SDK is a crucial component for proper functioning of the applications. - Open the Headstart codebase in Visual Studio Code - Open the terminal window in Visual Studio Code. - In the terminal window, navigate to the SDK directory in “src/UI/SDK”. - Run the command to install the necessary dependencies. npm install - Once the dependencies have been installed, run the command to build the SDK project. npm run build We’ve made significant progress in setting up the environment and installing necessary dependencies for our OrderCloud local setup. This includes seeding the environment and building the Headstart SDK. In our next blog, we’ll take the next step by setting up the necessary settings to run the Seller UI Application. ### Sitecore OrderCloud Headstart Installation Guide – Part 4 URL: https://www.gowthamaraja.com/install-sitecore-headstart-part4/ Last updated: 2025-11-17T10:40:31.000Z In this guide (Part 4), you will learn how to set up and configure the Middleware Project locally. The steps and instructions provided will help you successfully complete the installation process and run middleware on your local machine. The Middleware Project acts as a connector between the Buyer/Seller and the OrderCloud API. In Part 1, we cloned the Headstart repository from Sitecore Github. Now, in order to continue the installation process, we need to open the Headstart.sln file from the cloned repository. To do this, follow these steps: - Navigate to the location where the Headstart repository was cloned in Part 1. - Locate the Headstart.sln file. - Right-click on the file and select “Open” or “Open with Visual Studio”. - Visual Studio will open and load the Headstart solution. - Build the solution to restore all the nuget packages - Upon the successful build create appSettings.json on root of Headstart.API project ![appsettings_json](https://static.wixstatic.com/media/14fd51_f1ec444a62c9483b825d343544fb1ce7~mv2.png/v1/fill/w_350,h_322,al_c,lg_1,q_85,enc_avif,quality_auto/14fd51_f1ec444a62c9483b825d343544fb1ce7~mv2.png) - Copy the contents of AppSettingConfigTemplate.json which is located in “assets\\templates\\AppSettingConfigTemplate.json” - Fill in the required values in the appSettings.json file using the information obtained from the provided steps ## Getting OrderCloud Marketplace Name and ID - Create a new Marketplace in your OrderCloud environment - Obtain the OrderCloud Marketplace name and ID - Detailed steps for creating Marketplace can be found on the [official site](https://ordercloud.io/learn/getting-started/creating-your-first-marketplace?ref=gowthamaraja.com) ![ordercloud-marketplace-name-and-id](https://static.wixstatic.com/media/14fd51_07b538aed5b64df4ac1680f9c3e07ce4~mv2.png/v1/fill/w_740,h_342,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_07b538aed5b64df4ac1680f9c3e07ce4~mv2.png) - Use the Unique Identifier and Marketplace Name to update the below settings in appSettings.json `"OrderCloudSettings:MarketplaceID": "0spWGNkxDcIK5Msz", "OrderCloudSettings:MarketplaceName": "Headstart",` ## Getting Storage Account Connection String - Launch Azure Storage Explorer. - Navigate to the “local-1” blob container. - In the bottom left side of the pane, locate the “Primary Connection String”. - Copy the “Primary Connection String” to your clipboard. - If the properties are not visible, right-click on “local-1” and select “Properties”. ![primary-connection-string](https://static.wixstatic.com/media/14fd51_988d2e9da88a459ba05245cd3a550f62~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_988d2e9da88a459ba05245cd3a550f62~mv2.png) - Open the appSettings.json file in a text editor. - Locate the section in the file where the connection string is stored. - Replace the existing connection string with the one you copied from Azure Storage Explorer. - Save the appSettings.json file. `"StorageAccountSettings:ConnectionString": "{YourConnectionString}", "StorageAccountSettings:BlobPrimaryEndpoint": "{YourBlobPrimaryEndpoint}",` ## Starting the Middleware application - Open Visual Studio and Load the Headstart.sln solution - Right-click on the Headstart.API project - Select “Properties” from the context menu - Navigate to the “Debug” tab - Click on the “Open debug launch profiles UI” button - In the Launch Profile popup, select “Create New Profile” - Choose “Project” as the type for the new profile ![starting-the-middleware-application](https://static.wixstatic.com/media/14fd51_2777033991b240a89c44ee32cc66e8be~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_2777033991b240a89c44ee32cc66e8be~mv2.png) - Name the new profile “Headstart Demo” and close the popup - Select the “Headstart Demo” debug profile from the list - Click the “Run” button to start the Headstart.API project ![run-the-middleware-application](https://static.wixstatic.com/media/14fd51_f91fc1e7875446f59201084791dba329~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_f91fc1e7875446f59201084791dba329~mv2.png) - If the configurations are properly set up, a Command Prompt will start and listen on ports 25719 and 25720 ![verifying-the-middleware-application](https://static.wixstatic.com/media/14fd51_3581d830a974479999d8ba6ac434ecd0~mv2.png/v1/fill/w_740,h_387,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_3581d830a974479999d8ba6ac434ecd0~mv2.png) - This will launch the Swagger UI in your web browser, displaying the list of OrderCloud APIs ![swagger-for-ordercloud-application](https://static.wixstatic.com/media/14fd51_3a81f6dfd2d8465e8adebd6418fda48d~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_3a81f6dfd2d8465e8adebd6418fda48d~mv2.png) In this blog, we have successfully run the Headstart.API project. In our next blog, we will seed our OrderCloud data and install the dependencies for the Buyer and Seller Apps. ### Sitecore OrderCloud Headstart Installation Guide – Part 1 URL: https://www.gowthamaraja.com/install-sitecore-headstart-part1/ Last updated: 2025-11-17T10:37:51.000Z Sitecore OrderCloud Headstart is a game-changing e-commerce solution that streamlines the online sales process for businesses. In this series of guides, we’ll take you through the steps of getting started with a local installation of Sitecore OrderCloud Headstart. Clone the OrderCloud Headstart project from [official site](https://github.com/ordercloud-api/headstart?ref=gowthamaraja.com) ## Prerequisites - Node JS - Angular CLI - Azurite - Azure Storage Explorer - Azure Cosmos DB Emulator ## Step 1: Installing Node.js - Download the latest version of Node.js from the official website. - Install it using the default configuration. ## Step 2: Installing Angular CLI - Open PowerShell in administrator mode. - Run the following command to install Angular globally `npm install -g @angular/cli` ## Step 3: Installing Azurite - Azurite emulator provides a free local environment for testing Azure Blob. - Open PowerShell in administrator mode. - Run the following command to install the Azurite Command Line tool `npm install -g azurite` ## Step 4: Installing Azure Storage Explorer - Download Azure Storage Explorer from the official website. - Once the installation is complete, run the Microsoft Azure Storage Explorer from the start menu. ## Step 5: Installing Azure Cosmos DB Emulator - Download the Azure Cosmos DB Emulator from the official website. - Once the installation is complete, access the following URL to open the Cosmos DB Emulator: https://localhost:8081/\_explorer/index.html - You may encounter a privacy error related to the TLS certificate but this is not an issue when accessing the URL from the Edge browser. - If you encounter the “Site can’t be reached” page, run the Azure Cosmos DB Emulator application. ## Step 6: Azurite Setup and Initializing Blob Storage Container using Azure Storage Explorer - Create a new folder called “Azurite” on your C drive (C:\\Azurite). - Open PowerShell in administrator mode and switch the directory to C:\\Azurite. - Run the following command to run Azurite azurite start - On successful execution, you will see the following output ![azurite-blob-service](https://static.wixstatic.com/media/14fd51_e48c59f457dd4cb5866485ebdc5a0dc4~mv2.png/v1/fill/w_740,h_145,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_e48c59f457dd4cb5866485ebdc5a0dc4~mv2.png) Note: Make sure you do not close the PowerShell, otherwise you will not be able to connect to the emulator. ### Sitecore OrderCloud Headstart Installation Guide - Part 3 URL: https://www.gowthamaraja.com/install-sitecore-headstart-part3/ Last updated: 2025-11-17T10:37:25.000Z This blog will guide you through the process of creating a blob storage container and uploading the translation file needed by both the Buyer and Seller UI Applications. - Right-click on the Blob Containers of the Local Storage account created in the previous part and select “Create Blob Container.” - Name the container “ngx-translate”. ![create-blob-container](https://static.wixstatic.com/media/14fd51_b22e1921ac3642bebd398ac1d9917863~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_b22e1921ac3642bebd398ac1d9917863~mv2.png) - Create a virtual directory “i18n” by clicking “New Folder”. ![create-virtual-directory](https://static.wixstatic.com/media/14fd51_5238a02e3ae84cfc8e98908d836b9e26~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_5238a02e3ae84cfc8e98908d836b9e26~mv2.png) - Upload the translation file (en.json) located at “src\\Middleware\\src\\Headstart.API\\wwwroot\\i18n\\en.json”. ![upload-translation-file](https://static.wixstatic.com/media/14fd51_fe9bb7ac7e5b453bb86a09dbdb41d8f2~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_fe9bb7ac7e5b453bb86a09dbdb41d8f2~mv2.png) - Update the CORS settings to avoid Authorization Failure error. - Set the container to public access by right-clicking on the “ngx-translate” blob container and selecting “Set Public Access Level.” ![set-public-access-level](https://static.wixstatic.com/media/14fd51_6dc3624732bc4b5fb3ee7a622f847601~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_6dc3624732bc4b5fb3ee7a622f847601~mv2.png) - In the pop-up, select “Public read access for container and blobs” and click “Apply”. ![public-read-access-for-container-and-blobs](https://static.wixstatic.com/media/14fd51_e31321088387406a9a7f4ed860e5d9cb~mv2.png/v1/fill/w_583,h_436,al_c,lg_1,q_85,enc_avif,quality_auto/14fd51_e31321088387406a9a7f4ed860e5d9cb~mv2.png) - Right-click on the “Blob Containers” in the left pane of Azure Storage Explorer and select “Configure CORS Settings.” ![configure-cors-settings](https://static.wixstatic.com/media/14fd51_1e95f28e93ac4c8293de68f3fce15bcc~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_1e95f28e93ac4c8293de68f3fce15bcc~mv2.png) - In the pop-up, click “Add” to add the CORS setting values. ![add-cors-settings](https://static.wixstatic.com/media/14fd51_c073b409588f4802969cf7cac992d6fa~mv2.png/v1/fill/w_740,h_559,al_c,lg_1,q_90,enc_avif,quality_auto/14fd51_c073b409588f4802969cf7cac992d6fa~mv2.png) - Add the following values to the CORS rule: - Allowed Origins: http://localhost:4200 - Allowed Headers: x-ms-meta-data,x-ms-meta-target,x-ms-meta-abc - Exposed Headers: x-ms-meta-data,x-ms-meta-target,x-ms-meta-abc - Click “Save” to save the newly added CORS rule. ![add-cors-rule](https://static.wixstatic.com/media/14fd51_4734c48a59ad44bba9304ff7f12c3853~mv2.png/v1/fill/w_740,h_559,al_c,lg_1,q_90,enc_avif,quality_auto/14fd51_4734c48a59ad44bba9304ff7f12c3853~mv2.png) - Confirm that the newly added CORS Rule is added on the next window and click on “Save” to save your CORS settings ![cors-setting](https://static.wixstatic.com/media/14fd51_7f06fa2f92a7471397c8c2f4ed82f193~mv2.png/v1/fill/w_740,h_559,al_c,lg_1,q_90,enc_avif,quality_auto/14fd51_7f06fa2f92a7471397c8c2f4ed82f193~mv2.png) - Confirm that the CORS settings were saved by accessing the URL in a browser: [http://127.0.0.1:10000/devstoreaccount1/ngx-translat/i18n/en.json](http://127.0.0.1:10000/devstoreaccount1/ngx-translat/i18n/en.json?ref=gowthamaraja.com) ![cors-verification](https://static.wixstatic.com/media/14fd51_89c7e22b5df547109a2bbabd7e5c88e7~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_89c7e22b5df547109a2bbabd7e5c88e7~mv2.png) - To access the URL, right-click on the “en.json” file in Azure Storage Explorer and click “Copy URL” - Open the copied URL in a browser to confirm the CORS settings and validate the steps performed. ![cors-url](https://static.wixstatic.com/media/14fd51_602c54621ba642e889dfab33b7afe1f5~mv2.webp/v1/fill/w_740,h_403,al_c,q_80,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_602c54621ba642e889dfab33b7afe1f5~mv2.webp) We have finished setting up the blob storage container, uploading the translation file, and configuring CORS settings for the local installation of Sitecore Order Cloud. ### Sitecore OrderCloud Headstart Installation Guide – Part 2 URL: https://www.gowthamaraja.com/install-sitecore-headstart-part2/ Last updated: 2025-11-17T10:35:07.000Z In the following section, we will walk through the steps necessary to configure Azure Storage Explorer in preparation for subsequent procedures. Setting up the Azure Storage Explorer - Launch Azure Storage Explorer on your system - Find the “Open Connect” option on the left pane and click on it - A pop-up window will appear, offering multiple options for connecting to a resource. Select the “Local Storage Emulator” option to proceed ![azure-storage-explorer](https://static.wixstatic.com/media/14fd51_b68d7cfae3364702abdf982cc2f1defd~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_b68d7cfae3364702abdf982cc2f1defd~mv2.png) - Click on “Next” and no changes are necessary in the default settings ![connect-to-azure-storage](https://static.wixstatic.com/media/14fd51_a7c789ae04034d5397152e6914047962~mv2.png/v1/fill/w_740,h_560,al_c,q_90,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_a7c789ae04034d5397152e6914047962~mv2.png) - Open the settings window - Observe the settings used to connect to the Blob Endpoint - Click on the “Connect” button - Establish connection to the local Blob ![connect-to-azure-storage-2](https://static.wixstatic.com/media/14fd51_f28c3766f3784fb0be85e7d007be0b08~mv2.png/v1/fill/w_740,h_560,al_c,q_90,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_f28c3766f3784fb0be85e7d007be0b08~mv2.png) - Verify successful connection with display of local Blob in left pane of Azure Storage Explorer ![azure-storage-explorer-2](https://static.wixstatic.com/media/14fd51_b22e1921ac3642bebd398ac1d9917863~mv2.png/v1/fill/w_740,h_404,al_c,q_85,usm_0.66_1.00_0.01,enc_avif,quality_auto/14fd51_b22e1921ac3642bebd398ac1d9917863~mv2.png) The next step in the process will be to prepare Azure Storage Explorer to serve the necessary data (Translating File) to the OrderCloud service, which will be covered in the following blog. ### Sitecore Order Cloud: A Comprehensive Guide URL: https://www.gowthamaraja.com/sitecore-order-cloud/ Last updated: 2025-11-18T18:47:27.000Z As a business, the ability to manage and fulfill orders efficiently is crucial to success. With the growing demands of online commerce, the need for an efficient and reliable order management system has never been greater. Sitecore Order Cloud is a comprehensive solution designed to meet the needs of businesses of all sizes and industries. In this article, we'll take a deep dive into the features and benefits of Sitecore Order Cloud and explore why it's the best choice for your business. ## What is Sitecore OrderCloud? Sitecore Order Cloud is a cloud-based order management system that integrates with your existing Sitecore platform. This integration allows for seamless transfer of customer data and order information, resulting in a more efficient and streamlined process. Sitecore Order Cloud is designed to handle the entire order life cycle, from the initial order to final delivery and post-sale support. ## Key Features of Sitecore Order Cloud Sitecore Order Cloud comes packed with a range of features to help you manage your orders with ease. Some of the key features include: ### **Multi-Channel Integration** Sitecore Order Cloud allows for integration with multiple channels, including eCommerce websites, brick-and-mortar stores, and call centers. This means that you can manage all of your orders from a single platform, regardless of where they originate. ### **Real-Time Inventory Management** Sitecore Order Cloud provides real-time inventory management, allowing you to monitor stock levels in real-time. This means that you can make informed decisions about which products to stock and when, helping you avoid overstocking or running out of stock. ### **Order Processing and Fulfillment** Sitecore Order Cloud streamlines the order processing and fulfillment process, reducing the time and resources needed to manage orders. With automated processes and real-time tracking, you can ensure that orders are fulfilled efficiently and accurately. ### **Customer Management** Sitecore Order Cloud provides a centralized view of all customer information, allowing you to manage customer relationships more effectively. You can easily track customer behavior, preferences, and orders, providing you with the data you need to make informed decisions about your business. ## Benefits of Sitecore Order Cloud Sitecore Order Cloud provides a range of benefits for businesses of all sizes and industries. Some of the key benefits include: ### **Increased Efficiency** Sitecore Order Cloud streamlines the order management process, reducing the time and resources needed to manage orders. This increased efficiency means that you can focus on other areas of your business, such as growth and expansion. ### **Improved Customer Experience** Sitecore Order Cloud provides a seamless experience for customers, reducing the likelihood of errors and ensuring that orders are fulfilled efficiently. This improved experience can lead to increased customer loyalty and higher customer satisfaction. ### **Real-Time Data and Insights** Sitecore Order Cloud provides real-time data and insights into your business, allowing you to make informed decisions about your operations. This data and insights can help you identify areas of your business that need improvement and make data-driven decisions. ### **Scalability** Sitecore Order Cloud is a cloud-based solution, which means that it can be scaled to meet the needs of businesses of all sizes. Whether you're a small start-up or a large enterprise, Sitecore Order Cloud provides the flexibility and scalability you need to grow your business. Sitecore Order Cloud is a comprehensive order management solution that provides a range of features and benefits for businesses of all sizes and industries. With its multi-channel integration, real-time inventory management, and improved customer experience.