<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://waitingimpatiently.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://waitingimpatiently.com/" rel="alternate" type="text/html" /><updated>2026-06-15T13:39:05+00:00</updated><id>https://waitingimpatiently.com/feed.xml</id><title type="html">Waiting Impatiently</title><subtitle>Six Time Sitecore MVP 2017-2022 Marketing Technologist.</subtitle><author><name>Chris Auer</name></author><entry><title type="html">Are Your Salesforce Admins Ready for Phishing-Resistant MFA?</title><link href="https://waitingimpatiently.com/are-your-admins-ready-for-phishing-resistant-mfa/" rel="alternate" type="text/html" title="Are Your Salesforce Admins Ready for Phishing-Resistant MFA?" /><published>2026-06-12T00:00:00+00:00</published><updated>2026-06-12T00:00:00+00:00</updated><id>https://waitingimpatiently.com/are-your-admins-ready-for-phishing-resistant-mfa</id><content type="html" xml:base="https://waitingimpatiently.com/are-your-admins-ready-for-phishing-resistant-mfa/"><![CDATA[<p>Salesforce’s July 2026 enforcement deadline is approaching fast: admins and privileged users will be required to use <strong>phishing-resistant MFA</strong> — not just any second factor. A YubiKey or a platform authenticator like Windows Hello or Touch ID qualifies. A Salesforce Authenticator push notification or a TOTP code from Google Authenticator does not.</p>

<p>If you haven’t audited your org yet, here’s exactly how to do it.</p>

<h2 id="what-counts-as-phishing-resistant">What counts as phishing-resistant?</h2>

<p>Salesforce tracks two phishing-resistant methods:</p>

<ul>
  <li><strong><code class="language-plaintext highlighter-rouge">HasSecurityKey = true</code></strong> — a registered WebAuthn security key. This includes hardware keys (YubiKey, etc.) as well as synced passkeys from iCloud Keychain, 1Password, or Bitwarden, as long as the manager is FIDO2/WebAuthn-compliant.</li>
  <li><strong><code class="language-plaintext highlighter-rouge">HasBuiltInAuthenticator = true</code></strong> — a registered platform authenticator (Windows Hello, Touch ID, or Face ID bound to that device).</li>
</ul>

<p>Standard MFA methods — <code class="language-plaintext highlighter-rouge">HasSalesforceAuthenticator</code> and <code class="language-plaintext highlighter-rouge">HasTotp</code> — do not satisfy the phishing-resistant requirement and will trigger a step-up prompt at login after the enforcement date.</p>

<h2 id="step-1-create-the-mfa-api-access-permission-set">Step 1: Create the “MFA API Access” permission set</h2>

<p>The <code class="language-plaintext highlighter-rouge">TwoFactorMethodsInfo</code> object requires elevated permissions to query. Create a permission set that grants them.</p>

<ol>
  <li>Go to <strong>Setup → Permission Sets → New</strong></li>
  <li>Name it <strong>MFA API Access</strong>, leave the license blank</li>
  <li>Open <strong>System Permissions</strong></li>
  <li>Enable <strong>Manage MFA in API</strong> and <strong>Manage MFA in User Interface</strong></li>
  <li>Save, then assign the permission set to your user via <strong>Manage Assignments</strong></li>
</ol>

<p>Without this, the SOQL query below will return a <code class="language-plaintext highlighter-rouge">INSUFFICIENT_ACCESS</code> error.</p>

<h2 id="step-2-run-the-audit-query">Step 2: Run the audit query</h2>

<p>Open the <strong>Developer Console</strong> or use <strong>Workbench</strong> and run:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="k">User</span><span class="p">.</span><span class="n">Username</span><span class="p">,</span> <span class="k">User</span><span class="p">.</span><span class="n">Profile</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
       <span class="n">HasBuiltInAuthenticator</span><span class="p">,</span> <span class="n">HasSecurityKey</span><span class="p">,</span> <span class="n">HasU2F</span><span class="p">,</span>
       <span class="n">HasSalesforceAuthenticator</span><span class="p">,</span> <span class="n">HasTotp</span>
<span class="k">FROM</span> <span class="n">TwoFactorMethodsInfo</span>
<span class="k">WHERE</span> <span class="k">User</span><span class="p">.</span><span class="n">IsActive</span> <span class="o">=</span> <span class="k">true</span>
</code></pre></div></div>

