Skip to content

Latest commit

 

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Salesforce D360 + Agentforce Lab

Hands-on pipeline from raw data to AI agent: CRM data + Databricks Delta tables unified in Data Cloud (D360), grounded in Agentforce. Built to understand what D360 actually does at the infrastructure level, not just the slide deck version.

graph LR
    subgraph Sources
        CRM["Salesforce CRM<br/>25 Accounts, ~55 Contacts<br/>~35 Opps, 18 Cases"]
        DBX["Databricks Delta Lake<br/>Web Analytics (~44 rows, user_email)<br/>Product Usage (~38 rows, user_email)<br/>Firmographic (25 rows, domain)"]
    end

    subgraph D360["Salesforce Data Cloud (D360)"]
        direction TB
        DLO["Data Lake Objects<br/>(raw, source schema)"]
        DMO["Data Model Objects<br/>(normalized canonical)"]
        IR["Identity Resolution<br/>(exact email match via<br/>Contact Point Email)"]
        CI["Calculated Insights<br/>+ Segments"]
    end

    subgraph Output
        AF["Agentforce Agent<br/>(grounded in unified data)"]
    end

    CRM -->|"CRM Native<br/>Ingestion (free)"| DLO
    DBX -->|"Query Federation<br/>(Zero Copy, live)"| DLO
    DLO --> DMO
    DMO --> IR
    IR --> CI
    CI --> AF
Loading

D360's value proposition is straightforward: without it, your AI agent sees CRM data only. With it, the agent sees CRM + web engagement + product usage + third-party enrichment. The difference between "this account has an open deal" and "this account has an open deal, declining product usage, 3 escalated support tickets, and hasn't visited the pricing page in 60 days" is the difference between a chatbot and a useful agent.

Who This Is For

  • Evaluating D360 (Data Cloud) architecture for an implementation or proof of concept
  • Have a Salesforce Developer Edition with Data Cloud enabled
  • Have a Databricks workspace (trial works)
  • Comfortable with Python and SQL

Quick Start

# 1. Clone and set up
git clone https://github.com/btriani/salesforce-d360-agentforce-lab.git
cd salesforce-d360-agentforce-lab
python3 -m venv .venv && source .venv/bin/activate
pip install -r d360-agentforce-lab/01-synthetic-data/requirements.txt

# 2. Authenticate to Salesforce (OAuth, no SOAP)
sf org login web --alias my-dev-org

# 3. Load CRM data
cd d360-agentforce-lab/01-synthetic-data
python generate_and_load.py

# 4. Create Databricks tables (set DATABRICKS_HOST and DATABRICKS_TOKEN)
cd ../02-external-data
python generate_external_data.py

Lab Structure

# Phase What It Does D360 Concepts
01 Synthetic CRM Data Generate ~55 contacts, ~35 opps, 25 accounts, 18 cases and load into Salesforce via REST API CRM-native ingestion, data model foundation
02 External Data Create ~44 web analytics rows, ~38 product usage rows, 25 firmographic rows as Delta tables in Databricks External sources, Zero Copy, Query Federation
03 D360 Configuration Connect Databricks, create data streams, map DMOs, configure IR with email matching, build Calculated Insights and Segments Data Streams, DLOs, DMOs, Identity Resolution, Calculated Insights, Segments
04 Agentforce Agent Design agent with prompt templates grounded in unified D360 data Prompt templates, Trust Layer, grounding

How D360 Compares to Alternatives

The customer data platform space has several players. D360's differentiator isn't any single feature -- it's the tight integration between data unification, AI, and CRM action in one platform.

Dimension Salesforce D360 Segment / Tealium Databricks + Unity Catalog Snowflake + dbt
CRM integration Native -- zero-cost CRM ingestion, bidirectional Connector-based, one-way No CRM, requires ETL No CRM, requires ETL
External data Query Federation (Zero Copy), connectors, Ingestion API SDKs, connectors Native (it IS the lake) Native (it IS the warehouse)
Identity resolution Built-in, configurable match/reconciliation rules Built-in, event-stream focused Manual (write your own) Manual (write your own)
AI/Agent integration Agentforce natively grounded in unified data None built-in Mosaic AI, but no CRM context Cortex, but no CRM context
Zero Copy Yes -- Databricks, Snowflake, BigQuery, Redshift No N/A (data is already there) N/A
Time to value Fast for Salesforce shops, config-heavy for external data Fast for web/mobile events Requires engineering team Requires engineering team
Vendor lock-in High (Salesforce ecosystem) Medium Low (open formats) Medium
Best for Enterprises already on Salesforce wanting unified customer view + AI agents Marketing teams needing event tracking + audience activation Data teams wanting full control over the lakehouse Analytics teams wanting governed warehouse

