Jepto

Pricing

Sign In

Try For Free

Analytics

You don’t need a more expensive LLM. You need a data model.

Dale McGeorge

Head of Product

circle-4circle-3circle-1circle-2

Writing the code to pull marketing data now costs roughly nothing. Getting an answer you would put in front of a client still costs plenty. What actually goes wrong when you point AI at raw marketing data, the honest set of options for fixing it, and why we spent our time on a unified data model instead of a more detailed prompt.

A number that's wrong, and nothing to catch it.

Open Claude or ChatGPT right now and ask it to write a Python script that pulls last month's spend from the Meta Ads API. You'll have working code in under a minute. Ask it to add Google Ads, LinkedIn and TikTok. Still under ten. The barrier to getting marketing data has genuinely collapsed, and that's a good thing.

Now feed all that data back in and ask a question a client would actually ask: "What was our blended cost per acquisition last month across every channel?"

You'll get a number. It will be confidently formatted, probably to two decimal places, possibly with a nice little commentary about efficiency trends. Nothing will error.

Yet there's a good chance it's wrong, because somewhere in that answer, Google's cost in micros got added to Meta's cost in dollars, or a conversion counted by Meta's 1-day-view window got stacked on top of a Google data-driven conversion, or Google Business Profile got a zero for "clicks" instead of being left out of a metric it doesn't report.

The reason this is dangerous isn't that AI makes mistakes. It's that the only person who can catch this particular mistake is someone who already knows the answer, which rather defeats the point of asking.

Data is not software

Anthropic's data team put their finger on why this happens in their write-up on self-service analytics, and it's the cleanest framing I've seen: data is not software.

When AI writes application code, the world pushes back. A compiler throws a syntax error. A test fails. A page won't load. The feedback loop is immediate and mechanical, which is exactly why coding agents have gotten so good so fast. Hallucinations get caught by the environment, not by a human reading every line.

When an AI writes an analytics query, nothing pushes back. The SQL is valid. The rows come back. The chart renders. However, there's often only one correct answer and no deterministic way to prove you got it. Anthropic named the failure mode that swallows most errors: concept-to-entity ambiguity. The model can't reliably map the words in your question to the right things in your data.

Failure modes

Code fails loudly. Analytics fails silently.

The same model, two very different safety nets.

AI writes code
  1. Generates a function
  2. Compiler checks types
  3. Test suite runs
  4. Build breaks on failure
You find out in seconds
AI writes a data query
  1. Generates valid SQL
  2. Query executes cleanly
  3. Rows come back
  4. Chart renders perfectly
You find out in the client meeting

An LLM writing application code is surrounded by guardrails. The same model writing an analytics query has none.

This is not a model problem

The tempting response is to wait it out. Models get better every few months; surely this fixes itself?

The evidence says no. In April 2026 Cube published a paired benchmark: 100 natural-language questions over a retail dataset, run against three frontier models under two conditions. In one, the model got the raw warehouse schema. In the other, it got the same schema plus a four-kilobyte markdown document describing what the measures meant. No code, no runtime, no tools. Just the document, pasted into the prompt.

Every model improved by 17 to 23 percentage points. But the far more interesting result is what happened between the models: with the definitions present, the three models became statistically indistinguishable from each other. Without them, also indistinguishable, just worse. Nearly all the variance came from whether the definitions were there. Almost none came from which model you picked.

Controlled benchmark · n=99 questions

Definitions moved accuracy. Model choice didn't.

Same questions, same harness. The only variable is whether the model was told what the metrics mean.

Schema onlySchema + semantic layer
Claude Opus 4.7
50.5%
67.7%
+17.2 pp
Claude Sonnet 4.6
46.5%
68.7%
+22.2 pp
GPT-5.4
45.5%
68.7%
+23.2 pp
21% 95%
Anthropic's internal analytics agent, before and after adding curated domain knowledge
+20 / +15 pp
Independent replications: BIRD's external-knowledge ablation and the dbt Labs paired benchmark

If your team hasn't agreed on what a conversion means, no amount of model upgrading will produce a correct answer. The gap is in the context, not the model.

Anthropic's numbers point in the same direction from a different angle. Without curated domain knowledge, their internal analytics agent didn't clear 21% on their evaluation set. With it, they run consistently above 95%. Same models. Different context.