<p>This gives you a row per active user who has registered at least one verification method, showing exactly which factors each person has in place.</p>

<h2 id="step-3-find-who-isnt-ready">Step 3: Find who isn’t ready</h2>

<p>Narrow the results to users who have no phishing-resistant method registered:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="k">User</span><span class="p">.</span><span class="n">Username</span><span class="p">,</span> <span class="k">User</span><span class="p">.</span><span class="n">Profile</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
       <span class="n">HasBuiltInAuthenticator</span><span class="p">,</span> <span class="n">HasSecurityKey</span><span class="p">,</span> <span class="n">HasU2F</span><span class="p">,</span>
       <span class="n">HasSalesforceAuthenticator</span><span class="p">,</span> <span class="n">HasTotp</span>
<span class="k">FROM</span> <span class="n">TwoFactorMethodsInfo</span>
<span class="k">WHERE</span> <span class="k">User</span><span class="p">.</span><span class="n">IsActive</span> <span class="o">=</span> <span class="k">true</span>
  <span class="k">AND</span> <span class="n">HasBuiltInAuthenticator</span> <span class="o">=</span> <span class="k">false</span>
  <span class="k">AND</span> <span class="n">HasSecurityKey</span> <span class="o">=</span> <span class="k">false</span>
</code></pre></div></div>

<p>Anyone returned here would hit the step-up wall after July enforcement. Tighten the scope to the highest-risk profiles:</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="k">User</span><span class="p">.</span><span class="n">Username</span><span class="p">,</span> <span class="k">User</span><span class="p">.</span><span class="n">Profile</span><span class="p">.</span><span class="n">Name</span><span class="p">,</span>
       <span class="n">HasBuiltInAuthenticator</span><span class="p">,</span> <span class="n">HasSecurityKey</span><span class="p">,</span> <span class="n">HasU2F</span><span class="p">,</span>
       <span class="n">HasSalesforceAuthenticator</span><span class="p">,</span> <span class="n">HasTotp</span>
<span class="k">FROM</span> <span class="n">TwoFactorMethodsInfo</span>
<span class="k">WHERE</span> <span class="k">User</span><span class="p">.</span><span class="n">IsActive</span> <span class="o">=</span> <span class="k">true</span>
  <span class="k">AND</span> <span class="n">HasBuiltInAuthenticator</span> <span class="o">=</span> <span class="k">false</span>
  <span class="k">AND</span> <span class="n">HasSecurityKey</span> <span class="o">=</span> <span class="k">false</span>
  <span class="k">AND</span> <span class="k">User</span><span class="p">.</span><span class="n">Profile</span><span class="p">.</span><span class="n">Name</span> <span class="o">=</span> <span class="s1">'System Administrator'</span>
</code></pre></div></div>

<p>To focus on admins specifically, cross-reference the results against a User query filtered by <code class="language-plaintext highlighter-rouge">Profile.Name = 'System Administrator'</code>. Do the same for any profiles or permission sets granting Modify All Data or Manage Users — those users carry the same risk as sysadmins.</p>

<h2 id="two-caveats-you-need-to-know">Two caveats you need to know</h2>

<p><strong>Users with zero methods won’t appear.</strong> A row only exists in <code class="language-plaintext highlighter-rouge">TwoFactorMethodsInfo</code> once a user has registered <em>something</em>. Users who have never set up any MFA at all are silently absent. Cross-check your query results against a full active-admin list (<code class="language-plaintext highlighter-rouge">SELECT Username FROM User WHERE IsActive = true AND Profile.Name = 'System Administrator'</code>) to catch anyone missing entirely.</p>

<p><strong>Legacy U2F is a gray area.</strong> <code class="language-plaintext highlighter-rouge">HasU2F</code> (flagging keys registered under the old FIDO U2F protocol) is tracked separately from <code class="language-plaintext highlighter-rouge">HasSecurityKey</code> (WebAuthn). If anyone has a legacy U2F registration, it’s safer to have them re-register under WebAuthn rather than assume Salesforce will honor it toward the phishing-resistant requirement. Hardware keys like YubiKeys support both; the re-registration takes about a minute.</p>

<h2 id="what-to-do-with-the-results">What to do with the results</h2>

<p>Once you have your at-risk list:</p>