Honest take: D360 shines when you're already in the Salesforce ecosystem and want AI agents that act on unified data. If your data already lives in Databricks/Snowflake and you don't use Salesforce CRM, D360 adds a layer you may not need. The Zero Copy federation is genuinely useful -- it avoids the "copy everything into our platform" trap that most CDPs fall into. The weakness is the configuration complexity: DMO mapping, identity resolution setup, and Contact Point plumbing require significant upfront effort.

Architecture Deep Dive

Data Flow

graph TB
    subgraph "Phase 1: CRM Data"
        PY1["Python + simple_salesforce"] -->|"REST API"| SF["Salesforce CRM"]
        SF -->|"Native Ingestion<br/>(free, automatic)"| DLO_CRM["DLOs: Account_Home<br/>Contact_Home<br/>Opportunity_Home<br/>Case_Home"]
    end

    subgraph "Phase 2: External Data"
        PY2["Python + Databricks SQL API"] -->|"REST API"| DBX["Databricks<br/>Delta Tables"]
        DBX -->|"Query Federation<br/>(Zero Copy, live queries)"| DLO_EXT["DLOs: Web Analytics<br/>(user_email keyed)<br/>Product Usage<br/>(user_email keyed)<br/>Firmographic<br/>(domain keyed)"]
    end

    subgraph "Phase 3: D360 Unification"
        DLO_CRM --> DMO["Data Model Objects<br/>(normalized schema)"]
        DLO_EXT --> DMO
        DMO --> IR["Identity Resolution<br/>(exact email match)"]
        IR --> UP["Unified Individuals"]
        UP --> CI["Calculated Insights<br/>(Health Score)"]
        CI --> SEG["Segments<br/>(At Risk / Healthy / Upsell Ready)"]
    end

    subgraph "Phase 4: AI Action"
        SEG --> AGENT["Agentforce Agent"]
        CI --> AGENT
        UP --> AGENT
        AGENT -->|"Next Best Action"| USER["Sales / CS Rep"]
    end
Loading

Identity Resolution Logic

graph LR
    subgraph "CRM Contact (Salesforce)"
        C["Contact Point Email:<br/>jane.doe@apexfintech.com"]
    end

    subgraph "Web Analytics (Databricks)"
        W["user_email:<br/>jane.doe@apexfintech.com<br/>12 page views, 2 demo visits"]
    end

    subgraph "Product Usage (Databricks)"
        P["user_email:<br/>jane.doe@apexfintech.com<br/>logins: 18, feature_adoption: 72%"]
    end

    C -->|"exact email match"| UP["Unified Individual:<br/>jane.doe@apexfintech.com<br/>(3 sources matched)"]
    W -->|"exact email match"| UP
    P -->|"exact email match"| UP
Loading

Data Intentionally Designed for Identity Resolution Testing

Challenge What We Did Why It Matters
Partial coverage Not all contacts appear in web analytics or product usage Tests how D360 handles missing data across sources
Foreign keys Product usage uses EXT-XXXXX IDs, not Salesforce IDs Proves identity resolution works without shared keys
Name variations ~20% of firmographic names have "Inc.", "LLC", double spaces Tests fuzzy matching in reconciliation rules
Individual-level keying Web analytics and product usage keyed by user_email, not company domain Enables individual-level IR matching via Contact Point Email
Role-based exclusions Generic emails (info@, support@) excluded from external data Prevents false matches on shared mailbox addresses

Key D360 Vocabulary