This is the part worth sitting with if you're deciding what to build: this is an architecture decision, not a model decision. Get the definitions right and you can choose whichever model suits your budget and latency. Skip them and the most expensive model available won't save you.

Why marketing data is a worst case

Everything above applies to any type of stored business data. Marketing data is harder than most, for four specific reasons.

1. The same concept has a different name on every platform

"Spend" is the simplest metric in advertising, and no two platforms agree on how to express it. Google Ads reports metrics.cost_micros, the cost multiplied by a million, as an integer. Meta reports metrics.spend as a plain decimal. LinkedIn reports costInLocalCurrency. X reports total_spend_micro. Two of those need dividing by a million before they can be added to the other two, and one of them may not be in the currency you think it is.

An LLM handed four raw API responses has to infer all of that from field names. Sometimes it does. Sometimes it adds a micro figure to a dollar figure and reports a campaign that spent nine hundred million dollars, which at least you'd catch. The dangerous version is the one that's only slightly wrong.

One metric, six vocabularies

Every platform has its own word for “spend”

This is one row of the mapping. There are dozens more, and none of them are guessable from the field name alone.

Google Adsmetrics.cost_micros÷ 1,000,000
Meta Adsmetrics.spend
LinkedIn AdscostInLocalCurrencycurrency-dependent
Microsoft Adsspend
TikTok Adsspend
X Adstotal_spend_micro÷ 1,000,000
Governed definitionunified.spendNormalised to one currency-correct number, resolved once, identical on every surface that asks.
The decision that matters most is where to leave a gap. Google Business Profile has no concept of ad spend, so it contributes nothing to this metric — it is excluded, not zero-filled. A zero would quietly drag down every blended average you calculate.

Six platforms, six field names, two unit systems. The mapping has to live somewhere. The only question is whether it's written down or improvised per query.

2. Some platforms don't have the metric at all

Google Business Profile doesn't report a single "clicks" number. The API breaks it into separate metrics — website clicks, call clicks, and direction requests — and never rolls them into one figure. Impressions work the same way: instead of one "impressions" total, GBP splits it four ways, by surface (Search vs. Maps) and device (desktop vs. mobile). So if you want a cross-channel clicks or impressions number that includes local, someone has to decide what to sum, and then apply that decision the same way every single time.

Left to an LLM, that decision gets made fresh on each request, and differently depending on how the question was phrased.

3. Conversions from two platforms are not the same unit

This one is genuinely unsolvable by naming alone, and it's worth being blunt about. Ad platforms attribute a conversion back to the date of the ad interaction. GA4 records it on the date it actually happened. So the same purchase can land on two different days depending on which system you ask, and the further apart your click and your conversion, the worse the divergence.

Attribution windows compound it. In January 2026 Meta removed the 7-day-view and 28-day-view attribution windows entirely. Google Ads defaults to data-driven attribution. Adding those two conversion counts together produces a number, but it isn't a measurement of anything.

4. It all changes underneath you

Which brings us to the part everybody underestimates. More on that shortly.

The four options, honestly

We build one of these things for a living, so treat the following with appropriate suspicion, but I'd rather lay out the actual landscape than pretend there's one answer. There are four reasonable ways to get AI-assisted answers out of marketing data. You need to decide which one is right for you.

Build vs buy vs bolt-on

Four ways to do this, and who each one is right for

No scores here, deliberately. I build one of these for a living, so the only honest thing I can put in a table is what each arrangement actually is.

Option 1
Platform MCPs straight into a chatbot

Connect each platform's MCP server to Claude or ChatGPT and ask away.

Good for single-platform questions, ad-hoc exploration, one analyst who already knows the data fields.
Breaks on anything cross-platform, repeatability, and anyone consuming the answer who can't check it.
Definitions live
In the prompt, for one session
Maintained by
Nobody
Repeatability
Not guaranteed
Option 2
Build the whole stack in-house

Your own extraction, warehouse, transforms, semantic layer and agent harness.

Good for teams with real data engineers, unusual requirements, or where the data product is the business.
Breaks on the maintenance bill — which arrives every month, forever, and doesn't care how busy you are.
Definitions live
In your own repo, exactly as you want them
Maintained by
Your team, indefinitely
Repeatability
Yes, if you build for it
Option 3
A BI tool with a chat box added

