Tag: Data Cloud

  • Omni-Channel routing: what breaks it in practice

    Omni-Channel routing gets blamed for a lot of things it didn’t cause. A case sits in queue for twenty minutes, an agent swears they were available, and someone opens a ticket saying “routing is broken.” Nine times out of ten, the routing engine did exactly what it was configured to do. The configuration just stopped matching how the team actually works, months ago, and nobody noticed until a customer complained.

    I’ve debugged this pattern on more than one contact-centre org now. The fix is rarely a routing change. It’s usually somewhere upstream of routing: presence, capacity, or a queue that quietly drifted out of sync with the team roster.

    Start by checking what “available” actually means

    Omni-Channel routes work based on presence status, and presence status is only as reliable as the configuration behind it. The most common failure I see: an agent’s presence status is marked “Available,” but the status options aren’t tied to the actual channels the agent can handle. They’re online, green light showing, but their service presence status was built for phone and chat, not the new async channel someone added six months ago. The routing engine has no way to know that. It just sees “Available” and sends work.

    Same problem shows up in reverse. A status like “In a Meeting” or “Training” should decline new work, but if it wasn’t explicitly configured to do that, agents sit there accumulating case assignments while genuinely unavailable. Nobody built it wrong on purpose. Someone added a new presence status for a one-off project eighteen months ago, used the default settings, and it’s been quietly misrouting work ever since.

    What to actually check

    Go through every Service Presence Status record and confirm, for each one, exactly which channels it allows and whether it’s marked to decline incoming work. Don’t trust the label. “Available – Chat Only” doesn’t restrict anything unless the configuration says so. This takes maybe thirty minutes and it’s the single highest-value audit you can run on a struggling routing setup.

    Capacity models that were right on day one

    Capacity-based routing works well until the assumptions behind it stop holding. A common one: capacity weights were set when the average case took four business days to resolve. Then the team restructured and a chunk of cases started reopening within hours, sometimes the same day. The capacity model never changed. It still assumes a case closes and frees up capacity. In practice, agents are juggling three or four reopened cases that look closed to the model but are very much open to the customer.

    The result is agents who look underutilised on paper, routing more work to them, while they’re actually buried. This one’s hard to catch from the routing side because every signal routing looks at says the agent has room. You have to go looking at reopen rates and average handle time by case type, not at the routing config itself.

    Queue membership that nobody owns

    Queues drift. Someone leaves the team and their manager removes their licence, but forgets to pull them off the three queues they were on. Someone joins and gets added to the “general” queue on day one, then never gets added to the specialised queues they were actually hired to work. Six months later, routing decisions are being made against a membership list that reflects an org chart from last year.

    This is the one I’d flag hardest, because it’s invisible until you specifically go look. Nobody gets an error. Routing just quietly sends slightly less work to the right people and slightly more to the wrong ones, and the gap compounds. A quarterly audit of queue membership against the actual team roster catches this before it becomes a pattern someone has to explain to leadership.

    A smaller version of the same problem

    Skills-based routing has the identical failure mode at a more granular level. Skills get assigned when someone’s onboarded and almost never reviewed again. An agent who moved off a product line two years ago is still being routed cases for it, because the skill record was never updated. Treat skills like permission sets: they need a review cadence, not a one-time setup.

    Routing configuration changes that never got tested

    This is the one that should worry admins most. Routing configuration in Salesforce is declarative, which makes it feel low-risk. It isn’t. A single change to routing priority, or to how overflow is handled after a time limit, can shift work distribution across an entire team, and there’s usually no automated test watching for that.

    Before any routing change goes to production, simulate it against a realistic volume pattern, not just a happy-path manual test with one case. Push through a burst of work that mimics a busy Monday morning and watch where it lands. Check the overflow path specifically: what happens when the primary queue is full and work has to spill somewhere else. That’s the path that gets touched least often in testing and breaks most often in production, usually at the exact moment volume spikes and you can least afford it.

    Where I’d actually start

    If routing feels broken and you don’t know why, don’t start with the routing configuration itself. Start with presence statuses and confirm they decline work when they should. Then check queue membership against the current team roster. Then look at capacity assumptions against actual reopen and handle-time data. In most cases I’ve worked, the routing engine was never the problem. It was faithfully executing rules built on assumptions that stopped being true a long time before anyone noticed.

  • Data migration mistakes that show up three months after go-live

    Every data migration gets tested at cutover. Record counts match the source system, a sample of accounts and contacts gets eyeballed, a handful of business users click through their most important records and confirm nothing looks obviously wrong. Hypercare runs for two or three weeks, the incident count stays low, and everyone moves on. Then, somewhere around month three, the real problems start showing up. And by then nobody’s thinking about the migration anymore, so the first instinct is to blame the new automation, or the new integration, or “something Salesforce changed.”

    It’s rarely Salesforce. It’s usually the migration, and the reason it took three months to notice is that the mistakes that matter aren’t the ones cutover testing is built to catch.

    Why cutover testing misses the damage that matters

    Cutover validation answers one question: did the records land? Count comparisons, field-level spot checks, a UAT pass against a sample. All of that is necessary. None of it tests what happens once real users, real automation and real time start interacting with the migrated data. The bugs that surface later aren’t data quality bugs in the traditional sense. They’re mismatches between what the migration assumed and what the org actually does with a record over its lifecycle.

    I’ve seen this pattern often enough on enterprise orgs that I now treat it as the default outcome of any migration that only tests for “did it land correctly,” rather than “will it behave correctly.”

    The five mistakes that don’t show up on day one

    Backdated CreatedDate breaking date-based automation

    Migrated records usually carry their original creation date, which is the right call for reporting. But entitlement processes, SLA timers, and any flow with a time-based path built on CreatedDate or a derived field will behave differently for a record created three years ago versus one created this morning. A case migrated with its original 2023 timestamp can slip straight through an SLA escalation that was designed around cases created after go-live. Nobody notices during hypercare because hypercare is full of freshly created records, not migrated ones. It shows up the first time someone runs an aged-case report or an escalation fires (or doesn’t fire) on a record nobody remembers was migrated.

    Ownership that technically works but breaks sharing

    A common shortcut: assign every migrated record to the integration user or a generic “Data Migration” user, then reassign in a follow-up script. When that follow-up step is incomplete, or when territory and queue assignment rules only fire on record creation (not on data load), you end up with records that are visible to the wrong people, invisible to the right people, or sitting in a queue nobody’s monitoring. This one is genuinely hard to catch at cutover because sharing visibility depends on who’s looking. A system admin testing UAT sees everything. The actual case owner three months later doesn’t.

    External IDs that aren’t as unique as they look

    If the migration used an external ID field to support future upserts from an integration, and that field wasn’t validated for true uniqueness against production edge cases (leading zeros stripped, whitespace, case sensitivity on a text field instead of a proper external ID field), you get silent overwrites. The first few weeks nothing collides because the integration is dealing with genuinely new records. Then a legacy record with a near-duplicate key gets touched by an inbound sync and quietly overwritten. Nobody gets an error. The data is just wrong, and it stays wrong until someone happens to compare it against the source system.

    Roll-up and formula fields that drift instead of break

    Roll-up summaries recalculate on the trigger events they’re built for: a child record inserted, updated or deleted. A bulk data load that doesn’t fire those events in the expected order, or that loads parent and child records out of sequence, can leave a roll-up value that was correct on migration day and never gets touched again unless something forces a recalculation. Three months in, someone compares a roll-up total against the underlying child records and finds a gap. It’s not corruption. It’s a number that was right once and nobody ever asked Salesforce to check it again.

    Validation rules disabled for the load and never fully restored

    Almost every migration disables validation rules, and sometimes triggers, to get bulk data through without a wall of errors. The riskier version of this is when a rule gets disabled at the metadata level rather than bypassed for the load user specifically, and re-enabling it becomes a manual step buried in a cutover runbook that doesn’t get checked off with the same rigor as the actual data load. Bad records start entering the system weeks later through completely normal channels, because the guardrail that should have stopped them was never switched back on.

    Catching these before they’re three months old

    None of this requires exotic tooling. It requires treating the first ninety days after go-live as part of the migration, not the period after it.

    • Before the load, list every automation with a time-based or CreatedDate-dependent path and decide explicitly how migrated records should behave against it, rather than discovering the answer in production.
    • Test sharing visibility as the actual end users who will own the records, not as a system admin. Profile-level testing catches what UAT with a full-access login won’t.
    • Run a uniqueness and format audit on any field used as an external ID or upsert key, against real edge cases from the source system, not a clean sample.
    • Force a full recalculation of roll-up and formula fields after the load completes, then reconcile a sample against the source rather than assuming the load triggered it correctly.
    • Put “validation rules and triggers restored to pre-migration state” on the cutover checklist as its own signed-off line item, with a metadata diff to prove it, not a verbal confirmation.
    • Schedule a deliberate data health check at thirty, sixty and ninety days post go-live. Nobody plans for this, which is exactly why it catches things.

    The teams that get burned by this aren’t careless. They’re just measuring the wrong moment. A migration that “worked” on go-live day and a migration that holds up at day ninety are different things to test for, and only one of them is the one your users actually experience.

  • Marketing Cloud and Service Cloud: where the data should actually live

    Every org running both clouds eventually hits the same argument. Marketing wants the subscriber list clean and current. Service wants the case history complete and fast to load. Somewhere in the middle, a contact record gets updated in one system, doesn’t sync to the other for six hours, and an agent ends up apologising to a customer for an email campaign they already unsubscribed from. Nobody designed for that outcome. It just happens when nobody decided where the data actually lives.

    The question everyone asks wrong

    The usual framing is “should Marketing Cloud and Service Cloud share a database.” That’s not really the question, and chasing it wastes weeks. The real question is narrower: for each piece of data, which system is allowed to change it first, and which system is just reading a copy. Ownership, not location. Once you separate those two ideas, most of the architecture falls out on its own.

    I’ve seen teams spend a full discovery phase debating whether to sync every custom field bidirectionally, when the actual problem was that three fields had two owners each. Fix the ownership model and the sync design gets simple. Skip it and no integration pattern will save you.

    Service Cloud owns the case, Marketing Cloud owns the send

    Start with what each platform is actually good at. Service Cloud is built around the case object and everything that touches a live interaction: entitlements, SLAs, Omni-Channel routing, knowledge attach, agent productivity. Marketing Cloud is built around segmentation, journey orchestration and send-time optimisation at volumes Service Cloud was never designed to handle.

    That split points at a simple rule. Anything that changes because of a conversation with the customer (a case status, a resolution, an escalation, a preference an agent captured mid-call) should be written in Service Cloud first. Anything that changes because of engagement behaviour (an email open, a click, a journey exit, a subscription status) should be written in Marketing Cloud first. Trying to make either system the single source of truth for both kinds of data is where the pain starts.

    Where contact data actually belongs

    Core identity fields, name, primary email, phone, account association, belong in Salesforce as the CRM system of record. Marketing Cloud should hold a subscriber record that references back to that identity, not a parallel version of it. I’ve worked with orgs that let Marketing Cloud own email address changes because “marketing needed it faster.” Within a year they had two email addresses for a meaningful chunk of their contact base, one in each system, and nobody could say with confidence which one was current. Untangling that took longer than the original integration project.

    The sync pattern that actually works

    Once ownership is clear, the sync direction should follow it. Core identity and case-driven fields flow Salesforce to Marketing Cloud. Engagement and journey data flows Marketing Cloud to Salesforce, usually as read-only fields an agent can see but not edit. Two-way sync on the same field is where most of the genuinely hard bugs live, because now you need conflict resolution logic, and conflict resolution logic is where a “simple” integration turns into a six-week debugging exercise involving timestamps, retry queues and someone asking why a customer’s phone number reverted itself.

    Marketing Cloud Connect vs a custom integration

    Marketing Cloud Connect handles the standard case well: syncing contacts, data extensions built from Salesforce reports, and triggering journeys off Salesforce events. If your requirements sit inside that footprint, use it. Don’t build a custom middleware layer to solve a problem the managed package already solves, that’s effort spent maintaining infrastructure instead of shipping outcomes.

    Where I reach for something custom is high-volume event-driven sync (thousands of engagement updates a day that Connect’s polling cadence can’t keep up with), or complex transformation logic between the two data models. Even then, keep the ownership rule intact. A custom integration that blurs who owns what is worse than no integration at all, because it looks automated while quietly making the data less trustworthy.

    Where Data Cloud changes the calculus

    Data Cloud shifts this conversation in a useful direction. Instead of Service Cloud and Marketing Cloud each holding their own partial view and syncing fields back and forth, Data Cloud can sit underneath both as the unification layer, harmonising identity across sources and exposing a single calculated profile to each cloud. That doesn’t remove the ownership question, it just moves it up a level: now you’re deciding which source system is authoritative for each field inside Data Cloud’s identity resolution rules, rather than negotiating a point-to-point sync between two orgs.

    It’s worth genuinely evaluating for any org running both clouds at scale, but it’s not a shortcut around doing the ownership exercise. Teams that skip straight to Data Cloud without agreeing on ownership first end up with the same duplicate-identity mess, just inside a more expensive tool.

    A decision test that holds up in practice

    When a new field or object comes up in a design session, I ask one question: what event causes this data to change? If the answer is a customer interaction an agent is part of, it belongs in Service Cloud. If the answer is a marketing behaviour, an open, a click, a journey stage, it belongs in Marketing Cloud. If the answer is genuinely both, that’s a signal the field is doing two jobs and probably needs to be split into two fields with two clear owners.

    Apply that test consistently and the integration design writes itself. Skip it and you’ll be back in six months arguing about why the unsubscribe list and the case queue disagree with each other, and nobody will remember which system was supposed to be right.