<ol>
  <li><strong>Choose a method for each user.</strong> Platform authenticators (Windows Hello, Touch ID) are zero-cost and built into devices most admins already use. Hardware keys are the better fit for shared workstations or users who move between machines.</li>
  <li><strong>Have users register before the deadline.</strong> Walk them through <strong>Setup → Advanced User Details → Register</strong> under the Security Key or Built-In Authenticator section.</li>
  <li><strong>Re-run the audit query</strong> after registration to confirm <code class="language-plaintext highlighter-rouge">HasSecurityKey</code> or <code class="language-plaintext highlighter-rouge">HasBuiltInAuthenticator</code> flipped to <code class="language-plaintext highlighter-rouge">true</code>.</li>
  <li><strong>Don’t forget service/API users.</strong> Automated integrations authenticating as admin users need certificate-based or OAuth flows that don’t require interactive MFA — make sure those are in place before enforcement hits.</li>
</ol>

<p>The query takes two minutes to run. The harder part is the follow-up with users who’ve been putting off the upgrade. Give them a specific deadline a week before Salesforce’s, so you have buffer to resolve stragglers before the forced step-up affects production access.</p>]]></content><author><name>Chris Auer</name></author><category term="Salesforce" /><summary type="html"><![CDATA[Salesforce’s July 2026 enforcement deadline is approaching fast: admins and privileged users will be required to use phishing-resistant MFA — not just any second factor. A YubiKey or a platform authenticator like Windows Hello or Touch ID qualifies. A Salesforce Authenticator push notification or a TOTP code from Google Authenticator does not.]]></summary></entry><entry><title type="html">Enabling flows for Salesforce Integration user</title><link href="https://waitingimpatiently.com/enabling-flows-for-salesforce-integration-user/" rel="alternate" type="text/html" title="Enabling flows for Salesforce Integration user" /><published>2025-05-15T00:00:00+00:00</published><updated>2025-05-15T00:00:00+00:00</updated><id>https://waitingimpatiently.com/enabling-flows-for-salesforce-integration-user</id><content type="html" xml:base="https://waitingimpatiently.com/enabling-flows-for-salesforce-integration-user/"><![CDATA[<p>The Salesforce Integration user license provides an economical option for system-to-system integrations but arrives with significant constraints. Most notably, these users cannot execute Flows by default—a limitation that can obstruct automation efforts.</p>

<p>However, the restriction can be overcome through strategic permission configuration. The process involves five steps:</p>

<h2 id="step-1-create-permission-set">Step 1: Create Permission Set</h2>

<p>Establish a new permission set titled “Integration Permission Set” with no assigned license.</p>

<p><img src="/assets/images/salesforce-integration-flows/image.png" alt="Create Permission Set with no license assigned" /></p>

<h2 id="step-2-create-integration-user">Step 2: Create Integration User</h2>

<p>Set up a dedicated user with the “Salesforce Integration” license and assign the “Salesforce API Only System Integration” profile.</p>

<h2 id="step-3-assign-permission-set-license">Step 3: Assign Permission Set License</h2>

<p>This represents the critical phase. The Salesforce API license defaults to severe restrictions. Navigate to “Permission Set License Assignments” and enable the “Salesforce API Integration” license—this restores standard functionality.</p>

<p><img src="/assets/images/salesforce-integration-flows/image-1.png" alt="Permission Set License Assignments section" /></p>

<p><img src="/assets/images/salesforce-integration-flows/image-2.png" alt="Enable Salesforce API Integration license checkbox" /></p>

<h2 id="step-4-enable-run-flows-permission">Step 4: Enable Run Flows Permission</h2>

<p>Access the Integration Permission Set’s App Permissions section and activate the “Run Flows” checkbox.</p>

<p><img src="/assets/images/salesforce-integration-flows/image-3.png" alt="App Permissions link in Integration Permission Set" /></p>

<p><img src="/assets/images/salesforce-integration-flows/image-4.png" alt="Run Flows checkbox in App Permissions" /></p>

<h2 id="step-5-assign-permission-set-to-user">Step 5: Assign Permission Set to User</h2>

<p>Complete the configuration by assigning your newly created permission set to the integration user through the Manage Assignments button.</p>

<p><img src="/assets/images/salesforce-integration-flows/image-5.png" alt="Manage Assignments button in Permission Set" /></p>