Your existing dashboard vendor ships an AI panel over its own internal model.

Good for teams already standardized on that tool who only ever ask questions inside it.
Breaks on portability as the definitions aren't available for your day-to-day work or other tools.
Definitions live
Inside the vendor's BI tool
Maintained by
The vendor, for that tool only
Repeatability
Yes, inside that tool
Option 4
A governed model with portability

Definitions defined once, then served to every surface, including agents you don't own.

Good for agencies running many clients across many platforms who need the same answer in chat, report and analysis.
Breaks on anything genuinely bespoke as you inherit someone else's modeling decisions and roadmap.
Definitions live
In a shared model you can read and extend
Maintained by
The vendor, with your custom fields on top
Repeatability
Yes, across every surface

Jepto is Option 4. Options 1–3 can be the right answer for some situations, and I'd rather say so than pretend otherwise.

If you're a solo consultant on one ad account, Option 1 is genuinely fine.
The calculation on the right choice changes fast as the number of clients and platforms increases.

Why a stack of MCP servers isn't a data model

Option 1 deserves its own section, because it's the one most agencies are quietly trying right now and it's the one where the gap is least visible.

MCP is genuinely excellent. It solved a real problem in how an agent can gain knowledge from a system it wasn't trained on or take action on another platform. We have our own Jepto MCP server precisely because we think that's the right shape. But an MCP server is a transport. It hands the model the platform's own vocabulary, unchanged. Connect five of them and you haven't built a cross-platform model; you've given one agent five phrasebooks and asked it to negotiate a treaty.

What actually happens when you ask a five-MCP setup for blended ROAS:

  • The join happens in the context window. Raw rows from five platforms get pulled into the conversation, and the model does the arithmetic in prose. That's the least deterministic place in the entire system to perform a sum.
  • Nothing forces consistency between sessions. Ask the same question on Tuesday and you may get a different reconciliation, because nothing wrote the first one down. Cube calls this the difference between descriptive context and executable context: a description helps the agent choose, but only an executable definition makes the chosen answer correct.
  • Access rules are advisory. A permission the model is merely told about in a prompt is a permission it can reason its way around. In a governed layer, the rule is applied when the query is compiled, before any data moves.
  • It gets expensive in exactly the wrong way. Cross-platform questions mean pulling large volumes of raw rows into context on every single ask, then paying a per-token rate to have a language model add them up.
  • It fails hardest on the questions you care most about. Single-platform questions work well — the agent is just reading one system's own numbers back. The failures cluster on cross-channel questions, which are the ones clients actually ask.

Two architectures

Where does the reconciliation happen?

Both setups answer the question. Only one of them answers it the same way twice.

Raw MCPs into a chatbot
Google AdsMetaLinkedInTikTokGA4
raw rows, five vocabularies
Context window Joins, unit conversion, currency, dedupe and arithmetic — improvised per request
An answer Not necessarily the same one next time
Governed model, served over MCP
Google AdsMetaLinkedInTikTokGA4
normalised at sync time
Unified data model Mapping, units, aggregation, filters and access rules resolved before the query compiles
The answer Identical in a report, in chat, in Claude

MCP is the transport in both diagrams. The difference is what's on the other end of it.

The reconciliation has to happen somewhere. Doing it once, in code, beats doing it every time, in prose.

When code is free, maintenance is the whole bill

This is where the build-versus-buy conversation has genuinely shifted, and where we think most in-house projects go wrong in 2026.

Historically, "we'll build it ourselves" was gated by the cost of writing the extraction code. That gate is gone. AI can write a competent Meta Ads connector in an afternoon. So the project gets approved on the strength of a build estimate that is now, accurately, very small.

The problem is that the build was never the expensive part. AWS has been making this argument about infrastructure for years through its total cost of ownership framing: real TCO is direct costs plus indirect costs plus operational costs, and operational labour is a first-class line item, not a rounding error. Ownership costs are always significantly greater than acquisition costs. Marketing data just makes the ratio unusually brutal.

