Daily insights from Google, Meta, TikTok, LinkedIn and Microsoft
Same unit, same level and same conversion definition everywhere
One table by platform, account, campaign and day
Media dashboard, report and AI agent
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.
Business questions it answers
Ask your agent these questions once the case is live.
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
Where to activate
Spend, clicks, conversions and rates by platform, account and campaign, read from the unified table.
Answers about budget and efficiency with units and conversion definitions already resolved.
Daily notice when an expected account stops spending, when a campaign with a conversion to charge goes days without converting, or when the budget will run out before month end.
The rules are settled, but each platform has its own unit, level and date traps. Start with Google and Meta and add the others to the same schema. The detailed view has the business rules, the pitfalls and the acceptance test. Or send everything straight to your agent with the Nekt MCP.
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.
How it is usually done, and the rule
Each row is a mistake that already happened in practice.
spend in the same column.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.
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.
spend.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.
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.
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.
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.
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.
spend from the ad report.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.
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.
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.
From each platform to the common schema
Source field of each metric and the treatment before the union.
Definitions
spend / sum of clicks in the cutspend / sum of impressions x 1000 in the cutspend / sum of conversions in the cut, only for campaigns with a conversion to chargespend, null when the platform does not measure value (on Google, when no conversion action in the account has a value)Pitfalls that already happened
Google cost in micros was summed with Meta spend in reais and Google became almost all of the dashboard's spend.
Convert each platform to R$ before the union and check each total against its ads manager.
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.
Enable the conversions-by-action stream in the Google connector and use only the actions that count as a result.
The connector of a single account gained a new column and the positional union broke the pipeline for every account.
List columns by name in each branch of the union.
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.
Use campaign level as the base and handle ads only where they exist.
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.
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.
Meta adjusted conversions for previous days and the load that only read the new day left the table different from the ads manager.
Rewrite the recent window on every load and note in the report that the last days may still change.
Acceptance test
The case is done when every item passes.
- 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.
Agent package
Paste into Claude, ChatGPT or any client with the Nekt MCP connected.
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>.
Build the "Unified marketing (Google + Meta)" case in my Nekt workspace following the rules at https://academy.nekt.com/en/casos/marketing-unificado.md. 1) Find the source tables and confirm the columns the rules use. 2) Create a transformation at the stated grain applying every rule. 3) Run the acceptance test and show me the result of each item. 4) Create the case's context document in the workspace, leaving my clients' exceptions open for me to fill in.
Variations
An account to client registry defines each row's client, never the table or account name.
Join with the approved media plan by month and campaign and show spend pacing, with and without tax.
TikTok, Microsoft Ads and marketplace media join the same schema, each with its declared result conversion.