<p><strong>Note:</strong> Without enabling the permission set license in Step 3, attempting to assign the permission set generates an error message regarding incompatible user licenses.</p>]]></content><author><name>Chris Auer</name></author><category term="Salesforce" /><summary type="html"><![CDATA[The Salesforce Integration user license provides an economical option for system-to-system integrations but arrives with significant constraints. Most notably, these users cannot execute Flows by default—a limitation that can obstruct automation efforts.]]></summary></entry><entry><title type="html">xDB.Tracker Identifier Missing</title><link href="https://waitingimpatiently.com/xdb-tracker-missing/" rel="alternate" type="text/html" title="xDB.Tracker Identifier Missing" /><published>2020-09-11T00:00:00+00:00</published><updated>2020-09-11T00:00:00+00:00</updated><id>https://waitingimpatiently.com/xdb-tracker-missing</id><content type="html" xml:base="https://waitingimpatiently.com/xdb-tracker-missing/"><![CDATA[<p>A persistent bug in Sitecore xConnect involves contact identifier management during merge operations. When two contacts merge, the system must select which identifiers to retain, but it frequently discards the xDB.Tracker identifier entirely.</p>

<p>There are two key identifier types: the Alias identifier (a random GUID assigned at contact creation) and the xDB.Tracker (assigned only during web visits). The problem occurs when merging contacts—the system fails to preserve the xDB.Tracker, leaving contacts unable to process subsequent web visits.</p>

<p>When affected, users encounter an error stating “Contact…must have a tracker identifier.” This breaks tracking functionality until users clear their cookies, forcing them to essentially restart their session.</p>

<h2 id="the-solution">The Solution</h2>

<p>The solution involves creating a custom pipeline processor that executes before Sitecore’s standard conversion process. This processor checks for missing xDB.Tracker identifiers and regenerates them via xConnect API calls when necessary. This fix resolves approximately 60 daily errors down to roughly one occurrence every 4-5 days.</p>

<p>This approach is a temporary workaround—hopefully the community can help reproduce the underlying issue for official Sitecore resolution.</p>]]></content><author><name>Chris Auer</name></author><category term="xConnect" /><category term="Sitecore" /><category term="xDB" /><summary type="html"><![CDATA[A persistent bug in Sitecore xConnect involves contact identifier management during merge operations. When two contacts merge, the system must select which identifiers to retain, but it frequently discards the xDB.Tracker identifier entirely.]]></summary></entry><entry><title type="html">Are you losing your xDB data?</title><link href="https://waitingimpatiently.com/are-you-missing-xdb-data/" rel="alternate" type="text/html" title="Are you losing your xDB data?" /><published>2020-02-06T00:00:00+00:00</published><updated>2020-02-06T00:00:00+00:00</updated><id>https://waitingimpatiently.com/are-you-missing-xdb-data</id><content type="html" xml:base="https://waitingimpatiently.com/are-you-missing-xdb-data/"><![CDATA[<p>If you are on Sitecore 9.0 to 9.1.1 without patches, data loss may occur. Users should watch for specific error messages in their logs.</p>

<h2 id="expected-errors-in-sitecore-logs">Expected Errors in Sitecore Logs</h2>

<p>The system generates a message stating “ERROR General error when submitting contact. Exception: Sitecore.XConnect.Operations.FacetOperationException Message: Operation #0, AlreadyExists, <ContactId>, Classification Source: Sitecore.Xdb.Common.Web"</ContactId></p>

<h2 id="expected-errors-in-xconnect-logs">Expected Errors in xConnect Logs</h2>

<p>Similar FacetOperationException errors appear, indicating batch execution problems with contact classification operations.</p>

<h2 id="official-solution">Official Solution</h2>

<p>A patch exists in the Sitecore Knowledge Base addressing this contact-saving issue.</p>

<h2 id="persistent-problem-in-multi-server-environments">Persistent Problem in Multi-Server Environments</h2>

<p>Even with the patch installed, errors continue in specific configurations:</p>
<ul>
  <li>Multiple Content Delivery servers</li>
  <li>Load balancer implementation</li>
  <li>Session state stored in-process (not Redis, MongoDB, or SQL)</li>
</ul>

<h2 id="root-cause">Root Cause</h2>

<p>When clients switch between servers or devices, in-process sessions disconnect, severing the contact reference. New sessions attempting to save contacts generate duplicate operation errors.</p>

<h2 id="resolution">Resolution</h2>

<p>Move both shared and private session state to Redis, SQL Server, or MongoDB using Sitecore’s official configuration walkthroughs.</p>