Amazon didn't invent this framing for the sake of a sales deck — it came out of a real operating problem they'd hit themselves. In a 2006 talk, Jeff Bezos described what he called undifferentiated heavy lifting: the estimate, at the time, was that roughly 70% of a team's time, energy, and budget went into things like racking servers, patching operating systems, and keeping infrastructure alive — work that was necessary, but did nothing to make the product better or the business more competitive. Only the remaining 30% went into the thing that actually mattered: the idea itself. AWS was built to absorb that 70%. And critically, AWS's own advice was never "always use the raw building blocks because they're cheaper" it was closer to the opposite.

Their cost-optimization guidance explicitly tells customers to default to managed services and only drop down to the raw primitives (a bare server instead of a managed database, for example) once you've either outgrown what the managed version can do, or you have a genuine, specific need to customize at a level the managed layer doesn't allow. Below that threshold, running the primitive yourself isn't more control, it's just unpaid infrastructure work with your name on it.

Total cost of ownership

The part AI made free is the thin bar at the top

Everything below it still has to be done by someone, every month, forever.

Write the extraction codeNow genuinely close to zero
Keep the connectors aliveVersion migrations, sunsets, OAuth refresh, rate limits, backoff, dev tokens
Handle schema and semantic driftRetired metrics, changed attribution windows, shortened retention, historical restatements and backfills
Build and govern the semantic layerThe mapping, the aggregations, the exclusions, the naming — and a human who owns each definition
Prove it's still rightEvals, regression tests, freshness and completeness checks, someone on call when a sync fails at 2am
Keep the documentation currentAnthropic watched their own agent's accuracy fall from ~95% to ~65% in a single month when docs weren't maintained alongside model changes

Bar widths are illustrative of effort, not measured cost. Structure follows AWS's direct / indirect / operational TCO breakdown.

Zero-cost code generation removed the top bar. It didn't touch any of the others.

Data pipelines and analytics stacks are having the exact same conversation right now, just with the "primitive" being a script instead of a server. Writing a connector to pull data out of Meta Ads is the data equivalent of provisioning a bare server: technically simple, and now, with AI, nearly instant. But it hands you the same undifferentiated heavy lifting AWS was built to remove, except this time it's schema changes, silent API deprecations, and rate-limit errors, not OS patches.

None of that work makes your reporting better or your campaigns smarter. It's the 70%. A managed data model is the "managed service" version of the same choice: someone else absorbs the maintenance, and your team's time goes into the 30% that's actually yours: the analysis, the decisions, the campaigns. The same logic AWS uses to tell you when to reach for a raw EC2 instance applies here almost exactly: build it yourself once you've outgrown what a managed connector can do, or you have a real, specific customization need. Below that line, "we built it in an afternoon" isn't really a cost saving. It's a cost you've just chosen to pay every month instead of once.

What "API maintenance" actually looked like in 2026

This isn't hypothetical, and it isn't occasional. Here's a partial list of what a marketing data system had to absorb in the first seven months of the year, considering only the bare minimum of two platforms.

Google Ads moved to a monthly release cycle in January 2026, lifting major versions from three a year to four, each supported for roughly twelve months. That sounds generous until you notice what it means in practice: a major version reaches end of life every few months, and when it does, requests simply begin to fail — no grace period, no soft degradation. v19 died on 11 February. v20 in June. v21 on 5 August. v22 is scheduled for October.

Meta's changes were subtler and, honestly, worse.

Jan – Oct 2026 · partial list

Ten months of breaking changes on two platforms

Every one of these needed a human to notice, assess and ship a fix.

12 JanMeta7-day and 28-day view-through attribution windows removed; unique and hourly breakdowns capped at 13 months, frequency at 6silent
26 JanMeta10-second video view metric retiredsilent
28 JanGoogle Adsv23 ships; monthly release cadence begins, 4 major versions per yearstructural
11 FebGoogle Adsv19 sunset — all v19 requests begin to failbreaking
18 FebMetaMarketing API v25.0; Advantage+ campaign creation blocked on legacy endpointsbreaking
22 AprGoogle Adsv24 major releasemigration
JunGoogle Adsv20 end of lifebreaking
9 JunMetaAll Marketing API versions before v24.0 deprecatedbreaking
29 JulMetav26.0: 47 commerce endpoints blocked with no replacement; delivery-estimate fields removed; placements retiredbreaking
5 AugGoogle Adsv21 sunsetbreaking
27 OctMetav26.0 deprecations extend to every remaining supported versionbreaking
OctGoogle Adsv22 end of lifebreaking
Breaking — your pipeline stops. You find out fast.Silent — your pipeline keeps running. The numbers change meaning.

