---
id: casos/marketing-unificado
area: Marketing
usage: widely used
effort: medium
grain: Platform x account x campaign x day
testado_com_agente: Oct 2026
---

# Unified marketing (Google + Meta)

Google, Meta and the other platforms in a single table, with spend, clicks and conversions that match each ads manager.

## Executive summary

**For:** Marketing teams and agencies that invest in more than one media platform and need to compare everything in one view.

**What it solves**

- Each platform's spend in the table matches its own ads manager, by day and by month.
- Click, conversion and cost mean the same thing on every platform before they are compared.
- CTR, CPC, CPM and cost per conversion are correct at any cut, with no average of averages.

**Why it matters:** Each platform measures cost, clicks and conversions its own way, and a naive comparison is off by factors from 1.5 to one million. A budget decision built on that sum takes money away from the channel that works. It is also the foundation of every case that ties media to leads, sales and revenue.

**Business questions it answers**

- How much did we spend on each platform this month, and how does it compare with last month?
- Which campaign has the lowest cost per conversion, looking at Google and Meta together?
- Are Meta's CTR and CPC better or worse than Google's over the same period?
- How much of the budget went to Performance Max and how much to search?
- Which accounts or campaigns stopped spending or converting in the last few days?

**What you need**

- The media platforms connected to Nekt, with every account of each one and the list of expected accounts
- The conversion that counts as a result on each platform, with Google's conversions-by-action stream enabled in the connector
- The currency of each Google account and the rule for tax or fees on top of the media budget, if any

**What you get**

- A platform x account x campaign x day table with the same schema for all platforms
- Platform totals that match each ads manager
- A comparison dashboard with rates recalculated from the sums
- An AI agent that answers about media without mixing units

## Detailed

### The problem

Each platform delivers cost in its own unit, clicks with its own definition and conversions with its own attribution rule. Google sends cost in micros, Meta sends everything as text, and Google's conversions column can include even map directions and page views. Whoever stacks the tables and sums them directly ships a dashboard that matches no ads manager, and the media buyer goes back to each platform's tabs.

### Business rules