<p><strong>Note:</strong> SQL implementations won’t function in Azure SQL due to temp database requirements.</p>]]></content><author><name>Chris Auer</name></author><category term="Sitecore" /><category term="xDB" /><category term="xConnect" /><summary type="html"><![CDATA[If you are on Sitecore 9.0 to 9.1.1 without patches, data loss may occur. Users should watch for specific error messages in their logs.]]></summary></entry><entry><title type="html">Bonfire releases xDB Peek (Part 2)</title><link href="https://waitingimpatiently.com/xdb-peek-part-2/" rel="alternate" type="text/html" title="Bonfire releases xDB Peek (Part 2)" /><published>2019-09-02T00:00:00+00:00</published><updated>2019-09-02T00:00:00+00:00</updated><id>https://waitingimpatiently.com/xdb-peek-part-2</id><content type="html" xml:base="https://waitingimpatiently.com/xdb-peek-part-2/"><![CDATA[<p>This installment continues from Part 1, diving into the breakdown of xDB Peek’s information categories and upcoming features.</p>

<h2 id="contact-section">Contact Section</h2>

<p>The contact tab houses all xConnect-related contact data, including:</p>

<p><strong>Identifiers</strong> - A comprehensive list of assigned identifiers and merged accounts, containing source, identifier value, type, and validity status.</p>

<p><strong>IsKnown</strong> - Indicates whether a contact has been identified using methods beyond Sitecore’s default identifiers, such as through the IdentifyAs() function or direct xConnect assignment.</p>

<p><strong>ExpandOptions</strong> - Displays available facets for xConnect interaction, functioning as a registry of known facets.</p>

<p><strong>ConcurrencyToken</strong> - A GUID that Sitecore applies to all facets. Mismatched tokens during save operations trigger an error, preventing facet overwrites. Each object possesses a unique token.</p>

<p><strong>LastModified</strong> - Timestamp of the most recent contact modification.</p>

<p><strong>Id</strong> - The primary contact identifier visible in Experience Profile URLs and the Contacts table within shard databases (distinct from tracker contact IDs).</p>

<h2 id="visit-data-section">Visit Data Section</h2>

<p>Current interaction information specific to the active web visit:</p>

<ul>
  <li><strong>BrowserInfo</strong> - Browser identification data including major name, minor name, and version.</li>
  <li><strong>ChannelId</strong> - Current visit’s assigned channel, variable based on traffic source.</li>
  <li><strong>DeviceId</strong> - Associated device identifier from Sitecore’s device registry.</li>
  <li><strong>GeoData</strong> - Geographic information derived from IP geolocation services (available free in Sitecore 9.x).</li>
  <li><strong>HasGeoIpData</strong> - Boolean indicating geolocation data availability.</li>
  <li><strong>InteractionId</strong> - Unique identifier for the specific web visit.</li>
  <li><strong>Ip</strong> - User’s IP address in hexadecimal format (requiring hex decoding).</li>
  <li><strong>Keywords</strong> - Keywords assigned to the interaction.</li>
  <li><strong>Language</strong> - Current visit’s language designation.</li>
  <li><strong>ScreenInfo</strong> - Device screen dimensions as Sitecore perceives them, based on browser-provided data.</li>
  <li><strong>SiteName</strong> - Identified Sitecore site from the sites configuration node.</li>
</ul>

<h2 id="pages-section">Pages Section</h2>

<p>Comprehensive listing of all pages visited during the current interaction, excluding pages from previous sessions. Contains page title, URL, and blank-window status.</p>

<h2 id="goals-section">Goals Section</h2>

<p>Records goals triggered during web visits or out-of-channel activities, displaying engagement value, title, UTC timestamp, current/past visit designation, and associated event data.</p>

<p><strong>CurrentGoals</strong> - Goals triggered within the current session, enabling Sitecore to personalize based on present-session activity.</p>

<p><strong>PastGoals</strong> - Goals triggered before the current visit, allowing personalization based on historical behavior. Current session goals transition to past goals upon visit closure.</p>

<h2 id="facets-section">Facets Section</h2>

<p>Lists all available contact facets populated from ExpandOptions. Example Personal facet contains birthdate, name components, gender, job title, language preference, concurrency token, and modification timestamp.</p>

<h2 id="profiles-section">Profiles Section</h2>

<p>Tracks current and historical pattern card assignments based on profile scoring:</p>