The dangerous API changes aren't the ones that break your analytics setup. It's the ones that don't.

Look again at the two entries marked silent. When Meta removed the 28-day view-through window, nothing failed. Your sync ran. Your dashboard rendered. Your year-on-year comparison quietly started comparing two different definitions of a conversion, and your client's ROAS trend developed a step change that nobody could explain because nobody was looking at a Meta changelog.

A breaking change is a ticket. A silent semantic change is a credibility problem six weeks later, in a meeting.

And at the end of all that, you have data, not answers

Here's the part that catches teams who do successfully build the pipeline: you're now roughly where you started this article. You have clean rows in a warehouse and an LLM that still doesn't know what your agency means by a qualified lead.

The obvious shortcut is to have the AI generate the semantic layer too. Anthropic tried exactly that, bootstrapping metric definitions from raw tables and query logs, and reported that it produced plausible-looking definitions that encoded the very ambiguities they were trying to eliminate, and scored worse on their evaluations than a smaller, human-curated layer. Their conclusion: generate the documentation with AI, but have a human own the definition.

That's the sentence we'd underline for anyone scoping an in-house build. The valuable artifact is a set of human decisions, and AI can't make those for you. It can only help you write them down faster.

What we built, and why it's shaped like this

The Jepto Data Model is our answer: a governed catalog of every metric and dimension available for a client, in three layers.

Anatomy

Three layers, one catalogue

Every report, chat answer and agent query resolves against the same list.

01
Source fields

Each platform's own metrics and dimensions, labelled the way the platform's own UI labels them, with a stable key underneath.

googleAds.clicksfacebookAds.campaignNamegoogleAnalytics4.sessions
Use when you need a platform's own definition, or a metric only it reports.
02
Unified fields

Shared concepts mapped across every connected platform — spend, impressions, clicks, CTR, CPC, conversions, ROAS, campaign, device, date.

unified.spendunified.conversionsunified.campaignName
Use for anything cross-channel. Appears automatically once a client has more than one source connected.
03
Custom fields

Your agency's own definitions, written once as a formula, with their own aggregation and number format. Switch on Enable for All Clients and every client inherits it.

custom.blendedPaidSpendcustom.qualifiedLeadRate
Use when your definition of a metric is the thing that makes your reporting yours.

Source fields for depth, unified fields for breadth, custom fields for the definitions that are specifically yours.

A few decisions inside that are worth calling out, because they're the ones that took the longest to get right.

Labels speak marketing, keys speak machine. Every field carries a human label matching the language you'd see in Ads Manager, and a stable key like googleAds.clicks underneath. You pick by label; cards and agents resolve by key. That separation is what lets us change how a metric is computed without breaking every report that uses it.

Aggregation lives on the field, not the chart. How a metric rolls up: sum, average, count distinct is a property of the metric itself. It's the kind of thing that seems fussy until you've seen an averaged rate metric summed across a hundred campaigns.

Missing means excluded, not zero. If a platform doesn't report a concept, it contributes nothing rather than a zero. Google Business Profile isn't in the spend total. It's a small decision that keeps blended averages honest.

Definitions are account-wide by default when you want them to be. A custom field created under All Clients is available to every client, so the definition of "blended paid spend" is written once and can't drift between the report your senior strategist built and the one a new starter built last week.

No formulas created in a chart or report. This one's a deliberate restriction, not a missing feature. Tools like Data Studio let you build a formula inside a single chart, and it's tempting to leave that door open for flexibility. But a formula built inside a chart lives and dies with that chart. Nnobody can find it to fix it, reuse it, or even know it exists, so the same "ROAS" gets rebuilt from scratch in the next report, each one a slightly different guess at what the last person meant.

The second trust problem: nobody can read the SQL

Suppose the AI gets it right. There's still a question sitting underneath, and it's the one that comes up every time an agency starts letting AI near client reporting: how would you prove it?

