The Datacompany AI connector
Ask your own marketing attribution and ad spend directly, in Claude or ChatGPT.
Datacompany builds a marketing-mix model on your own advertising, analytics and CRM data, and reports what each channel actually contributed. The AI connector puts those numbers inside the assistant you already use, so you can ask a follow-up question instead of exporting a dashboard.
Technically it is a remote Model Context Protocol server. It
speaks streamable HTTP over HTTPS at
https://app.datacompany.nl/mcp, and every user signs in with their own
Datacompany account over OAuth 2.1. There is no API key to paste and no
shared secret to pass around.
Before you connect
You need a Datacompany account in an organisation that has at least one completed model run. If your data sources are still syncing, the connector will answer honestly that there is no model yet rather than make something up.
Connect Claude
Open the add-connector dialog in Claude. The name and URL are filled in for you; review them, confirm, and Claude sends you to Datacompany to sign in and approve. That link works on Claude for web and the desktop app.
To do it by hand instead: in Claude, open Settings, then Connectors, then
Add custom connector, and enter https://app.datacompany.nl/mcp.
Connect ChatGPT
- In ChatGPT on the web, open Settings, then Apps, then Advanced settings, and turn on Developer mode.
- Still in Settings, open Connectors and choose Create.
- Paste the connector URL above, choose OAuth as the sign-in method, and confirm.
- ChatGPT sends you here to sign in and approve the connection.
Custom connectors are still a beta at OpenAI: web only, and on a Business or Enterprise workspace an admin has to allow them first.
Connect Claude Code or your own scripts
Run claude mcp add --transport http datacompany https://app.datacompany.nl/mcp
and sign in when prompted. For clients that send their own Authorization
header, create an organisation API token under Settings, then AI
connectors, in the Datacompany app.
What a connected assistant can read
- Spend and platform metrics
- Daily cost, clicks and impressions per channel, campaign and country.
- Conversions and value
- Conversions per goal, and the margin behind them in euros.
- Attribution results
- Attributed conversions, margin and profit per channel from your latest model run, with confidence intervals and evidence strength.
- Model and data health
- When the model last trained, how well it fits, and how fresh each connected source is.
What it cannot do
- Change or delete anything. Every tool is read-only.
- See another organisation's data, on any request.
- Read your chats, files or anything else in the assistant.
Access is scoped to the organisation of the account that approved it, on every single request, and it is enforced in the database as well as in the application. You can see every connected assistant and disconnect any of them yourself, at any time, under Settings, then AI connectors.
Tools
Every tool is read-only and is annotated as such, so an assistant does not have to ask you to confirm each call.
| Tool | Name | What it returns |
|---|---|---|
| Fetch entity metrics | fetch |
Fetch latest-month attribution metrics for one entity found via the search tool. 'id' looks like 'channel:Google Ads', 'campaign:<name>', 'goal:<name>' or 'country:<name>'. |
| Attribution detail | get_attribution_detail |
Attribution rows at (channel, sub_channel, strategy, goal) grain for a period ('YYYY-MM' or 'YYYY-Www'; empty = the latest month with data), including HOW each number was produced: attribution_method (mmm/last_click/blended/ experiment), evidence_strength (high/medium/low), confidence interval bounds, and the underlying component estimates (mmm/last_click/experiment/mta conversions). Use this to answer 'how confident is this number and where does it come from'. Optional exact-match filters. Max 500 rows, sorted by margin. |
| Channel breakdown | get_channel_breakdown |
Per-channel spend, attributed conversions, margin (EUR), ROAS, CPA, POAS for a period ('YYYY-MM' or 'YYYY-Www'; empty = the latest month with data), each with percent change vs the previous period. Sorted by margin desc. Paid channels also carry 'platform_reported': the spend, clicks, impressions, cpc_eur and conversion count the ad platform itself claimed for the same days. That is a second, independent measurement. Quote them separately and never build one ratio from both — for a deeper cut of the platform figures alone, use get_media_performance. 'platform_reported' is null for unpaid channels (Organic Search, Brand, Direct, Email and the organic social ones). That means there is no ad platform behind the channel, not that a platform reported nothing — those channels have no cost by definition. Do not read it as a data gap. The two conversion counts routinely disagree, and the direction is not fixed: measured on one customer's August, Google Ads claimed 140 where the model attributed 168, while Meta claimed 0 against the model's 15 (its conversion tracking reports nothing). Treat a gap as the finding, not as one side being broken. Channels with spend but no attributed result (a channel the model has not been fit on, or one excluded from the run) appear under 'channels_without_attribution' rather than being dropped. An organization with ad spend but no completed model run still gets the platform figures, with reason_code NO_MODEL_RUN. |
| Country summary | get_country_summary |
Per-country monthly performance (attributed conversions, spend, margin in EUR) with MoM and YoY deltas. 'month' is 'YYYY-MM'; empty = latest month with data. Sorted by conversions desc. |
| Data freshness | get_data_freshness |
Is the data current? Per-connection last sync time, sync errors, how far each source's data actually runs, and how far attribution has been modelled. Call when a recent period looks wrong or empty before concluding performance dropped. |
| Data overview | get_data_overview |
What data exists for this organization, and the defaults every other tool falls back to. Use it when the available range, channel names, goal names or countries are not yet known. Returns: the available date range, channels, conversion goals, countries (and which are excluded from the model), the latest completed model run, and the latest complete week/month to use as defaults in other tools. All monetary values are EUR. |
| Media performance | get_media_performance |
Platform-reported paid media performance for a date range, across Google Ads, Meta, Microsoft Ads and LinkedIn. This is what the ad platforms themselves reported: spend, impressions, clicks, ctr_pct, cpc_eur, cpm_eur and platform_conversions. Use it for "what is my CPC on LinkedIn", "which Meta campaigns have the worst CTR", "which campaigns cost money and converted nothing", and for comparing markets or channels on cost. It is NOT attribution. Platform conversions are each platform's own claim, counted in its own window, so they overlap between channels and are larger than the business's real total. There is deliberately no cost-per-conversion field here for that reason: dividing spend by a platform's self-reported conversions produces a CPA that is too cheap and too flattering. For CPA, ROAS and which channel actually caused what, call get_channel_breakdown — it answers from the model. Read 'totals' for the totals of everything that matched; never sum the returned rows, which are capped at 'limit' ('meta.truncation' says when rows were dropped). 'group_counts' splits matching rows by whether they spent anything — paused campaigns keep reporting zeros, so a raw row count overstates activity. Reach and frequency are Meta-only. Google Ads, Microsoft Ads and LinkedIn report no reach at all, so those rows come back null, which means "not reported" and not zero. Never total reach across channels, and treat a multi-day reach figure as an upper bound. Parameters: start_date, end_date YYYY-MM-DD. Default: the last 30 days. A date this cannot parse is an error, not a silent fall back to the default. group_by channel (default), account, campaign, country, region or month. 'account' and 'campaign' are grouped within channel, so a name reused on two platforms stays two rows. 'region' is grouped within country. channel Exact channel name from the spend data ("Google Ads", "Meta Ads"). These are not always the names the attribution tools use; an unknown one is an error listing both vocabularies. account_name, campaign_name Substring, case-insensitive. country Exact country name. min_spend_eur Minimum spend per group. Combine with only_without_conversions for the shortlist worth acting on. only_without_conversions Keep only groups the platform itself reports zero conversions for. Because the platform is generous to itself, a zero here is strong evidence of a real zero. sort spend (default), cpc, cpm, ctr, clicks, impressions or platform_conversions. Descending; groups whose ratio has no denominator sort last. compare_to_previous Add prev_* fields and change percentages from the preceding window of equal length, for "is this getting worse". limit 1-200. Default 50. |
| Model health | get_mmm_model_info |
Health and provenance of the marketing-mix model: latest training run (method, data window, review status), fit metrics (MAPE, R², RMSE where available), per-channel blend weights (how MMM / last-click / experiment / MTA are mixed), and the distribution of evidence strength across current attribution rows. Use when asked how reliable the attribution is or when the model last trained. |
| Monthly summary | get_monthly_summary |
Monthly marketing performance with month-over-month and year-over-year deltas, per-channel breakdown, and (when no country filter is set) a per-country breakdown. 'month' is 'YYYY-MM'; empty = latest month with data. All monetary values EUR. |
| Data schema | get_schema |
Table-level schema of the underlying attribution data, as plain text. Useful to understand what dimensions and measures exist before deciding which reporting tool to call. |
| Search term analysis | get_search_term_analysis |
Google Ads search terms for a date range, aggregated per query. Rows are (search_term x campaign x account) and carry: clicks, impressions, ctr_pct, spend_eur, cpc_eur, conversions, cpa_eur (both null when the denominator is zero). Use it to find wasted spend, which queries actually convert, and long-tail opportunities. Google Ads only — not Meta, LinkedIn or Bing. For "is this getting more expensive", cpc_eur is the direct answer; cpa_eur also moves when conversions change, which is a different question. Quote both. Read 'totals' for the real totals of everything that matched. Never sum 'search_terms' to get a total: it is capped at 'limit' and 'meta.truncation' tells you when rows were dropped. Most search terms cost nothing — they only ever drew impressions. 'term_counts' gives four numbers, and they answer different questions: 'matching' counts rows at (term x campaign x account) grain, 'distinct_search_terms' counts unique query strings, and 'with_spend' / 'without_spend' split rows by whether they cost anything. Voys NL in August was 9,863 rows over 9,137 distinct terms, of which only 700 rows spent money. Say which one you are quoting: "9,137 search terms" implies far more activity than the 700 that cost anything. Search terms never cover all Google Ads spend (Google withholds low-volume queries; Performance Max, Display and YouTube report none). A SEARCH_TERMS_PARTIAL_SPEND advisory gives the real percentage — quote it rather than implying this is total spend. Keyword and match type (BROAD/PHRASE/EXACT) are NOT available: the Windsor.ai ingest rejects both fields, so this tool cannot answer match-type questions. Say so rather than guessing. Parameters: start_date, end_date YYYY-MM-DD. Default: the last 30 days. A date this cannot parse is an error, not a silent fall back to the default. account_name Substring, case-insensitive. Prefer this over campaign_name for per-country questions: campaign names collide ("NL" also matches "BENL - VoIP"), account names do not. campaign_name Substring, case-insensitive. min_clicks Minimum clicks per term. Default 1. min_spend_eur Minimum spend per term. Combine with only_without_conversions for the list actually worth acting on: most zero-conversion terms cost nothing. only_without_conversions Keep only terms with zero conversions — the negative-keyword shortlist. sort spend (default), cpa, clicks, conversions or impressions. Descending. 'cpa' puts terms without conversions last. compare_to_previous Add prev_* fields and spend_change_pct from the preceding window of equal length, for "is this getting worse". limit 1-200. Default 50. |
| Top campaigns | get_top_campaigns |
Top campaigns ranked by ROAS (attributed margin / spend) for a period ('YYYY-MM' or 'YYYY-Www'; empty = the latest month with data), with MoM ROAS/margin deltas. Only campaigns with spend > 0 are ranked. 'limit' max 100. |
| Weekly summary | get_weekly_summary |
Weekly marketing performance: totals and per-channel attributed conversions, margin (EUR), profit, spend, ROAS/CPA/POAS. 'week' accepts 'YYYY-Www' or an ISO date inside the week; empty = the latest week with data. Optional 'country' filter (use values from get_data_overview). Numbers come from the latest model run. |
| Search marketing entities | search |
Search this organization's marketing entities (channels, campaigns, goals, countries) by name. Returns result ids that can be passed to the fetch tool. Prefer the specific reporting tools (get_weekly_summary etc.) when you already know what you need. |
Questions worth asking
- Which channels made the most profit last month, and how sure is the model?
- If my budget stays flat next month, where should I move spend?
- Conversions dropped last week. Is that real, or is a data source behind?
Data handling and support
The connector reads the data your organisation has already connected to Datacompany and returns it to the assistant you approved. It cannot read your conversations, your files or anything else inside the assistant. We do keep an audit trail of which tool was called, by whom, and with which parameters, so that you can see how the connector has been used; we do not store your conversation. See our Privacy Policy and Terms of Service for the full picture.
Something not working, or a question this page does not answer? Mail jeroen@datacompany.nl.