<p><strong>CurrentProfiles</strong> - Active pattern cards with profile name, score, count, and pattern details.</p>

<p><strong>PastProfiles</strong> - Historical pattern cards with scoring frequency, totals, and individual score records by key-value pairs.</p>]]></content><author><name>Chris Auer</name></author><category term="xDB" /><category term="Sitecore" /><summary type="html"><![CDATA[This installment continues from Part 1, diving into the breakdown of xDB Peek’s information categories and upcoming features.]]></summary></entry><entry><title type="html">Bonfire releases xDB Peek (Part 1)</title><link href="https://waitingimpatiently.com/xdb-peek/" rel="alternate" type="text/html" title="Bonfire releases xDB Peek (Part 1)" /><published>2019-09-02T00:00:00+00:00</published><updated>2019-09-02T00:00:00+00:00</updated><id>https://waitingimpatiently.com/xdb-peek</id><content type="html" xml:base="https://waitingimpatiently.com/xdb-peek/"><![CDATA[<p>Bonfire has unveiled xDB Peek, an evolved version of their analytics data transfer object project. This tool provides an accessible, styled interface for viewing comprehensive information about Sitecore website visitors.</p>

<h2 id="key-features">Key Features</h2>

<p>The tool displays:</p>
<ul>
  <li>xConnect Details</li>
  <li>Facets</li>
  <li>Goals</li>
  <li>Marketing Plans</li>
  <li>Campaigns</li>
  <li>History</li>
  <li>Patterns and profiles</li>
</ul>

<h2 id="background">Background</h2>

<p>The project originated in 2017 when James Williamson requested a way to identify a user’s profile during an active session without terminating it. The initial solution used a simple API endpoint (<code class="language-plaintext highlighter-rouge">/apis/v1/visitordetails</code>) that returned xConnect profile data in JSON format.</p>

<h2 id="evolution-to-xdb-peek">Evolution to xDB Peek</h2>

<p>The upgrade transforms this functionality into a user-friendly interface accessible without browser extensions. Instead of viewing raw JSON strings, data now organizes into distinct tabs for clarity. The tool supports both desktop and mobile viewing, recognizing that personalization experiences differ across devices.</p>

<h2 id="future-development">Future Development</h2>

<p>The team plans to expand beyond read-only capabilities, adding functions such as triggering goals, enrolling users in pattern cards, merging contacts, and executing other operational tasks.</p>

<p>The release targets Sitecore 9.x versions and is available on GitHub at the Bonfire repository.</p>]]></content><author><name>Chris Auer</name></author><category term="xConnect" /><category term="xDB" /><category term="Sitecore" /><summary type="html"><![CDATA[Bonfire has unveiled xDB Peek, an evolved version of their analytics data transfer object project. This tool provides an accessible, styled interface for viewing comprehensive information about Sitecore website visitors.]]></summary></entry><entry><title type="html">Add your xConnect facet to Experience Profile, the Lazy Way</title><link href="https://waitingimpatiently.com/add-facet-to-experience-profile-the-lazy-way/" rel="alternate" type="text/html" title="Add your xConnect facet to Experience Profile, the Lazy Way" /><published>2019-07-10T00:00:00+00:00</published><updated>2019-07-10T00:00:00+00:00</updated><id>https://waitingimpatiently.com/add-facet-to-experience-profile-the-lazy-way</id><content type="html" xml:base="https://waitingimpatiently.com/add-facet-to-experience-profile-the-lazy-way/"><![CDATA[<p>The challenge of displaying xConnect facets in Sitecore’s Experience Profile traditionally involves complex, time-consuming processes. I discovered a faster solution using the EP Express Tab, an open-source Sitecore project that enables adding tabs to Experience Profile in approximately 10 minutes.</p>

<p>The implementation involves three main steps:</p>

<h2 id="step-1-add-the-nuget-package">Step 1: Add the NuGet Package</h2>

<p>Install the EPExpressTab NuGet package to begin development.</p>

<h2 id="step-2-create-a-model-and-view-model">Step 2: Create a Model and View Model</h2>

<p>Build a model to hold your facets and other necessary data. Then construct a view model extending the EpExpressViewModel class, which specifies the CSHTML view location for the EP tab.</p>

<h2 id="step-3-design-the-cshtml-view">Step 3: Design the CSHTML View</h2>

<p>Create the presentation layer injecting into the new EP tab. I incorporated Sitecore’s styling to maintain visual consistency with Speak.</p>