The stock answer is "show the SQL." Most tools now do a little expandable panel under the chart with the generated query in it. It looks like transparency. In practice it's theatre, because the person who most needs to check the number is an account manager or a client, and they cannot read SQL. Neither can most senior strategists, and there's nothing wrong with that; it isn't their job.

Even for people who can read it, the format works against them. OpenAI made this point vividly by publishing one of their own analysts' queries, a 180-line statement with the note that it isn't easy to tell whether you're joining the right tables and querying the right columns. Anthropic put the structural version of the same problem plainly: the end user of the data model is now an agent acting for someone who isn't a data expert, so the result can't require the user to validate the underlying correctness, because the user doesn't know how.

That's the audit problem. An audit trail nobody can audit is just a longer receipt.

What an auditable request looks like

The alternative is to make the request itself the artifact, not the SQL it compiles into. In Jepto, every chart and table stores a data query, the saved recipe behind the card, visible in a Query tab beside the preview. It's declarative: it says what you're asking for, not how to fetch it. There are no joins in it, no unit conversions, no grain decisions, no timezone handling. All of that lives in the data model, resolved once, the same way for everyone.

Which means the thing you check is short enough to check.

Auditability

Same question. One version you can check.

“Spend and conversions by campaign across Google Ads and Meta, last 30 days, Brand campaigns only, top 10 by spend, compared to the previous period.”

Generated SQL
WITH g AS (
  SELECT campaign_name,
         SUM(cost_micros)/1000000 AS spend,
         SUM(conversions)         AS conv
  FROM   google_ads_campaign_daily
  WHERE  segments_date BETWEEN @from AND @to
  GROUP  BY 1
), m AS (
  SELECT campaign_name,
         SUM(spend)       AS spend,
         SUM(conversions) AS conv
  FROM   meta_ads_insights
  WHERE  date_start BETWEEN @from AND @to
  GROUP  BY 1
)
SELECT COALESCE(g.campaign_name, m.campaign_name) AS campaign,
       COALESCE(g.spend,0) + COALESCE(m.spend,0)  AS spend,
       COALESCE(g.conv, 0) + COALESCE(m.conv, 0)  AS conv
FROM   g FULL OUTER JOIN m USING (campaign_name)
WHERE  campaign_name LIKE '%Brand%'
ORDER  BY spend DESC
LIMIT  10;
Three things are wrong here. None of them will throw an error.
  • The two conv columns are added together despite being counted under different attribution models
  • campaign_name is the join key, so a Google campaign and a Meta campaign sharing a name silently merge into one row
  • Each date filter resolves in its own platform's reporting timezone, so “last 30 days” isn't the same 30 days
Jepto Data Query
{
  "metrics": [
    { "field": "unified.spend",       "aggregation": "sum" },
    { "field": "unified.conversions", "aggregation": "sum" }
  ],
  "dimensions": [
    "unified.source",
    "unified.campaignName"
  ],
  "timeDimension": {
    "field":       "unified.date",
    "dateRange":   "last30days",
    "granularity": "day"
  },
  "filters": [
    { "field":    "unified.campaignName",
      "operator": "contains",
      "values":   ["Brand"] }
  ],
  "comparison": "previousPeriod",
  "order":      { "unified.spend": "desc" },
  "limit":      10
}
An account manager can check every line of this.
  • Joins, grain, currency, and timezone aren't here because they were defined once, in the data model
  • Two cards with an identical data query always return identical numbers, so there is no more “why don't these match?” investigations.
  • When AI creates a chart, this is what you can review, not a wall of SQL
Six decisions, all visibleWhat to measureHow to break it downWhich periodWhat to includeHow to compareHow to order

SQL shown is illustrative of the shape, not generated by any one tool

The left panel is honest about what it did. It just isn't legible to the person who has to sign off on the number.

Two properties of this fall out for free, and both matter more than they sound.

Disagreements become diffs. Because identical queries always produce identical numbers, "these two reports don't match" stops being a forensic exercise. You open both Query tabs and look at what's different — a stray filter, a different date range, a source-specific field where a unified one was intended. It's usually a thirty-second job.

AI output gets reviewed at the right altitude. When you describe a chart in plain language and let AI build it, the thing you check afterwards is the query, not the SQL. That's a review a marketer can actually perform. Our own docs are blunt about this: AI drafts are a starting point, and the Data tab is the source of truth.