1. **Convert cost to currency on the way in.** Google Ads: metrics_cost_micros divided by 1,000,000. Meta Ads: spend arrives as text, in the account currency, and must become a number. LinkedIn: costInLocalCurrency is also text. Convert each platform before unifying, and keep the account currency in a column. On Meta, the currency comes from the currency field of the accounts table. On Google, the performance table carries no currency: declare each account's currency in the context document. A USD account is converted with a declared rate. (Avoid: Summing metrics_cost_micros with spend in the same column.)
2. **One common schema with explicit columns.** The single table has the same columns for every platform: date, platform, account, campaign (id and name), spend, impressions, clicks, conversions, conversion value and currency. Each branch of the union lists its columns by name. When one account's connector gains a new column, the union neither breaks nor shifts values. (Avoid: Stacking the tables with a select of all columns.)
3. **The insights table is the authority on actuals.** Spend, impressions and clicks come only from the daily performance table. Campaigns, ad sets and accounts only enrich it with name, objective and status. A paused, renamed or deleted campaign keeps the spend it had. Meta delivers insights by ad and day: roll them up to campaign and day before the union. Google's campaign performance carries no account: take the customer_id from the resource_name in the campaigns table (customers/<id>/campaigns/<id>). Configuration tables keep several versions per id: keep the latest one (highest updated_time; when the table has no updated_time, highest _nekt_sync_at) before joining. (Avoid: Starting from the list of active campaigns and looking up their spend.)
4. **A click is a link click.** On Meta, the clicks column counts any click on the ad, including likes, profile and see more. The number that matches the ads manager and compares with Google's clicks is link_click from the actions list (or inline_link_clicks). On Google, clicks already means a click on the ad. (Avoid: Comparing Meta clicks with Google clicks.)
5. **A Google conversion is a primary conversion.** metrics_conversions sums only the actions marked as primary, but if the account marked page views, button clicks or map directions as primary, they are included. Break it down by conversion action (the conversions by campaign stream segmented by segments.conversion_action, which must be enabled in the connector) and choose the actions that count as a result. If the stream is not enabled, use metrics_conversions and record the limitation in the context document. Never use metrics_all_conversions. GET_DIRECTIONS and STORE_VISIT are top-of-funnel estimates; PHONE_CALL_LEAD, CONTACT and SUBMIT_LEAD_FORM are the closest to a real contact. (Avoid: Using Google's conversions column as total leads.)
6. **A Meta conversion follows the ad set objective.** Each campaign's result is the action_type of the ad set's optimization goal (optimization_goal). LEAD_GENERATION: lead. OFFSITE_CONVERSIONS: the event in promoted_object.custom_event_type (LEAD becomes lead, PURCHASE becomes purchase, COMPLETE_REGISTRATION becomes complete_registration). CONVERSATIONS: onsite_conversion.messaging_conversation_started_7d. LINK_CLICKS, LANDING_PAGE_VIEWS, REACH, THRUPLAY and VISIT_INSTAGRAM_PROFILE have no conversion to charge. A goal outside this list is declared in the context document before it goes in. lead already adds form and pixel, so never add lead to onsite_conversion.lead_grouped and offsite_conversion.fb_pixel_lead. (Avoid: Summing every action_type that contains lead.)
7. **Rates are recalculated from the sums.** CTR = sum of clicks / sum of impressions. CPC = sum of spend / sum of clicks. CPM = sum of spend / sum of impressions x 1000. Cost per conversion = sum of spend / sum of conversions. The rate columns the platforms deliver stay out of the table, because summing or averaging them gives a wrong number at any cut. (Avoid: Average of daily CTR or sum of each platform's CPC.)
8. **Performance Max and Demand Gen at campaign level.** Performance Max has no individual ad, and the ad report misses those campaigns. The unified table stays at campaign level. Whoever needs ads uses the ad report for search, display and video and the campaign report only for Performance Max, without overlapping the two. (Avoid: Building Google spend from the ad report.)
9. **Day in the account time zone and a reprocessing window.** Each platform cuts the day in the account time zone. Use the date the platform delivers, without converting it again. Meta and Google adjust conversions for past days (on Meta, up to about 28 days), so each load rewrites at least the last 30 days by platform, account, campaign and day, without duplicating. If the source sends several extractions of the same day, keep the latest before summing. (Avoid: Loading only yesterday and never rewriting.)
10. **Null means not measured, zero means zero.** A platform with no conversion value (such as a messaging campaign on Meta) gets a null value, not zero, and its ROAS is null. Google returns 0 in metrics_conversions_value when the account does not measure value: if no conversion action in the account has a value, treat it as null. An account shared between brands or between client and agency is filtered by a declared campaign name pattern. An old source that was replaced leaves the union: before the union, look for tables of the same platform with the same account_id under another connector or prefix and compare monthly spend; if the numbers match, keep only one. (Avoid: Filling missing conversions with zero and summing two sources of the same account.)

### From each platform to the common schema

Source field of each metric and the treatment before the union.

- **Google Ads · spend** → Divide by 1,000,000 (`metrics_cost_micros`)
- **Meta Ads · spend** → Text to number (`spend`)
- **LinkedIn Ads · spend** → Text to number (`costInLocalCurrency`)
- **Google Ads · clicks** → Click on the ad (`metrics_clicks`)
- **Meta Ads · clicks** → Link click (`link_click`)
- **Google Ads · conversions** → Only the actions chosen as a result (`metrics_conversions · segments.conversion_action`)
- **Meta Ads · conversions** → action_type of the ad set objective, rolled up from ad to campaign (`actions · optimization_goal`)
- **Conversion value** → Null when the platform does not measure it, including Google's 0 with no valued action (`metrics_conversions_value · action_values`)
- **Native rates** → Out of the table, recalculated from the sums (`ctr · cpc · cpm`)

### Definitions

| Metric | Definition |
|---|---|
| Spend | sum of cost in R$ by platform, account, campaign and day, already converted from each platform's unit |
| Clicks | clicks on the ad on Google and link clicks on Meta, by campaign and day |
| Conversions | sum of the conversion actions chosen as a result on each platform, by campaign and day, on the date the platform attributes; null for campaigns with no conversion to charge |
| CTR | sum of clicks / sum of impressions in the cut |
| CPC | sum of spend / sum of clicks in the cut |
| CPM | sum of spend / sum of impressions x 1000 in the cut |
| Cost per conversion | sum of spend / sum of conversions in the cut, only for campaigns with a conversion to charge |
| Platform ROAS | sum of conversion value / sum of spend, null when the platform does not measure value (on Google, when no conversion action in the account has a value) |

### Pitfalls

- **A factor of one million.** Google cost in micros was summed with Meta spend in reais and Google became almost all of the dashboard's spend. How to avoid: Convert each platform to R$ before the union and check each total against its ads manager.
- **Google with six times more conversions.** Google's conversions column included micro-conversions and showed 43 thousand conversions against fewer than 7 thousand Meta leads over the same period. The cross-platform comparison was off by a factor of six. How to avoid: Enable the conversions-by-action stream in the Google connector and use only the actions that count as a result.
- **The union stopped over one column.** The connector of a single account gained a new column and the positional union broke the pipeline for every account. How to avoid: List columns by name in each branch of the union.
- **Performance Max vanished from the report.** Google spend was built from the ad report, which has no Performance Max or Demand Gen campaigns. The total came in below the ads manager. How to avoid: Use campaign level as the base and handle ads only where they exist.
- **Accounts outside the connector.** The live connectors covered only some of a platform's accounts, and the year's spend was understated by 15% to 36% without anyone noticing. How to avoid: Keep a registry of expected accounts per platform and alert when an account is missing from the table. Without a registry, use the active accounts in the connector's accounts table as the expected list.
- **The month's number changed after the report.** Meta adjusted conversions for previous days and the load that only read the new day left the table different from the ads manager. How to avoid: Rewrite the recent window on every load and note in the report that the last days may still change.

Validated on real data: In Nekt's own Meta Ads account, in 2026, the clicks column adds up to about 1.5 times the link clicks, and half of the daily rows show the two numbers differently. In Nekt's Google Ads, metrics_conversions comes fractional from data-driven attribution and on the click date; counted by conversion date, each month's conversions are 10% to 25% higher.

### Acceptance test

- [ ] Each platform's spend for a closed month matches its ads manager, with a difference below 1%.
- [ ] The sum of the campaign table for the month equals the month's spend in a reference monthly series (an already validated monthly report or an ads manager export), for each platform.
- [ ] There is never more than one row per platform, account, campaign and day.
- [ ] CTR, CPC and CPM for any cut equal the ratio of the sums for that cut.
- [ ] Every account in the expected accounts registry (without a registry, the active accounts in the connector's accounts table) appears in the table with spend in the month, or is flagged as paused.

### Context document

```text
Unified paid media
- Source for spend, impressions, clicks and conversions: the unified table at platform x account x campaign x day grain. Do not sum platform tables on the side.
- Spend in R$. Google came from metrics_cost_micros / 1,000,000; Meta from spend converted to a number; LinkedIn from costInLocalCurrency converted. The currency of Google accounts is the one declared in the exceptions.
- A click on Meta is a link click (link_click). A click on Google is a click on the ad.
- Google conversion = only the conversion actions chosen as a result, never metrics_all_conversions. Meta conversion = action_type of the ad set's optimization goal. If Google has no conversions by action, say that the number includes every primary action.
- Reach or awareness campaigns have no conversion to charge. Say that, do not say zero conversions.
- CTR, CPC, CPM and cost per conversion are always recalculated from the sums of the cut. Never sum or average rates.
- A null conversion value means not measured. ROAS stays null in those cases.
- The last 30 days may still change because the platforms adjust conversions. Mention it when reporting the current month.
- A platform conversion is not a CRM lead. For leads, sales and revenue by channel, use the funnel and attribution cases.
Client exceptions:
- <client>: Google conversion actions that count as a result: <list of actions>.
- <client>: spend reported <with|without> a <percentage> tax on the media budget.
- <client>: shared account; only campaigns whose name contains <pattern> are included.
- <client>: Google account currency: <currency>; declared conversion rate: <rate>.
- <client>: expected accounts per platform: <list of accounts>; replaced source left out of the union: <source>.
```

### Variations

- **Agency with many clients:** An account to client registry defines each row's client, never the table or account name.
- **Planned vs actual:** Join with the approved media plan by month and campaign and show spend pacing, with and without tax.
- **More platforms:** TikTok, Microsoft Ads and marketplace media join the same schema, each with its declared result conversion.