<h2 id="how-it-works">How It Works</h2>

<p>EP Express Tab automatically detects classes inheriting EpExpressViewModel and generates corresponding tabs in the core database. The tab naming derives from the TabLabel property, and the rendering automatically integrates into Experience Profile’s presentation details.</p>

<p>For multiple tabs, developers simply create additional view models and views. The tab ordering can be adjusted within the core database at <code class="language-plaintext highlighter-rouge">/sitecore/client/Applications/ExperienceProfile/Contact/PageSettings/Tabs/</code>.</p>]]></content><author><name>Chris Auer</name></author><category term="xDB" /><category term="xConnect" /><category term="Sitecore" /><summary type="html"><![CDATA[The challenge of displaying xConnect facets in Sitecore’s Experience Profile traditionally involves complex, time-consuming processes. I discovered a faster solution using the EP Express Tab, an open-source Sitecore project that enables adding tabs to Experience Profile in approximately 10 minutes.]]></summary></entry><entry><title type="html">Working with the xConnect hex identifiers</title><link href="https://waitingimpatiently.com/convert-xconnect-hex-identifier/" rel="alternate" type="text/html" title="Working with the xConnect hex identifiers" /><published>2019-06-20T00:00:00+00:00</published><updated>2019-06-20T00:00:00+00:00</updated><id>https://waitingimpatiently.com/convert-xconnect-hex-identifier</id><content type="html" xml:base="https://waitingimpatiently.com/convert-xconnect-hex-identifier/"><![CDATA[<p>This article explains how to work with hexadecimal identifiers in Sitecore 9.x xConnect shard databases. Identifiers for contacts, contact facets, interactions, and interaction facets are now stored in separate tables with hexed values, unlike the Mongo structure used in Sitecore 8.2.</p>

<p>I needed to find a contact ID using a known email address. In the previous version, a simple Mongo query would retrieve this information. However, in 9.x, the identifiers are encoded in hexadecimal format.</p>

<p>Using an online hex-to-ASCII converter, I confirmed these are standard hex characters without encryption. Here are two SQL queries to work with this data:</p>

<h2 id="query-1-display-all-email-identifiers">Query 1: Display All Email Identifiers</h2>

<p>This query displays all email address identifiers in readable format using a CONVERT function to decode the hexadecimal values.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="k">CONVERT</span><span class="p">(</span><span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">100</span><span class="p">),</span> <span class="n">Identifier</span><span class="p">)</span> <span class="k">as</span> <span class="n">Email</span>
<span class="k">FROM</span> <span class="p">[</span><span class="n">xdb_collection</span><span class="p">].[</span><span class="n">ContactIdentifiers</span><span class="p">]</span>
<span class="k">WHERE</span> <span class="k">Source</span> <span class="o">=</span> <span class="s1">'email'</span>
</code></pre></div></div>

<h2 id="query-2-find-specific-email">Query 2: Find Specific Email</h2>

<p>This query finds a specific email address by converting the search term to VARBINARY format and comparing it against the stored Identifier column.</p>

<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SELECT</span> <span class="o">*</span>
<span class="k">FROM</span> <span class="p">[</span><span class="n">xdb_collection</span><span class="p">].[</span><span class="n">ContactIdentifiers</span><span class="p">]</span>
<span class="k">WHERE</span> <span class="n">Identifier</span> <span class="o">=</span> <span class="k">CONVERT</span><span class="p">(</span><span class="nb">VARBINARY</span><span class="p">(</span><span class="mi">100</span><span class="p">),</span> <span class="s1">'user@example.com'</span><span class="p">)</span>
</code></pre></div></div>

<p>This approach allows direct database access to retrieve contact information from the xConnect shard databases.</p>]]></content><author><name>Chris Auer</name></author><category term="Sitecore" /><category term="xConnect" /><category term="SQL" /><summary type="html"><![CDATA[This article explains how to work with hexadecimal identifiers in Sitecore 9.x xConnect shard databases. Identifiers for contacts, contact facets, interactions, and interaction facets are now stored in separate tables with hexed values, unlike the Mongo structure used in Sitecore 8.2.]]></summary></entry><entry><title type="html">What if I were to tell you the Sitecore.Kernel dll from NuGet isn’t the latest?</title><link href="https://waitingimpatiently.com/friendly-reminder-to-patch-your-sitecore-kernel/" rel="alternate" type="text/html" title="What if I were to tell you the Sitecore.Kernel dll from NuGet isn’t the latest?" /><published>2019-05-16T00:00:00+00:00</published><updated>2019-05-16T00:00:00+00:00</updated><id>https://waitingimpatiently.com/friendly-reminder-to-patch-your-sitecore-kernel</id><content type="html" xml:base="https://waitingimpatiently.com/friendly-reminder-to-patch-your-sitecore-kernel/"><![CDATA[<p>Sitecore maintains an extensive knowledge base containing patches and updates necessary for various environments. The manner in which sites are patched carries significant importance, requiring consistency across all instances.</p>