Term What It Actually Means
Data Stream A pipeline that brings data into Data Cloud (like an ETL job)
DLO (Data Lake Object) Raw data container -- preserves source schema as-is
DMO (Data Model Object) Normalized canonical model -- the "T" in ELT
Query Federation D360 queries external data live (Databricks, Snowflake) without copying it
Zero Copy Marketing term for Query Federation + file sharing -- data doesn't move
Identity Resolution Matching records across sources into unified profiles using match rules
Contact Point Email Bridge object linking Individual DMO to email addresses -- the key to IR matching
Calculated Insight A computed metric (e.g., Health Score) built on unified data
Segment A group of entities filtered by criteria (e.g., "At Risk" accounts)
Agentforce AI agent framework -- value is proportional to the data it's grounded in
Einstein Trust Layer Governance layer ensuring agents only access permitted data
Profile vs Engagement Profile = what something IS (attributes). Engagement = what something DOES (events)

Tech Stack

Technology Usage
Python 3.14 Data generation (Faker), Salesforce REST API (simple_salesforce), Databricks SQL API
Salesforce Data Cloud Data unification, Query Federation, identity resolution, segmentation
Databricks Delta Lake tables, Serverless SQL Warehouse, Unity Catalog
Agentforce Studio AI agent design, prompt templates, grounded actions
SF CLI (sf) OAuth browser-flow authentication (no SOAP API)
GitHub Actions Automated data refresh

Observations from This Build

  1. Query Federation works well. Connecting Databricks to D360 was straightforward -- enter hostname, HTTP path, PAT, done. The "Direct Access (Accelerated)" stream type queries live and caches locally.

  2. DMO mapping is the real work. The two-layer model (DLO to DMO) makes architectural sense but the UI-based mapping is manual and tedious. In production, use DevOps Data Kits and sf project deploy start for CI/CD.

  3. Individual-level data is what makes IR work. The original design used company-level web analytics and product usage (keyed by domain). Domain matching produced account-level unification but couldn't match individuals. Switching to user_email as the key field -- so each row represents one person's activity, not one company's aggregate -- made Contact Point Email matching work at the individual level. This is the single most important architectural decision in the pipeline.

  4. Identity Resolution has a steep setup curve. The Individual DMO needs Contact Point Email/Phone objects with formula-based composite primary keys. The Sales Cloud data bundle helps but doesn't auto-configure everything. Understanding the architecture (Individual -> Contact Points via Party ID -> Match Rules) matters more than memorizing the UI steps.

  5. CRM-native ingestion is a genuine advantage. Zero-cost, zero-config ingestion from Salesforce objects is something competitors can't match. Building a CDP inside the CRM platform avoids the connector tax that standalone CDPs pay.

  6. Agentforce without D360 is limited. An agent that only sees CRM data misses the full picture. D360 is what turns "this account has a deal" into "this account has a deal, declining usage, and 3 escalated tickets."

Lessons from Building This Lab

The biggest lesson was about data granularity and identity resolution.

The first version of this lab used company-level external data: one row per company in web analytics (keyed by domain), one row per company in product usage (keyed by domain). D360's Identity Resolution matched these to accounts via domain, which produced a unified account view -- but not unified individuals.

The problem: D360's IR is designed around the Individual DMO and Contact Point Email. It matches people, not companies. When external data is keyed by domain, there's no email to match against. The IR ruleset can match jane.doe@apexfintech.com (from CRM) to jane.doe@apexfintech.com (from web analytics) -- but only if the web analytics data actually contains that email address.

The fix was to redesign the external data to be individual-level: each row in web analytics and product usage represents one person's activity, keyed by user_email. This meant generating ~44 web analytics rows (one per active contact, excluding role-based emails like info@ and support@) and ~38 product usage rows, rather than the original 20 and 25 company-level rows.

The result: IR now matches a CRM contact to their web analytics record and their product usage record via exact email match through Contact Point Email. Three sources, one unified individual. This is how D360 is designed to work -- the data model just needs to match the platform's assumptions about granularity.

License

MIT


All data is synthetic. No credentials, API keys, or proprietary data from any employer.

About

End-to-end Salesforce D360 (Data Cloud) + Agentforce pipeline: CRM data + Databricks Delta tables unified via Query Federation, mapped to DMOs, and grounded in an AI agent. Includes platform comparison with Segment, Tealium, Databricks, and Snowflake.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages