How to build Affinity deal-flow dashboards in Metabase
Affinity is a relationship-intelligence CRM where your lists, opportunities, and auto-captured interactions live — popular with venture, private equity, and dealmaking teams.Metabaseis where you turn that activity into shared, trustworthy deal-flow dashboards. This guide covers two complementary paths: a lightweight MCP + CLI route that pulls live data with an Affinity MCP server and loads a CSV into Metabase with the Metabase CLI for quick analysis, and a durable pipeline route that syncs Affinity into a database so you can build deal-flow, pipeline, and sourcing dashboards anyone can read.
How do you connect Affinity to Metabase?
Most teams combine both routes: use the Affinity MCP server and Metabase CLI route to pull live data and stand up a quick analysis, and the pipeline route for the deal-flow dashboards the firm depends on.
Live data in, quick analysis out
Connect Affinity through a managed MCP server (Gumloop) to read live lists, opportunities, and relationship data, then pair it with the Metabase CLI, whose upload command loads a CSV into Metabase as a ready-to-query table and model.
- Quick lookups like "which deals in our sourcing list have gone quiet?"
- Loading an Affinity CSV export into Metabase in seconds
- Spot-checks and one-off analyses without a warehouse
- Great for exploration, not governed reporting
- Scope the Affinity MCP connection to read-only where possible
- CSV uploads are snapshots — refresh or move to the pipeline for history
Durable dashboards with history
Sync Affinity into a database or warehouse with the Affinity API, dlt, or a managed connector, then point Metabase at it.
- Deal-flow, pipeline, and sourcing dashboards the whole firm relies on
- List and stage conversion trends over quarters
- Joining relationship data with portfolio, fund, or ops data
- Requires a destination database and a sync to maintain
- You own the stage and status definitions and the refresh schedule
- Capture list-entry stage changes if you want accurate velocity metrics
What can you analyze from Affinity data in Metabase?
- Deal flow — new opportunities by source, sector, and week
- Pipeline — open value by list, stage, and owner
- Stage conversion — where deals advance and where they stall, per list
- Win rate — won vs. decided opportunities, by source and sector
- Relationship coverage — interactions per opportunity and orgs with a recent touch
- Sourcing quality — which channels and relationship paths produce real deals
Which Affinity dashboards should you build in Metabase?
Deal flow
What's coming in and where it sits.
- New opportunities by source and week (line)
- Pipeline value by list and stage (bar)
- Active deals with no interaction in 30 days (table)
- Deals by owner and stage (matrix)
Conversion
Where deals advance and where they stall.
- Stage-to-stage conversion by list (funnel)
- Win rate by source and sector (bar)
- Passed vs. progressed by reason (bar)
- Median time-in-stage (bar)
Relationships
Who we know and how warm it is.
- Interactions per active opportunity (number)
- Coverage: orgs with a recent touch (number)
- Introductions by relationship path (table)
- Response time to inbound (line)
Sourcing quality
Which channels produce real deals.
- Sourced deals by channel (bar)
- Source → won conversion (funnel)
- Median deal size by source (bar)
- Aging of sourcing list entries (table)
How do you use the Affinity MCP server with the Metabase CLI?
Connect Affinity through a managed MCP server (Gumloop) and pair it with the Metabase CLI for fast, hands-on analysis. The Affinity MCP looks up current lists, opportunities, and interactions; the Metabase CLI's upload command loads a CSV into Metabase and creates a ready-to-query table and model. Scope the connection to read-only where possible.
Example workflow
- Ask the Affinity MCP which active deals in the sourcing list have gone quiet, or pull an organization's opportunities and recent interactions.
- Export the deals or list you want to keep as a CSV.
- Run
mb upload csvto load it into Metabase as a table and model, then build questions and dashboards on top.
Be honest about the limits
- The Affinity MCP is great for live lookups — not for scheduled or audited deal-flow reporting.
- A CSV upload is a point-in-time snapshot; refresh it with
mb upload replaceor move to the pipeline for real history. - Scope the managed connection to read-only where possible; it acts with the permissions of the connected Affinity account.
mb upload csvneeds an uploads database configured under Admin → Settings → Uploads.
How do you set up the Affinity MCP server and the Metabase CLI?
Affinity MCPmanaged
- Provider
- Gumloop (managed connector)
- Endpoint
- Gumloop-generated server URL
- Auth
- Connect your Affinity account in Gumloop (API key)
- Note
- No official first-party Affinity MCP server yet
Metabase CLIofficial
- Install
npm install -g @metabase/cli- Auth
mb auth login(browser OAuth on v62+, or an API key)- Load data
mb upload csv --file data.csv- Requires
- An uploads database (Admin → Settings → Uploads)
{
"mcpServers": {
"affinity": {
"url": "https://your-gumloop-server-url/mcp"
}
}
}# Install the Metabase CLI
npm install -g @metabase/cli
# Log in (opens your browser; requires Metabase v62+)
mb auth login --url https://your-metabase.example.com
# Load an Affinity CSV export — creates a table AND a model
mb upload csv --file affinity-opportunities.csv --collection root
# Refresh that same table later from a new export
mb upload replace <table-id> --file affinity-opportunities.csvAffinity doesn't publish a first-party MCP server, so the practical path is a managed connector: connect your Affinity account in Gumloop, then use its generated MCP URL. Because a third party brokers access, scope the connection tightly and review what the connector can read and write. The Metabase CLI stores its credentials securely after mb auth login.
Can you generate an Affinity dashboard with AI?
Yes. Use the prompt below with any assistant that can run the Affinity MCP server and the Metabase CLI. It works end to end: if Affinity tables already exist in Metabase it analyzes those; otherwise it pulls the data over the Affinity MCP, loads it with mb upload csv, then builds the dashboard — resolving stage per list and skipping metrics the data can't support instead of faking them.
Create a polished Metabase dashboard for Affinity deal-flow and pipeline analytics.
Work end to end: get the data into Metabase if it isn't there yet, then build.
Goal: Help partners and platform teams understand deal flow, pipeline, stage
conversion, sourcing quality, and relationship coverage from Affinity data.
Step 1 — Find or load the data:
- First, check what already exists in Metabase (search for Affinity tables and
models). If durable Affinity data is already present — synced from a warehouse
or uploaded earlier — use it and skip to Step 2.
- If nothing is there, pull it with the Affinity MCP server (scope the connection
to read-only where possible): opportunities, organizations, lists and list
entries, and interactions. Write each result to a CSV, then load it with the
Metabase CLI — run "mb upload csv --file <export>.csv" so each upload creates a
table and a ready-to-query model. Use
"mb upload replace <table-id> --file <export>.csv" to refresh an existing table
instead of creating duplicates.
Step 2 — Inspect before querying:
Affinity CSV exports are usually flat and pre-aggregated (one row per opportunity
or list entry, with columns like list, stage, amount, and source), while
warehouse tables are raw and normalized (persons, organizations, list entries,
field-value changes, interactions). Stages and statuses live in list-specific
fields, so inspect the actual tables and column names first; do not assume exact
names or a global stage set.
Important:
- Build on whatever data is present; don't claim Metabase connects natively to
Affinity — it reads a database or CLI-uploaded tables.
- Affinity is highly customizable: stages and statuses live in list-specific
fields, so resolve them per list rather than assuming a global stage set.
- For win rate, state the denominator explicitly (won / decided vs. won /
created) and hold the cohort fixed.
- Report deal size and time-in-stage as medians (p50) and p90, never plain
averages — both are right-skewed.
- Only compute time-in-stage or stage conversion when list-entry stage-change
history exists; otherwise use a caveat.
- Convert all amounts to a single reporting currency; caveat any mix.
- Only build a card if its underlying column/metric exists in the data.
- A single CSV is a point-in-time snapshot: only build trend cards if there is a
usable date column or multiple periods have been uploaded.
Dashboard title: Affinity Deal Flow Overview
Sections:
1. Executive summary (KPI cards): Open pipeline; New deals (last 90 days); Win
rate; Median deal size; Median time-in-stage; Orgs with a recent interaction.
2. Deal flow: New opportunities by source; pipeline by list and stage; stale
deals.
3. Conversion: Stage-to-stage conversion by list; win rate by source and sector.
4. Relationships: Interactions per opportunity; coverage; response time.
5. Sourcing: Sourced deals by channel; source-to-won conversion; deal size by
source.
Filters: List, Stage, Owner, Source, Date range.
Reuse the models Metabase auto-created from uploaded CSVs, or (for a warehouse)
create reusable models: modeled_affinity_opportunities,
modeled_affinity_list_entries, modeled_affinity_stage_history,
modeled_affinity_organizations, and modeled_affinity_interactions.
Output: Build the dashboard if you have permission; otherwise provide the exact
questions, SQL, model definitions, and layout. Include caveats for any metric
that cannot be calculated from the available data. Reconcile totals against
Affinity's own reporting. Keep it practical, dense, and executive-readable.How do you sync Affinity data into a database or warehouse?
For dashboards that need history and reliability, land Affinity data in a database first, then connect Metabase to that database.
Connector options
- Affinity API (raw) — the source of truth; pull persons, organizations, opportunities, lists, list entries, field values, and interactions.
- dlt (code) — write a Python pipeline against the Affinity API for full control of schema and incremental loads.
- Managed ETL (Airbyte / Fivetran) — check the connector catalogs for an Affinity source; where one exists it can land the core objects on a schedule.
- Reverse-ETL / webhooks — Affinity webhooks can stream field and list-entry changes so you don't lose transitions between syncs.
Notes
- Land raw tables first, then build clean models on top.
- Stages and statuses live in list-specific fields, not a global column — resolve them per list.
- Capture field-value history (webhooks) for time-in-stage and conversion.
- Convert opportunity amounts to a single reporting currency.
How should you model Affinity data in Metabase?
Core tables
| Table | Grain | Key columns |
|---|---|---|
opportunities | one row per opportunity | id, name, organization_id, amount, status, source, owner_id, created_at |
lists | one row per list | id, name, type |
list_entries | one row per entry on a list | id, list_id, entity_id, stage, created_at |
field_value_changes | one row per change | entity_id, field, value, changed_at |
organizations | one row per org | id, name, domain, sector |
interactions | one row per interaction | id, organization_id, type (email/meeting/call),direction, occurred_at |
Modeling advice
- Build a
modeled_affinity_opportunitiestable with cleanstatus,amount(one currency),source, andclosed_at. - Resolve stage from the relevant list's status field and normalize it into an ordered funnel.
- Derive
modeled_affinity_stage_historyfrom field-value changes for time-in-stage and velocity. - Roll auto-captured
interactionsup to organization and opportunity for coverage metrics. - Reconcile modeled pipeline against Affinity's own reports before trusting it.
Which Affinity metrics should you track in Metabase?
| Metric | Definition | Notes |
|---|---|---|
| Open pipeline | Sum of amount for active opportunities. | Segment by list, stage, owner. |
| Deal flow | New opportunities created per period. | Segment by source and sector. |
| Win rate | Won ÷ decided opportunities in a cohort. | Fix the denominator (decided vs. created) first. |
| Time-in-stage | Days an entry spends in each stage. | Needs field-value history; report median and p90. |
| Relationship coverage | Orgs with an interaction in the last N days. | Uses auto-captured interactions. |
| Sourcing conversion | Sourced → won by channel. | Read with deal size, not alone. |
What SQL powers Affinity dashboards in Metabase?
These assume the modeled tables above (PostgreSQL dialect). Adjust identifiers to match your warehouse.
The current funnel — active deals and value by list and stage.
SELECT
le.list_name,
le.stage,
COUNT(*) AS active_deals,
ROUND(SUM(o.amount), 2) AS pipeline_value
FROM modeled_affinity_list_entries le
JOIN modeled_affinity_opportunities o ON o.id = le.opportunity_id
WHERE o.status = 'active'
GROUP BY le.list_name, le.stage
ORDER BY pipeline_value DESC;Won as a share of decided opportunities, by sourcing channel.
SELECT
o.source,
COUNT(*) FILTER (WHERE o.status = 'won') AS won,
COUNT(*) FILTER (WHERE o.status IN ('won', 'passed')) AS decided,
ROUND(
100.0 * COUNT(*) FILTER (WHERE o.status = 'won')
/ NULLIF(COUNT(*) FILTER (WHERE o.status IN ('won', 'passed')), 0),
1
) AS win_rate_pct
FROM modeled_affinity_opportunities o
WHERE o.status IN ('won', 'passed')
GROUP BY o.source
ORDER BY decided DESC;Active opportunities with no logged interaction in 30 days.
-- Active opportunities with no logged interaction in the last 30 days
SELECT
o.id,
o.name,
o.owner,
MAX(i.occurred_at) AS last_interaction
FROM modeled_affinity_opportunities o
LEFT JOIN modeled_affinity_interactions i
ON i.organization_id = o.organization_id
WHERE o.status = 'active'
GROUP BY o.id, o.name, o.owner
HAVING MAX(i.occurred_at) < CURRENT_DATE - INTERVAL '30 days'
OR MAX(i.occurred_at) IS NULL
ORDER BY last_interaction NULLS FIRST;