← Back to TrailMap

Analysis You Can Audit

A whitepaper on deterministic paid-media analytics with an LLM judgment layer

For marketing directors, agency principals, and heads of growth evaluating analytics and AI tooling.

1. Executive summary

Most paid-media reporting produces charts. It does not produce decisions. A director opens a dashboard, sees that cost per acquisition is up 14% month over month, and still has to do the actual work: figure out why, decide what to change, and defend that decision to a client or a CFO. The chart was the easy part.

A wave of "AI insights" products promised to close that gap. Most close it by pointing a general-purpose chatbot at a spreadsheet and asking it to summarize. That approach has a disqualifying failure mode for anyone spending real money: language models are next-token predictors, not calculators. Ask one to compute a blended ROAS across nine campaigns and it returns a plausible-looking number that is frequently wrong, with no way for you to tell which numbers are real and which were invented. In paid media, a confidently hallucinated CPA is worse than no analysis at all.

TrailMap is built on a different premise. Every number is computed in code by a deterministic analysis engine. The language model never touches arithmetic. The engine ingests your data from six platforms (Google Ads, Microsoft Ads, Meta, LinkedIn Ads, TikTok Ads, and OpenAI Ads, meaning ads inside ChatGPT) by report-file upload or by official API connector, normalizes it all into one canonical schema, and computes the full battery of paid-media diagnostics: CPA, CPL, ROAS, CTR, CVR, and CPC trends; impression-share loss decomposed into budget-limited versus rank-limited; search-term waste with negative-keyword theme mining; Quality Score and match-type distribution; creative fatigue and concentration; ad-set budget fragmentation below learning thresholds; robust-statistics anomaly detection; and cross-channel reallocation candidates. Two newer enterprise connectors, in beta, SA360 (Search Ads 360, cross-engine paid search) and DV360 (Display & Video 360, TrailMap's first programmatic display/video channel) extend that same engine to larger and holdco-scale accounts. A third addition, also in beta, is GA4, which is not a seventh platform but a read-only conversion cross-check: it pulls the conversions Google Analytics has already attributed to a paid channel, so TrailMap can show what a platform claims next to what GA4 credits it.

TrailMap's analyst AI, purpose-built for paid media, is given a closed set of these pre-computed findings and asked to do only what it is genuinely good at: prioritize them, explain the mechanism behind each like a senior analyst would, and write specific next actions with effort and impact ratings. It is architecturally prevented from doing math. Every figure it may reference exists verbatim in the findings payload, its output is schema-validated, and a numeric-fidelity check rejects any response citing a number not present in that payload. If the analyst AI is unavailable, the full dashboard still renders from the deterministic findings alone.

The result is analysis you can audit. Every number traces to a cell in your export, while the narrative on top reads like it came from an experienced strategist, because prioritization and explanation are language tasks. This document explains how that split works, what the engine computes, how recommendations are generated, how your data is handled, and, candidly, what the product does not yet do.

2. The problem: reporting theater

Charts are not decisions

Walk into most paid-media reviews and you will find a deck of line charts, a few red and green arrows, and a table of week-over-week deltas. This is reporting theater: the appearance of insight, performing the motions of analysis without doing the work analysis is for. The charts describe what happened. They do not tell you why it happened, which of the twelve things that moved actually matters, or what to do on Monday.

The reason is structural. Native platform interfaces and BI dashboards are optimized to display metrics, not to reason about them. A dashboard can show you that impression share fell. It will not tell you whether you lost that share because you ran out of budget (raise the budget) or because your rank was too low (fix Quality Score or bids), a distinction with opposite prescriptions that most reports never surface. It can show a campaign's CTR sliding. It will not connect that slide to a rising ad frequency and flag it as creative fatigue with a refresh recommendation.

Closing that gap has, until now, meant paying for it: a senior analyst or an agency retainer, someone with the pattern library in their head who can look at the same charts and say "the branded campaign is budget-capped and you're leaving conversions on the table." That expertise is expensive, inconsistent between people, and does not scale across a portfolio of accounts.

Why "ChatGPT-wrapper" analytics can't be trusted with arithmetic

The obvious modern move is to hand the spreadsheet to a large language model and ask for the analysis. A great deal of tooling launched in the last two years does exactly this, and for buyers who have been burned, the failure mode is familiar.

Language models are trained to predict the most likely next token given the preceding text. That objective makes them extraordinary at fluent prose, summarization, classification, and explanation. It also means that when you ask one to calculate to sum a spend column, divide cost by conversions, weight a ROAS across campaigns, it does not run arithmetic. It generates the most statistically plausible-looking sequence of digits. Often that sequence is correct. Frequently, especially across many rows or several steps of aggregation, it is not. And critically, the wrong answer arrives with exactly the same confident tone as the right one. There is no uncertainty marker, no way to tell from the output which figures are real.

For an internal blog draft, a hallucinated statistic is embarrassing. For a media account, it is a decision made on a fabricated number. If a tool tells you a campaign's CPL is $42 when it is actually $68, and you scale that campaign on the tool's recommendation, the tool just cost you money and handed you a citation-shaped object to justify it. The claims are also unverifiable: the model cannot show its work, because there was no work: no formula, no intermediate values, nothing to trace back to a source cell.

Smart buyers have internalized this. The question they now ask any "AI analytics" vendor is the correct one: which numbers in your output are computed, and which are generated? If the honest answer is "the model does the math," the tool cannot be trusted with a budget. TrailMap's entire architecture exists to make the honest answer: the model does none of the math.

3. The TrailMap architecture

Two components, one hard boundary

TrailMap is two systems with a strict contract between them.

The deterministic analysis engine is ordinary, testable, reproducible code. It parses exports, normalizes them, and computes every metric and every finding. Run it twice on the same upload and you get byte-identical results. No language model is involved at this stage, so nothing varies between runs: the output is arithmetic and well-understood statistics. This is where all numbers come from, without exception.

The LLM judgment layer receives the engine's output as a structured findings payload and produces prose: it ranks the findings by importance for this specific business, explains the mechanism behind each, and drafts concrete next actions. It is handed numbers; it never derives them.

Two ways in, one schema

Data reaches the engine two ways, and the engine cannot tell them apart. You can upload the report files you already pull (CSV, XLSX, or legacy UTF-16) or connect the platform's official API and sync directly. Both routes land in the same CanonicalRow schema, so a connector sync produces normalized datasets that appear in the run builder next to uploaded files and analyze identically. Connectors cover all six platforms (Google Ads, Microsoft Ads, Meta, LinkedIn Ads, TikTok Ads, and OpenAI Ads) plus, in beta, two enterprise connectors: SA360 (Search Ads 360) and DV360 (Display & Video 360). Setup is OAuth or token credentials pasted once on a Connections screen (encrypted at rest, see §6); a one-click sync pulls the last 90 days, with the same parsing fidelity as uploads, so a privacy-clamped impression share arrives as a bound rather than a fabricated point estimate. A connected account can also be set to refresh itself daily or weekly, optionally running a full analysis on the fresh data and emailing the report when it completes. A fourth connector, GA4, also in beta, connects the identical OAuth way but is not an ad platform: it carries no spend, and its rows are never merged into the CanonicalRow totals it cross-checks against.

          ┌────────────────────────────────────────────────────────────┐
          │  Six platforms: Google Ads · Microsoft Ads · Meta ·        │
          │  LinkedIn Ads · TikTok Ads · OpenAI Ads (ChatGPT)          │
          │  + enterprise (beta): SA360 · DV360                        │
          │                                                            │
          │  CSV / XLSX upload  OR  official API connector (OAuth)     │
          │  generic column mapper for anything else                   │
          └──────────────────────────────┬─────────────────────────────┘
                                         │
                                         ▼
          ┌────────────────────────────────────────────────────────────┐
          │  INGESTION                                                 │
          │  decode → sniff headers → platform parsers → CanonicalRow  │
          │  (API sync writes the SAME CanonicalRow as uploads)        │
          │  money = integer micros · '--' = not reported (not 0)      │
          │  bounded values kept as bounds · per-upload issue ledger   │
          └──────────────────────────────┬─────────────────────────────┘
                                         │
                                         ▼
   ╔══════════════════════════════════════════════════════════════════════════╗
   ║  DETERMINISTIC ANALYSIS ENGINE            (all math lives here)          ║
   ║                                                                          ║
   ║  CPA/CPL/ROAS/CTR/CVR/CPC trends · impression-share decomposition        ║
   ║  search-term waste + negative-keyword themes · Quality Score / match     ║
   ║  creative fatigue & concentration · budget fragmentation                 ║
   ║  spend concentration · robust anomaly detection (median/MAD)             ║
   ║  period-over-period trends · cross-channel reallocation candidates       ║
   ║                                                                          ║
   ║  OUTPUT: a structured FINDINGS PAYLOAD — every number, verbatim          ║
   ╚═════════════════════════════════════╤════════════════════════════════════╝
                                         │
                 findings payload ───────┤────── renders dashboard directly
                (the ONLY numbers        │       (works even if the AI is down)
                 the model ever sees)    │
                                         ▼
   ┌──────────────────────────────────────────────────────────────────────────┐
   │  SENIOR ANALYST AGENTIC AI                (judgment lives here)          │
   │  JUDGMENT & PROSE ONLY — no arithmetic, ever                             │
   │  · prioritize findings for THIS business                                 │
   │  · explain the "why" like a senior analyst                               │
   │  · write next actions with effort / impact ratings                       │
   │                                                                          │
   │  GUARDRAILS:  schema-validated output                                    │
   │               numeric-fidelity check → flag any figure not in the        │
   │               findings payload                                           │
   └─────────────────────────────────────┬────────────────────────────────────┘
                                         │
                                         ▼
          ┌────────────────────────────────────────────────────────────┐
          │  Interactive dashboard  +  single-file HTML report export  │
          │  (identical renderer; white-labeled per tenant)            │
          └────────────────────────────────────────────────────────────┘

Ingesting large accounts

Both routes are built so that account size is a property of the data, not a limit on the product. Neither route holds a whole dataset in memory, and neither is gated by tier.

Connector syncs page, absorb, and resume. A sync pulls in bounded pages of 10,000 rows rather than requesting a report whole, so peak memory is a page, not an account. Where a platform reports rate-limit pressure, the connector reads the platform's own usage headers and paces itself before being rejected, then honors the platform's stated wait rather than guessing at a backoff, so a rate limit slows a sync down instead of ending it. Requests that a date range cannot help are handled as such: some platform reports carry no date dimension at all, so narrowing the range does nothing, and the connector stops narrowing instead of retrying its way into failure. Every completed window is checkpointed to staging, so a sync interrupted at hour two resumes from where it stopped rather than starting over. Checkpoints expire after 24 hours, deliberately, since stitching a window read today onto one read days ago would join data across a platform's own conversion restatements.

Uploads stream end to end. Parsing formerly held the file in memory several times over, roughly 4 KB of RAM per row, which is how a 21 MB export could exhaust a server. The ingest path now streams: the request body is written to disk in chunks, parsed in batches, and written out as Parquet row groups, so peak memory is one batch rather than one file. Measured on a 160 MB, 2,000,000-row file: 169 MB of peak memory, against roughly 2 GB before. Memory no longer grows with file size at all.

The honest limits that remain:

  • Upload, per file: 100 MB. Every paid tier, identically. 25 MB on the free trial.
  • Connector sync: no per-file limit. Streams in pages, resumable, runs in the background.
  • Per report, per sync: 2,000,000 rows. A very wide date range on a very large account may need splitting.
  • Account size: not limited, and not tier-gated. Pricing meters analysis runs, not rows or spend.

The upload ceiling is a property of upload parsing running inside the web request, not of memory, so raising it means moving that parse to the background worker first. Until then it is 100 MB on every paid tier, and a large or ongoing account belongs on a connector rather than a file.

The numeric-fidelity guarantee, in plain terms

Three mechanisms, layered, enforce the boundary.

First, the model only ever sees pre-computed numbers. The prompt it receives is the findings payload, a structured object where every metric, delta, threshold, and dollar figure has already been calculated by the engine. The model is not shown the raw export and asked to crunch it. It is shown the answers and asked to explain and prioritize them. There is nothing for it to add up.

Second, the output is schema-validated. The model must return its judgment in a fixed structure of ranked findings, explanations, and actions in named fields. Free-form responses that don't conform are rejected before they reach you. This constrains the model to the job it was given and prevents it from wandering into freelance calculation.

Third, and this is the backstop that makes the guarantee real, every number in the model's prose is checked against the findings payload. After generation, a numeric-fidelity check scans the output for figures and verifies each one appears verbatim in the deterministic payload the model was given. If the model writes a CPA, a percentage, or a dollar amount the engine did not compute and hand it, that response is rejected. The model may not introduce a single number of its own; it can only quote numbers the engine already proved.

The practical consequence: you can audit every figure. Any number in a TrailMap report traces back through the payload to a computation in the engine to a cell in your export. If a stakeholder challenges a figure, you can show your work, because there is work to show.

And because the dashboard renders directly from the deterministic findings, the analysis does not depend on the model being available. If the LLM endpoint is down, over quota, or deliberately disabled, you still get the complete diagnostic dashboard: every metric, every finding, every chart. You lose the prose narrative and the prioritization commentary, not the analysis. The numbers are never at the mercy of a model.

4. What the engine actually computes

This section walks the finding families the engine produces. Each is illustrated with a small worked example drawn from a single illustrative scenario: a residential plumbing lead-generation account running Google Ads and Meta. The scenario and all figures in it are invented for illustration and internally consistent; they are not real client data.

Efficiency-metric trends

The engine computes CPA, CPL, ROAS, CTR, CVR, and CPC at the account, campaign, and ad-group level, and tracks each period over period. Because the account is lead-gen, the profile leads with CPL and CVR over ROAS (see §5 on business-profile adaptation).

Illustrative: Account CPL rose from $61 to $74 (+21%) versus the prior 30 days, while lead volume was roughly flat (312 → 305). The engine flags that the CPL increase is driven by cost, not conversion rate (CVR held at 4.1%), pointing the investigation toward spend efficiency rather than landing-page or offer problems.

Impression-share loss, decomposed

This is the finding most reports never produce correctly. When you lose impression share, the platform reports lost IS to budget and lost IS to rank separately, and they demand opposite responses. Budget-limited loss means demand exists that you are not paying to capture, so raise the budget. Rank-limited loss means you are being outranked, so improve Quality Score, ad relevance, or bids. The engine decomposes the loss and attaches the correct prescription to each portion. (This requires the impression-share columns to be present in your export; see §9.)

Illustrative: The "Emergency Plumbing" campaign shows 47% lost impression share to budget and 6% lost to rank. The engine flags this as a budget-limited, high-intent campaign leaving conversions unclaimed, and prescribes a budget increase rather than a bid or Quality Score change, the opposite of what a rank problem would call for.

Search-term waste and negative-keyword theme mining

The engine scans the search-terms report for spend on queries that produce no conversions, then mines the wasteful terms for recurring word patterns that suggest negative-keyword themes rather than one-off exclusions. Instead of handing you 200 individual terms, it surfaces the themes those terms share.

Illustrative: $1,899 of spend across the period went to search terms with zero conversions. The dominant wasted themes are "how to" (DIY researchers, e.g. how to fix a running toilet), "jobs" and "salary" (job seekers, e.g. plumber jobs near me), and "parts" (self-repair shoppers). The engine proposes these as negative-keyword themes, so one decision on "how to" excludes dozens of current and future queries at once.

Quality Score and match-type distribution

The engine profiles Quality Score across keywords and the distribution of spend and conversions across match types (exact, phrase, broad), flagging concentrations that carry risk, for example heavy broad-match spend without the search-term hygiene to contain it.

Illustrative: 58% of the account's spend runs on broad match while only 20% of conversions come from it, and average Quality Score on the broad-match keywords is 4.2 versus 7.1 on exact. Combined with the search-term waste above, the engine flags broad match as the mechanism channeling budget into off-intent queries.

Creative fatigue and creative concentration

For paid social, the engine detects creative fatigue, the signature pattern of rising frequency alongside falling CTR, indicating an audience that has seen an ad too many times, and creative concentration, where too large a share of spend or delivery depends on a single asset, a fragility risk when that asset fatigues.

Illustrative: A Meta prospecting creative shows frequency climbing from 1.8 to 4.5 while CTR fell from 2.0% to 0.86% over the same window, a textbook fatigue signature. The engine also notes this one creative carried 64% of the ad set's spend (creative concentration), so its decline dragged the whole ad set's efficiency down. Prescription: refresh the creative and diversify delivery across assets.

Budget fragmentation below learning thresholds

Ad platforms need a minimum volume of conversions per ad set to exit the "learning" phase and optimize well. The engine flags ad sets whose budgets are fragmented so thinly that they cannot plausibly reach that threshold, a common, quiet drag on paid-social performance.

Illustrative: Six Meta ad sets each run at $12/day and none exceeds ~8 conversions/week, below the platform's learning threshold. The engine flags the fragmentation and suggests consolidating into two better-funded ad sets so the algorithm can actually optimize.

Spend concentration and robust anomaly detection

The engine profiles where spend concentrates (by campaign, channel, device) and runs robust-statistics anomaly detection using median and median-absolute- deviation (MAD) z-scores rather than mean and standard deviation. This matters: classic mean/standard-deviation outlier detection is itself distorted by the very outliers it is trying to find. Median/MAD is resistant to that, so a single freak day does not poison the baseline and the anomalies it flags are trustworthy.

Illustrative: One day's CPC on a single ad group spiked to a MAD z-score of 6.1, far outside normal daily variation, isolating a specific day and ad group for investigation rather than raising a vague "costs went up" alarm.

Cross-channel reallocation candidates

Looking across Google and Meta together, the engine identifies where marginal budget is likely being misallocated between channels given each channel's current efficiency, and surfaces reallocation candidates for human judgment.

Illustrative: Google search converts leads at $61 CPL while the fatiguing Meta prospecting is running at $140 CPL. The engine flags a candidate reallocation from the underperforming Meta ad set toward the budget-capped "Emergency Plumbing" search campaign, connecting the impression-share finding and the fatigue finding into one coherent move.

Notice how the findings interlock. The broad-match concentration explains the search-term waste; the creative concentration explains why one fatiguing asset sank an ad set; the budget-capped search campaign and the failing Meta ad set together make the reallocation obvious. Assembling that connective narrative from a set of individually-true findings is a judgment task, which is exactly what the LLM layer is for.

The chat channel: ads inside ChatGPT

TrailMap treats OpenAI Ads, advertising placed inside ChatGPT, as a distinct third channel, alongside search and social, with its own dashboard tab and its own place in the cross-channel view. The separation is deliberate. Chat ads are not search: there is no auction on a typed keyword, no impression-share-to-budget-versus-rank decomposition, no search-terms report to mine for negative-keyword themes. Nor are they a social feed: the fatigue-and-frequency and ad-set-fragmentation patterns that govern Meta, LinkedIn, and TikTok delivery do not map onto a conversational surface. Folding chat spend into either bucket would misdescribe it, so the engine keeps it in its own channel. LinkedIn and TikTok, by contrast, are social feeds and classify as social, with the same fatigue, concentration, and fragmentation rules apply to them.

What the engine computes for the chat channel today is the metric spine the platform's insights expose: daily spend, impressions, and clicks, and the CPM, CPC, and CTR trends derived from them period over period. Those figures render on a dedicated Chat tab and feed the cross-channel reallocation analysis, so a dollar's marginal efficiency in ChatGPT can be weighed against the same dollar in Google or Meta.

Conversion-side analysis takes one setup step on the advertiser's side. OpenAI's insights rows carry the traffic spine only, at every grain, so conversions do not ride the same report. They are read separately: TrailMap checks the account's conversion-measurement catalog, and where measurement is configured, pulls the attributed conversion totals for each day of the sync window and merges them onto that day's campaign rows. Chat then gets a CPA and a CVR computed the same deterministic way as every other channel's. No extra step for the customer beyond configuring measurement in OpenAI; it is part of the same sync.

Three bounds, stated rather than glossed. There is no chat ROAS: OpenAI's conversion response carries counts, not revenue, so conversion value stays unreported and no revenue-based metric is computed for the channel. The totals are blended and campaign-level: the response has no per-event dimension and no intra-day bucket, so conversions land on campaign rows while ad-group and ad rows keep theirs unreported, and channel totals read the campaign rows. And attributed totals restate as attribution windows mature, exactly as they do on other platforms; each sync carries a warning that says so.

Where an account has no conversion measurement configured, chat conversions stay unreported, never a silent zero, and the sync says so in as many words. A campaign missing from a day's totals while measurement is configured is measured-and-zero, and is reported as zero. The distinction between "not measured" and "measured, zero" is preserved rather than flattened, because collapsing it is how a channel gets wrongly written off.

TrailMap is among the first analytics products to support ChatGPT ads at all, a timing advantage rather than a moat, but it means a marketer putting early budget into the channel can measure it in the same place as everything else instead of flying blind.

The display channel: DV360, and the SA360 enterprise search connector

Two connectors extend the engine's reach for larger and holdco-scale advertisers, both currently in beta, validated against live accounts on request rather than broadly production-certified.

SA360 (Search Ads 360) is where enterprises and holdcos running search across multiple engines (Google, Microsoft, and others) keep their system of record, often without granting engine-level access to each underlying account. SA360's reports are search-shaped (campaign, ad group, keyword) and flow into the engine's existing search channel and finding library (impression-share decomposition, Quality Score and match-type distribution) exactly as Google Ads does.

DV360 (Display & Video 360) is different: it introduces a fourth canonical channel, display, because programmatic display and video economics do not resemble search or social. The unit bought is the impression (CPM, not a cost-per-click auction on a keyword); value depends on whether the impression was actually seen (viewability) rather than served into an unviewable slot; delivery risk shows up as frequency saturation (the same person shown an ad far too many times) rather than creative fatigue in the search/social sense; and for video, success is measured by whether the creative was watched to completion (VCR), not just clicked. The engine's display-specific rules (CPM outliers, low viewability, frequency saturation, low video-completion rate) run only on DV360 data and feed the same cross-channel reallocation view as every other channel, so a marginal display dollar can be weighed against the same dollar in search, social, or chat.

Both connectors ship the same way every connector does, with OAuth credentials, encryption at rest, and one-click sync into the canonical schema (§6), and both are offered on the Growth and Agency tiers as enterprise-oriented additions (see pricing).

GA4: a neutral conversion cross-check (beta), not a seventh platform

Every connector above this subsection is an ad platform: it has spend, campaigns, and its own claim about how many conversions it drove. GA4 (Google Analytics 4) is deliberately not one of those, and it does not get a canonical channel the way DV360 did. GA4 is Google's analytics layer, sitting downstream of every channel, paid and unpaid, that sends traffic to a site or app. Unlike a raw ecommerce order feed, which carries no attribution at all, GA4 has already run its own cross-channel attribution model by the time TrailMap sees it, crediting each conversion to a channel. That is precisely what makes it usable as a neutral referee without any closed-loop stitching of TrailMap's own: TrailMap reads what GA4 already decided, and sets it beside what the ad platform separately claims.

Connected read-only (scope analytics.readonly, no write access to anything), the GA4 connector pulls conversions and revenue grouped by GA4's default channel group, keeping only paid groups, so organic, direct, and cross-network traffic is dropped. The result is a claimed-vs-GA4 comparison a director can act on directly: "Meta claims 100 conversions this week; GA4 attributes 62 of that week's conversions to Paid Social." That gap is a prompt to investigate over-counted click attribution, view-through inflation, or tracking gaps, rather than an automatic verdict on which number is "right." GA4's own attribution is itself a model, a genuinely independent second opinion, not deterministic first-party ground truth. TrailMap never blends GA4 rows into an ad platform's claimed totals; the two sit side by side by design.

GA4 is offered on the Growth and Agency tiers, the same positioning as SA360 and DV360, and carries the same honest beta caveat: the connector is built to GA4's documented Data API shape but not yet confirmed end-to-end against a live property.

5. From findings to action

The engine produces facts. Facts are necessary but not sufficient; a director does not want a longer list of true statements, they want to know what to do first. That is the LLM judgment layer's job, and it does three things with the findings payload.

It prioritizes. A busy account can surface dozens of findings. The model ranks them for this business, so a budget-capped, high-intent search campaign with 47% lost IS to budget outranks a minor CTR wobble on a low-spend display line, because the former is unclaimed demand and the latter is noise. The ranking is a judgment about relative importance, informed by the business profile, not a recalculation of the numbers.

It explains the mechanism. For each priority finding, the model writes the "why" a senior analyst would give, rather than "CPL is up 21%," which the chart already said, but "CPL rose while CVR held flat, so this is a cost problem, not a conversion problem; the broad-match spend feeding off-intent queries is the most likely driver." This is precisely the language task models excel at, operating strictly over numbers the engine computed.

It writes next actions with effort and impact ratings. Each recommendation is concrete and tagged with an effort estimate and an impact estimate, so a team can sequence work by return on effort, taking the low-effort, high-impact moves first.

Illustrative recommendations, ranked:

1. Add "how to / jobs / salary / parts" negative-keyword themes. Effort: low · Impact: high. Recovers roughly $1,899/period of zero-conversion spend and prevents its recurrence.

2. Raise the "Emergency Plumbing" budget to reclaim the 47% budget-limited lost IS. Effort: low · Impact: high. High-intent demand currently going unserved; the reclaimed spend is efficient at $61 CPL.

3. Refresh the fatiguing Meta creative (freq 4.5, CTR 0.86%) and diversify delivery. Effort: medium · Impact: medium. Arrests the ad set's decline and reduces single-creative fragility.

4. Consolidate the six sub-scale $12/day ad sets into two. Effort: medium · Impact: medium. Clears the learning threshold so the algorithm can optimize.

Adapting to the business profile

None of this is generic. During onboarding, TrailMap captures a business profile: industry, business model (lead-gen, ecommerce, or hybrid), primary KPI, and targets. That profile shapes three things at once:

  • KPI emphasis. A lead-gen plumber's report leads with CPL and lead volume; an ecommerce account's leads with ROAS and revenue. The same engine, different framing.
  • Engine thresholds. What counts as "wasteful," "fatigued," or "concentrated" is calibrated to the vertical and the model's targets rather than one-size-fits-all defaults.
  • Analyst voice. The LLM layer's prose and prioritization are tuned to the profile, so the narrative reads like an analyst who understands this business, not a template.

The recommendations, in other words, are the same expertise a good analyst applies, with the pattern library encoded in the engine and the judgment supplied by the model, consistently, on every account.

6. Data stewardship and deployment

Smart buyers ask hard questions about where their data goes. Here are direct answers.

What's stored, and how

TrailMap is multi-tenant with per-tenant data isolation: each customer's data is partitioned and access-scoped to that tenant. Normalized rows from your uploads and connector syncs live in per-upload columnar files; the database holds metadata, the computed findings, and the report payloads. You are not pooled into a shared dataset, and analysis runs against your data alone.

Team access, roles, and the audit trail

TrailMap is a team product, not a single login. You invite teammates by email, and each member holds one of four roles (owner, admin, analyst, or viewer), enforced on every action, so a viewer-only stakeholder or client contact can read reports without touching settings, billing, or connections. Each plan includes a fixed number of seats (they pool across the whole billing account, so you can't multiply them by adding workspaces).

Every consequential action (invites and role changes, connection edits, runs, exports, billing and plan changes) is written to a tenant-scoped audit log, visible to your admins, so there is an answer to "who did what, and when." The log is retained on a schedule and purged after its retention window. This is the accountability surface larger and regulated teams ask for, and it ships on every plan rather than being reserved for an enterprise SKU.

Running many clients: agency workspaces

An agency or fractional CMO doesn't want one shared account with every client's data intermingled, and TrailMap doesn't make you have one. A single subscription can run many isolated client workspaces, each its own tenant with its own data, its own connections, and its own white-label brand. The workspaces share one pooled monthly run allowance and one seat pool, and the operator gets a portfolio rollup across the whole account alongside per-workspace usage, so you see every client at once and draw runs from a common pool, without a per-client bill. Data isolation between workspaces is the same partition boundary as between unrelated tenants: one client's data never reaches another's report.

Connector credentials

If you connect a platform's API rather than uploading files, the credentials you paste (OAuth client secrets, refresh tokens, access tokens) are encrypted at rest with Fernet using a server-side key, and once saved are never returned by any API endpoint or rendered in the UI. Sync errors surface the platform's own message but never echo your tokens. The connector calls are read-only reporting queries. TrailMap pulls your reporting data and makes no changes to your ad accounts.

Fidelity in the pipeline

The stewardship story starts at ingestion, because analysis is only as trustworthy as the parsing beneath it. TrailMap makes a series of deliberate, unglamorous choices that most tools skip:

  • Money is handled as integer micros, the same convention Google's own Ads API uses, so currency never touches floating-point arithmetic and never accumulates rounding error. Conversions are integer millis for the same reason.
  • -- placeholders parse to "not reported," never to zero. Treating an unreported value as 0 silently corrupts every average and total computed over it. TrailMap keeps the distinction between "zero" and "we don't know."
  • Bounded values are stored as bounds. When a platform reports impression share as < 10%, that is a bound, not a point estimate. The engine stores it as a bound and will not present a bound as if it were a fact. It will not quietly turn < 10% into 10% or 5%.
  • A per-upload parse-issue ledger shows you every cell that was skipped or coerced during ingestion. You can see exactly what the engine did with messy data, rather than trusting a black box.
  • Overlapping uploads are reconciled deterministically: segmented exports do not double-count rows, and re-uploads of overlapping date ranges resolve to a single authoritative version by a fixed rule, with every such decision recorded in the issue ledger so you can see exactly what was kept and what was superseded.
  • Legacy encodings are supported, including UTF-16 exports from older Google Ads, so real-world files parse correctly instead of turning into mojibake.
  • Localized exports are parsed natively. Locale packs for Spanish, German, and French Google Ads and Meta exports recognize the translated column headers and the European number format (1.234,56), so a comma-decimal figure is read as the number it is, never silently turned into a smaller one. Mis-parsing money is the one unforgivable failure in this product, and non-English files are where it usually happens.

These choices are why the engine's numbers are trustworthy in the first place. Analytical rigor downstream is worthless if the parsing upstream quietly fabricates data.

Key handling and the self-hosted option

LLM API keys are server-side only and never reach the browser. The judgment layer runs on leading commercial language models by default, or a self-hosted model inside your own infrastructure. Switching is configuration, not code. The self-hosted option (for example a vLLM or Ollama deployment) is for data-residency-sensitive customers who require that prompt content never leave their own infrastructure. The deterministic engine is identical either way.

Per-tenant LLM usage is metered, with monthly run quotas by subscription tier, so consumption is visible and bounded.

Portable, white-labeled reports

Every analysis renders as an interactive in-app dashboard and downloads as a single self-contained HTML file that opens in any modern browser (Chrome/Edge 80+, Safari 16.4+, Firefox 113+) with no server, so you email it to a stakeholder and it just works. Its report payload is embedded as a compressed, encoded blob for compactness rather than as readable JSON, a convenience rather than encryption, since the browser decodes it in the clear to render. White-labeling (logo and accent color) flows into both the in-app dashboard and that downloadable report, so an agency can put its own brand in front of clients. Critically, the in-app view and the standalone export are produced by the same renderer, so the two can never drift out of sync.

Programmatic access: the public API

Everything the dashboard shows is also reachable over a public REST API (v1) authenticated with scoped API keys. You can trigger analysis runs and read report payloads, the same JSON document the dashboard renders, from your own code, a scheduler, or a tool like Zapier, and wire TrailMap into a BI stack or an internal workflow. Keys are scoped to a single workspace and least-privilege (you grant only the permissions an integration needs, e.g. reading runs and reports without the ability to create them), shown once at creation, stored only as a hash, and revocable. Programmatic runs draw from the same monthly allowance as runs started in the app, so the API is a second door into the same product, not a separate meter. It is available on the plans that include it (Growth and above).

Deployment and identity

TrailMap runs as a hosted subscription, and it also self-hosts. The whole application (API, web app, and the report renderer) ships as a single Docker image with a docker compose deployment alongside Postgres, so a team that needs the software inside its own infrastructure can run it there. Production mode arms a boot-time secrets preflight that refuses to start on insecure defaults (an empty encryption key, a default admin secret, cookies not marked Secure), so a self-hosted instance can't quietly come up mis-configured. Connector credentials and any per-tenant model keys are encrypted at rest, and the encryption key supports rotation without losing already-stored data.

For enterprise identity, TrailMap supports single sign-on via OIDC (Okta, Azure AD, or Google Workspace) on the top (Agency) tier, so access is governed by your identity provider rather than a separate password. Combined with roles and the audit log, that gives a security team the centralized control and the accountability trail they expect before approving a new tool.

Your data rights

You can export your data and delete your account, a full removal of your data (GDPR/CCPA). TrailMap's default posture is that your reporting data is yours: it is never pooled into a shared dataset, never used to train a model, and leaves the system, in keyed mode, only as the prompt sent to your configured model provider (which is server-side, and can be a model you host yourself).

7. Where TrailMap fits

TrailMap is a decision-support layer. It is honest about what it complements and what it can replace.

Versus BI dashboards (Looker, Data Studio, Tableau)

BI tools are visualization platforms. They are excellent at connecting to sources, modeling data, and rendering flexible charts, and they will happily show you that CPL rose 21%. What they do not do is reason about that number: they will not decompose your impression-share loss into budget versus rank, mine your search terms for negative-keyword themes, or tell you which of twenty findings to act on first. BI shows; TrailMap interprets and prescribes. They are complementary, and many teams will keep their BI dashboards for exploration and monitoring and use TrailMap for diagnosis and recommendations.

Versus in-platform recommendations (Google's own, Meta's own)

The ad platforms surface their own recommendations, and some are useful. But they have a structural conflict of interest: their recommendations reliably trend toward raising budgets and enabling broad automation, and each platform sees only its own inventory, so none of them can reason across the six platforms together. TrailMap is independent of the platforms and looks across all of them, which is exactly why it can flag a cross-channel reallocation from a failing Meta ad set into a budget-capped Google campaign. Treat TrailMap as the neutral second opinion the platforms cannot be.

Versus an agency analyst retainer

This is the one where the framing gets interesting. A great analyst does what TrailMap does. It carries the pattern library, spots the fatigue, decomposes the impression-share loss, and prioritizes the fixes, and it does all that with human context TrailMap lacks. TrailMap does not fully replace that person. What it does is replace the mechanical 80% of their monthly work: metric computation, finding detection, and first-draft prioritization and write-up, done consistently in minutes across an entire portfolio. For an in-house team with no analyst, that is the difference between senior-grade analysis and none. For an agency, it multiplies reach: one analyst can cover more accounts at a higher floor of quality, spending their time on strategy and client relationships instead of assembling the same report by hand for the fortieth time. TrailMap is not trying to fire your analyst. It is trying to stop your analyst from doing arithmetic.

8. Roadmap

TrailMap proved the analytical core on upload-based ingestion first, then layered live integrations and the team/enterprise foundations on top. Several items once on this roadmap have since shipped and are described in the body above rather than here: official API connectors for all six platforms (§3, direct authenticated sync into the same canonical schema, so the export step is now optional); scheduled connector sync, where a connected account refreshes itself on a daily or weekly cadence, optionally running a full analysis and emailing the report when it completes; the SA360 and DV360 enterprise connectors and DV360's new display channel, both in beta (§4); the GA4 conversion cross-check, also in beta, a referee rather than a platform (§4); the Postgres deployment path and Docker self-host for larger deployments (§6); multi-user teams with roles and an audit log, agency multi-workspace with pooled quotas and a portfolio rollup, the public REST API with scoped keys, SSO via OIDC on the top tier, data export and deletion (GDPR/CCPA), and Spanish/German/French locale packs (all in §6). The generic column mapper still ingests any export a platform can produce, including sources beyond the eight first-class platforms, by mapping arbitrary columns onto the canonical schema.

What remains near-term:

  • Confirming SA360/DV360/GA4 against live accounts. All three connectors ship today in beta, built to each platform's documented API shape; the next step is validating that shape against real customer accounts and properties and lifting the beta label (see §9).
  • Deeper chat-channel coverage. Spend, traffic, and conversions are read today (§4); the chat finding library keeps expanding as the platform exposes more dimensions, with a per-event breakdown and conversion value being the two that would unlock the most.
  • Continued expansion of the finding library, the part of the product that compounds in value over time.

The sequencing principle is consistent: the deterministic engine is the asset, and every roadmap item extends its reach or its inputs, never its right to do arithmetic in a model.

9. Limitations

Candor is part of the product. Here is what TrailMap does not do today.

  • A very large first sync takes time, and the product says so rather than hiding it. A connected account of substantial size can take many minutes to pull for the first time. The sync runs in the background and resumes if interrupted (§3), so it is not fragile, but it is not instant, and TrailMap will not report a run as current while a sync is still in flight. Uploads have a related freshness property: analysis reflects the data you last provided.
  • SA360 and DV360 are in beta. Both connectors are built to each platform's documented API shape and pass the same fidelity discipline as every other connector, but neither has yet been confirmed end-to-end against a live customer account the way the original six have. If a field or report shape doesn't match your account, a sync fails with the platform's own error rather than silently mis-mapping data, and TrailMap validates against live accounts on request.
  • GA4 is in beta, and its comparison is a second opinion, not a verdict. The connector is built to GA4's documented Data API shape but not yet confirmed against a live property, the same honest caveat as SA360/DV360. Separately, GA4's own attribution is a model, not deterministic ground truth, and it is a claimed-vs-GA4 gap is a prompt to investigate, not proof of which number is correct.
  • Analysis quality is bounded by data completeness. The engine computes what the data supports, whether it arrived by upload or by connector. If the data omits the impression-share columns, the engine cannot perform the budget-versus-rank IS decomposition; if it omits the search-terms report, there is no search-term waste analysis. The chat channel gets spend and traffic from OpenAI's insights, plus conversions once the advertiser has configured conversion measurement, but never conversion value, so there is no chat ROAS (§4). Better inputs yield better analysis, and the parse-issue ledger will tell you what was missing.
  • The LLM narrative is advisory, not auto-applied. The prioritization, explanations, and recommended actions are decision support. They are drafted by a model, and a human should review them before acting. They are not executed automatically and should not be treated as infallible.
  • TrailMap does no bid management and makes no in-platform changes. It is a diagnosis and recommendation layer, not an optimization or automation platform. It tells you what to change and why; you (or your tools) make the change in the ad platform. It does not touch your accounts.

None of these are accidents. TrailMap's design philosophy is to be trustworthy within a clearly-drawn boundary rather than to over-claim across a blurry one. A tool that is honest about its limits is a tool you can actually rely on inside them.

10. About and contact

TrailMap by Sasquatch Creative is a subscription web application that turns paid-media data (across search, social, and chat, from six platforms, by file upload or official API connector) into senior-analyst-grade recommendations you can audit line by line, a deterministic engine for every number, a language model for the judgment and the prose, and a hard architectural boundary between the two.

If you have been burned by "AI insights" that could not show their work, that is precisely the problem TrailMap was built to solve.

To arrange a walkthrough or a pilot on your own account exports:

Ready to see it on your own data?

Start a 14-day trial (3 runs, no credit card) and get a senior analyst's action plan on your own account exports.

This whitepaper describes TrailMap's architecture and capabilities as of the current release. The plumbing lead-generation scenario in §4 and §5 is illustrative and does not represent real client data.