> AI agents: this is one page from Mammoth Analytics documentation. The index of all pages as Markdown is https://docs.mammoth.io/llms.txt. Append `.md` to any docs URL, or send `Accept: text/markdown`, to get Markdown.

# Salesforce + Tableau

> Clean Salesforce opportunity data in Mammoth and hand it to Tableau by CSV, Live Link, a Mammoth-managed database, or your own warehouse.

Tableau can connect directly to Salesforce, but Salesforce data is messy—opportunity stage names differ across teams, fields are inconsistently populated, and the object model is complex. Mammoth sits in the middle to clean, reshape, and enrich the data before Tableau sees it.

This guide is for data analysts and BI developers. It covers what is specific to the Salesforce → Tableau pairing: the cleanup recipe and the three ways to hand cleaned data to Tableau. For the general mechanics (connecting Salesforce, building transformations, setting up a refresh schedule), it links to the reference docs. If you are building a full sales-reporting workflow, see the [Sales analytics use case](https://docs.mammoth.io/guides/use-cases/sales-analytics) instead.

![Salesforce data flows through a Mammoth pipeline into a View that reaches Tableau by CSV or through a warehouse.](https://docs.mammoth.io/api/v1/images/20260805_053531_architecture-salesforce-tableau1.jpg)

## What you will build

- A Salesforce dataset (Opportunities, Accounts, and Users for owner names) connected via the [Salesforce connector](https://docs.mammoth.io/learn/connectors/salesforce-connector/)
- A transformation pipeline: stage normalization, owner enrichment, deal scoring
- A View that Tableau reads from—by CSV or Live Link, a Mammoth-managed database, or your own warehouse
- A [Dataset Refresh automation](https://docs.mammoth.io/learn/automations/dataset-refresh/) to keep it current

## Step 1: Connect Salesforce

Follow the full [Salesforce connector guide](https://docs.mammoth.io/learn/connectors/salesforce-connector/) to authenticate and create your dataset. Two things specific to this integration:

- **Objects to pull:** `Opportunity` and `Account` for the pipeline data, plus `User` so you can resolve `OwnerId` to a readable name later. Mammoth's object list reflects everything your connected Salesforce profile can see—it is not limited to a fixed set.
- **API access:** requires the "API Enabled" permission on the connected profile—included in Enterprise, Unlimited, and Developer editions; Professional edition needs the API add-on. Field-level security (FLS) also applies: a field the integration user cannot see in Salesforce does not appear in Mammoth. Use a dedicated integration user rather than a personal login.

## Step 2: Build the transformation pipeline

This is the part that is specific to CRM-for-BI cleanup.

### Stage normalization

Salesforce stage names often drift across teams—"Proposal Sent", "Proposal/Price Quote", and "Proposal" all mean the same thing.

1. Add a [Bulk Replace](https://docs.mammoth.io/learn/transform/filter-label-replace) task on the `StageName` column and group the variants into your canonical stages: `Prospecting`, `Discovery`, `Proposal`, `Negotiation`, `Closed Won`, `Closed Lost`.
2. Add a `StageNumber` column with [Label & Insert Values](https://docs.mammoth.io/learn/transform/filter-label-replace) so each canonical stage maps to an integer (1–6) for sorting and funnel math.

### Owner enrichment

Opportunity owner is stored as `OwnerId` (a Salesforce ID), not a name. Bring in the readable details from the `User` object with [Join](https://docs.mammoth.io/learn/transform/unify#join). Use Join rather than Lookup here because you are pulling in more than one column at once:

- Key columns: `Opportunity.OwnerId` ↔ `User.Id`
- Columns to bring in: `User.Name`, `User.Title`, `User.Region` (if you track one), `User.Manager`

### Deal scoring (optional AI enrichment)

Use [Generative AI](https://docs.mammoth.io/learn/transform/generative-ai/) with a plain-English prompt against `Amount`, `StageNumber`, and days-since-last-activity, for example: *"Classify this opportunity as Hot, Warm, Cold, or At Risk based on amount, stage, and recent activity."* This gives Tableau a color-codeable column without a calculated field. Note the feature's limits: 300 characters per generated value, and only the first 50,000 rows of the view are processed per run.

### Pipeline metrics

Using [Math Function](https://docs.mammoth.io/learn/transform/date-numeric-text):

- `DaysToClose = CloseDate - TODAY()` (for open opportunities)
- `WeightedValue = Amount * (Probability / 100)` (if Probability is populated)

## Step 3: Create the View

Create a View from the finished pipeline (name it something like `sf_pipeline_clean`). This is the stable, cleaned dataset Tableau reads from. How you expose it to Tableau depends on which option you pick in Step 5.

## Step 4: Keep it current

Add a [Dataset Refresh automation](https://docs.mammoth.io/learn/automations/dataset-refresh/) on the Salesforce dataset. Every 4 hours is a reasonable default for sales teams: frequent enough to feel current without pulling more from the Salesforce API than necessary. Check the Automation list for run status (Active / Failed) rather than assuming success. If you are on a large org and see rate-limit errors from Salesforce, reduce the cadence or narrow the query to recently modified records—Salesforce's own API limits vary by edition and license count, so there's no single number to plan around.

## Step 5: Connect Tableau

**Option A: Tableau Desktop (simplest).** [Download](https://docs.mammoth.io/learn/export-share/export-formats) the View as CSV, then in Tableau Desktop: **Connect** → **Text File**. For something that stays current without re-downloading by hand, use a [Live Link](https://docs.mammoth.io/learn/export-share/live-links) instead—it's a stable URL that always serves the View's latest data.

**Option B: Mammoth-managed database (no infrastructure to run).** Export the View to a Mammoth-managed **BigQuery** or **PostgreSQL** destination (**Export** → **Databases**). Mammoth provisions it and gives you connection credentials. Point Tableau (Desktop or Server) at that database and let it refresh on its own schedule.

**Option C: Your own warehouse.** Use [Send to destinations](https://docs.mammoth.io/learn/export-share/send-to-destinations) to an external **BigQuery**, **PostgreSQL**, **SQL Server**, or **Redshift** destination—whichever matches your existing stack—then connect Tableau Server/Cloud directly to that table. This option suits larger deployments: the warehouse handles the serving layer, and BigQuery destinations support Replace, Combine, or Merge write modes depending on whether you want a full refresh or an incrementally updated table.

## Common issues and fixes

| Issue | Cause | Fix |
| --- | --- | --- |
| Missing fields in Mammoth | Field-level security on the Salesforce integration user | Grant field access in the Salesforce profile |
| Salesforce rate-limit errors | Too-frequent refresh, or a large org | Reduce refresh cadence, or filter the Salesforce query to recently modified records |
| Stage names not normalizing | A new stage was added in Salesforce after the Bulk Replace mapping was built | Update the Bulk Replace grouping to include the new value |
| Warehouse destination not updating | Auto-sync is off, or the pipeline did not re-run | Check Auto-sync on both the View and the destination; see [Send to destinations troubleshooting](https://docs.mammoth.io/learn/export-share/send-to-destinations#troubleshooting) |

---
Source: https://docs.mammoth.io/guides/integrations/salesforce-tableau.md · Updated: 2026-10-13