Worth saying plainly, though: readable is not the same as right. A data query being legible doesn't mean someone read it. It just removes the excuse that nobody could.

Write once, use anywhere

Here's the part we care most about, and it's the reason the data model is deliberately decoupled from any one interface.

Historically, semantic models lived inside a BI tool. If you wanted the logic, you used that tool. Cube puts the objection well: a context layer that ships as a feature of a single BI tool wraps trust around a seat you're already locked into. Anthropic reached the same conclusion internally, their rule is that the same knowledge must produce the same answer in Slack, in the IDE, in a dashboard tool. Which is the same rule that we have adopted.

Three organizations with unlimited engineering resources, solving this independently, and all three landed on the same shape: one governed core, many front doors.

Portability

Govern it once. Consume it wherever you work.

Same catalogue, same maths, six front doors.

Unified Data Modelmetrics · dimensions · formulas · aggregations
In Jepto
Report cards Charts and tables built from the field picker
AI report building Describe a chart in plain language; it resolves to real field keys
Data Chat Conversational analysis with client context attached
Outside Jepto
External Claude & ChatGPT Via the Jepto MCP server — your definitions, their interface
External External data Add your own custom data sources and query them in place through schema you define.
External Data Warehouse Whether you use our Pipelines or BigQuery directly, we query it directly without copying.
Ask the same question in any of these and the arithmetic underneath is identical.

The practical version for an agency: a strategist can build a client dashboard in the report editor, a junior can ask Data Chat what happened to cost per lead last week, and you can point Claude at the MCP server to diagnose a sudden performance drop at eleven o'clock at night, and all three are reading the same definition of cost per lead. Nobody has to reconcile anything, because there was never more than one number.

What a data model can't do

It would be a poor learning piece if we stopped at the good bits. Four honest limits.

It can't decide what you mean. A semantic layer records a decision; it doesn't make one. If your agency hasn't agreed whether a lead form submission counts as a conversion, the model will faithfully encode whichever answer you type into it. That conversation is still yours to have, and it's the highest-leverage hour you'll spend on reporting all year.

Normalizing names doesn't reconcile attribution. We can make Google's and Meta's spend directly comparable, because money is money. We cannot make their conversions the same unit, because they're measured with different windows and different models. Blended ROAS is a useful directional number and a bad forensic one, and any tool that tells you otherwise is selling.

Bad inputs stay bad. Inconsistent UTM tagging, conversion actions counting the same event twice, or a GA4 property with a broken key event. A governed layer makes those failures more visible, not less real.

It doesn't remove the human check. Anthropic runs adversarial review, provenance footers and daily sanity checks against internal dashboards, and still describes silent wrong answers as the failure mode they haven't fully solved. Anyone claiming they have is not being straight with you. Read anything before it goes to a client.

Five questions worth asking any AI analytics tool, including ours

  1. Where is "spend" defined, and can I read the definition without opening a support ticket?
  2. Can I see the actual query the AI ran to produce this number?
  3. Can I define a metric once and have every client, report and chat session use it?
  4. If I ask the same question in a report, in your chat, and in Claude, do I get the same number?
  5. When Meta retires a metric next quarter, who migrates it, and how will I find out?

You don't need to reinvent the wheel

The AI wave didn't make data engineering less important. It made it the whole game. An agent is only as good as the structure you hand it, and the benchmark evidence is unusually consistent on this point: the definitions move accuracy far more than the model does.

What hasn't changed is which part is worth your time. Writing the extraction script used to be the hard bit, and it's now nearly free, which is precisely why it's not an advantage. The advantage is in the decisions: what your agency counts as a conversion for optimization, how you blend paid channels, which metrics you'll defend in a client meeting. Those are yours, they're worth writing down carefully, and no model will generate them for you.

The plumbing underneath them is a solved problem. There are already solutions that maintain it, monitor the sunset calendar, and migrate field names when Meta changes its mind. That doesn't have to be you.

Own your definitions. Rent the pipes.

Want to get into the detail? The Data Model and Unified Fields docs list every field mapping we use, platform by platform, including the gaps.

Was this post useful?
Nice one!

Thanks a lot for your feedback! If you’d like a member of our support team to respond to you, please send a message here

Please try again

Oops! Something went wrong while submitting the form.