<p>In Sitecore 8.2 Update 6 and 7, as well as 9.1 Update 1, the kernel contains a bug that crashes when encountering bad internal links. This malfunction can either crash the Rebuild Link Database application or bring down an entire site. When Sitecore attempts to resolve a link without proper error handling, it can fail deep within kernel code, producing a “System.FormatException: Unrecognized Guid format” error.</p>

<h2 id="the-patching-challenge">The Patching Challenge</h2>

<p>The solution involves a Sitecore knowledge base patch that completely replaces the Sitecore.Kernel dll. However, this presents a patching challenge: Sitecore does not publish hotfixes through NuGet packages; they release fixes through their knowledge base for selective implementation.</p>

<h2 id="two-approaches">Two Approaches</h2>

<ol>
  <li>Include the patched kernel in builds</li>
  <li>Exclude it entirely and patch servers manually</li>
</ol>

<p>I advocate for the first option, emphasizing intentional CI builds that eliminate snowflake servers—environments with undocumented, manual patches.</p>

<h2 id="recommended-solution">Recommended Solution</h2>

<p>Create an Infrastructure.Patch project within Helix solutions to manage all patches centrally. This approach ensures consistency across environments and simplifies upgrades. By incorporating patches directly into build processes, organizations can achieve their goal of rebuilding production environments entirely through CI scripting.</p>]]></content><author><name>Chris Auer</name></author><category term="Sitecore" /><category term="CI" /><summary type="html"><![CDATA[Sitecore maintains an extensive knowledge base containing patches and updates necessary for various environments. The manner in which sites are patched carries significant importance, requiring consistency across all instances.]]></summary></entry><entry><title type="html">9.1 Release of the Bonfire Analytics DTO</title><link href="https://waitingimpatiently.com/9-1-release-of-the-bonfire-analytics-dto/" rel="alternate" type="text/html" title="9.1 Release of the Bonfire Analytics DTO" /><published>2019-04-09T00:00:00+00:00</published><updated>2019-04-09T00:00:00+00:00</updated><id>https://waitingimpatiently.com/9-1-release-of-the-bonfire-analytics-dto</id><content type="html" xml:base="https://waitingimpatiently.com/9-1-release-of-the-bonfire-analytics-dto/"><![CDATA[<p>I needed to monitor what Sitecore observes about users and sessions, encompassing goals, events, profiles, patterns, pages, geographic data, marketing automation, and xConnect facets—both current and historical versions.</p>

<p>I originally created a JSON application for version 8.2 and have maintained it through the 9.1 release cycle.</p>

<h2 id="key-feature-handling-sitecore-facets">Key Feature: Handling Sitecore Facets</h2>

<p>The system retrieves requested facets through ContactExpandOptions. My approach involves accessing the xConnect server configuration to obtain all KnownModels (available facet models), passing these into ContactExpandOptions to retrieve and serialize all facets.</p>

<h2 id="json-output-includes">JSON Output Includes</h2>

<p>The resulting JSON output includes:</p>
<ul>
  <li>Identifiers</li>
  <li>Contact status</li>
  <li>Visited pages</li>
  <li>Interaction details</li>
  <li>Current and past goals</li>
  <li>Current and past events</li>
  <li>xConnect facets with values</li>
  <li>Current profile identification</li>
  <li>Past profile identification</li>
</ul>

<p>Check the GitHub releases page for access to the tool.</p>]]></content><author><name>Chris Auer</name></author><category term="xConnect" /><category term="Sitecore" /><summary type="html"><![CDATA[I needed to monitor what Sitecore observes about users and sessions, encompassing goals, events, profiles, patterns, pages, geographic data, marketing automation, and xConnect facets—both current and historical versions.]]></summary></entry></feed>